diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 4ce24f19e..1c481da80 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -20,7 +20,7 @@ "estate/static/src/scss/estate.scss", ] }, - "depends": ["base", "mail"], # 依赖的模块列表 + "depends": ["base", "mail",'hr'], # 依赖的模块列表 "license": "LGPL-3", # 许可证类型 "installable": True, # 是否可安装 "application": True, # 是否为应用程序 diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index c2ed2b67b..9ef0ca9fb 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -12,7 +12,7 @@ - + diff --git a/header_search_panel/static/src/search/header_search/components/quick_filter/quick_filter.js b/header_search_panel/static/src/search/header_search/components/quick_filter/quick_filter.js index 669ace439..d41858434 100644 --- a/header_search_panel/static/src/search/header_search/components/quick_filter/quick_filter.js +++ b/header_search_panel/static/src/search/header_search/components/quick_filter/quick_filter.js @@ -121,5 +121,4 @@ QuickFilter.props = { groupId: { type: Number, required: true }, // 显示label showLabel: { type: Boolean, required: false, default: true }, - resModel: { type: String } } diff --git a/yuthon_contract/models/inherit_hr_contract.py b/yuthon_contract/models/inherit_hr_contract.py index 9f771d1af..3f25434dc 100644 --- a/yuthon_contract/models/inherit_hr_contract.py +++ b/yuthon_contract/models/inherit_hr_contract.py @@ -10,49 +10,86 @@ class HrContract(models.Model): _inherit = "hr.contract" _description = "员工合同拓展" - code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('contract_code')) - name = fields.Char(string="合同名称", compute='_compute_name', readonly=False) + code = fields.Char( + string="编号", + default=lambda self: self.env["ir.sequence"].next_by_code("contract_code"), + ) + name = fields.Char(string="合同名称", compute="_compute_name", readonly=False) is_annual_salary = fields.Boolean(string="是否年薪") - resource_calendar_id = fields.Many2one('resource.calendar', string='考勤时间表') - state = fields.Selection([ - ('draft', '草稿'), - ('open', '运行中'), - ('close', '完成'), - ('cancel', '已中止'), - ], string='状态', default='draft', readonly=True, copy=False) - date_of_entry = fields.Date(related='employee_id.entry_date', string="入职时间") - salary_group_id = fields.Many2one('yuthon.salary.group', string="工资单分组", store=True, index=True) - is_internship = fields.Boolean(string="实习期", compute='_compute_name', store=True) + resource_calendar_id = fields.Many2one("resource.calendar", string="考勤时间表") + state = fields.Selection( + [ + ("draft", "草稿"), + ("open", "运行中"), + ("close", "完成"), + ("cancel", "已中止"), + ], + string="状态", + default="draft", + readonly=True, + copy=False, + ) + date_of_entry = fields.Date(related="employee_id.entry_date", string="入职时间") + salary_group_id = fields.Many2one( + "yuthon.salary.group", string="工资单分组", store=True, index=True + ) + is_internship = fields.Boolean(string="实习期", compute="_compute_name", store=True) date_end = fields.Date(string="合同结束时间") termination_date = fields.Date(string="中止时间") - reason_suspension = fields.Selection([ - ('turnover', '离职'), - ('died', '意外离世'), - ], string='中止原因') - work_entry_source = fields.Selection([ - ('calendar', '考勤安排'), - ('attendance', 'Attendances'), - ('planning', '特殊排版')]) + reason_suspension = fields.Selection( + [ + ("turnover", "离职"), + ("died", "意外离世"), + ], + string="中止原因", + ) + work_entry_source = fields.Selection( + [ + ("calendar", "考勤安排"), + ("attendance", "Attendances"), + ("planning", "特殊排版"), + ] + ) is_probation = fields.Boolean(string="试用期") - start_date = fields.Date(string="试用开始日期", required=True, default=fields.Date.today) - end_date = fields.Date(string="试用结束日期", required=True, - default=lambda self: fields.Date.today() + relativedelta(months=+2) - relativedelta(days=1)) + start_date = fields.Date( + string="试用开始日期", required=True, default=fields.Date.today + ) + end_date = fields.Date( + string="试用结束日期", + required=True, + default=lambda self: fields.Date.today() + + relativedelta(months=+2) + - relativedelta(days=1), + ) salary_day = fields.Float(string="日薪") - party_id = fields.Many2one('yuthon.party.setting', string='甲方(用人单位)') - representatives = fields.Char(related='party_id.representatives', string='法定代表人或委托代理人') - contract_type_id = fields.Many2one('hr.contract.type', default=lambda self: self.env['hr.contract.type'].search( - [('name', '=', '正式合同(一签)')], - limit=1 - ).id or False, string='合同类型') - economy_type = fields.Char(related='party_id.economy_type', string='经济类型') - address = fields.Text(related='party_id.address', string='通讯地址') - contact = fields.Char(related='party_id.contact', string='联系人') - phone = fields.Char(related='party_id.phone', string='电话') - documents_ids = fields.Many2many('ir.attachment', string="合同附件") - current_contract = fields.Boolean(string="当前合同", default=True, compute='_compute_current_contract', store=True) - is_company = fields.Boolean(string="本公司", default=True, compute='_compute_is_company', search='_search_part_of_company') + party_id = fields.Many2one("yuthon.party.setting", string="甲方(用人单位)") + representatives = fields.Char( + related="party_id.representatives", string="法定代表人或委托代理人" + ) + contract_type_id = fields.Many2one( + "hr.contract.type", + default=lambda self: self.env["hr.contract.type"] + .search([("name", "=", "正式合同(一签)")], limit=1) + .id + or False, + string="合同类型", + ) + economy_type = fields.Char(related="party_id.economy_type", string="经济类型") + address = fields.Text(related="party_id.address", string="通讯地址") + contact = fields.Char(related="party_id.contact", string="联系人") + phone = fields.Char(related="party_id.phone", string="电话") + documents_ids = fields.Many2many("ir.attachment", string="合同附件") + current_contract = fields.Boolean( + string="当前合同", default=True, compute="_compute_current_contract", store=True + ) + is_company = fields.Boolean( + string="本公司", + default=True, + compute="_compute_is_company", + search="_search_part_of_company", + ) - @api.depends('date_start', 'date_end') + @api.depends("date_start", "date_end") def _compute_current_contract(self): today = date.today() for contract in self: @@ -60,188 +97,197 @@ class HrContract(models.Model): end_valid = not contract.date_end or contract.date_end >= today contract.current_contract = start_valid and end_valid - - @api.onchange('date_start') + @api.onchange("date_start") def _onchange_date_end(self): for record in self: if record.date_start: record.employee_id.entry_date = record.date_start - record.date_end = record.date_start + relativedelta(years=1) - relativedelta(days=1) + record.date_end = ( + record.date_start + relativedelta(years=1) - relativedelta(days=1) + ) - @api.onchange('contract_type_id') + @api.onchange("contract_type_id") def _onchange_contract_type_id(self): for record in self: if record.contract_type_id: - if record.contract_type_id.name == '正式合同(一签)': - record.date_end = record.date_start + relativedelta(years=1) - relativedelta(days=1) - elif record.contract_type_id.name == '正式合同(二签)': - record.date_end = record.date_start + relativedelta(years=3) - relativedelta(days=1) + if record.contract_type_id.name == "正式合同(一签)": + record.date_end = ( + record.date_start + + relativedelta(years=1) + - relativedelta(days=1) + ) + elif record.contract_type_id.name == "正式合同(二签)": + record.date_end = ( + record.date_start + + relativedelta(years=3) + - relativedelta(days=1) + ) - @api.onchange('date_start') + @api.onchange("date_start") def _onchange_date_start(self): for record in self: - if record.date_start and record.state == 'open' and record.employee_id: + if record.date_start and record.state == "open" and record.employee_id: record.employee_id.entry_date = record.date_start def renew(self): contract_ids = self.env["hr.contract"].browse( - self._context.get('active_ids', self._context.get('active_id'))) + self._context.get("active_ids", self._context.get("active_id")) + ) for record in contract_ids: if len(record) > 1: raise UserError("只能选择一个合同续签") return { - 'name': '续签', - 'type': 'ir.actions.act_window', - 'res_model': 'yuthon.renewal.approval', - 'view_mode': 'form', - 'context': { - 'default_employee_id': self.employee_id.id, - 'default_current_status': self.date_end, - 'default_contract_id': self.id, + "name": "续签", + "type": "ir.actions.act_window", + "res_model": "yuthon.renewal.approval", + "view_mode": "form", + "context": { + "default_employee_id": self.employee_id.id, + "default_current_status": self.date_end, + "default_contract_id": self.id, + }, } - } def pub_leaving_employee(self): - record_id = self.env["hr.contract"].browse(self._context.get('active_ids', self._context.get('active_id'))) + record_id = self.env["hr.contract"].browse( + self._context.get("active_ids", self._context.get("active_id")) + ) if len(record_id) != 1: raise UserError("请选择一个合同") - form_id = self.env.ref('yuthon_hr_employee_approval.view_yuthon_leaving_approval_form').id + form_id = self.env.ref( + "yuthon_hr_employee_approval.view_yuthon_leaving_approval_form" + ).id return { "type": "ir.actions.act_window", "name": "离职申请", "res_model": "yuthon.leaving.approval", "views": [[form_id, "form"]], "context": { - 'default_employee_id': self.employee_id.id, - } + "default_employee_id": self.employee_id.id, + }, } def write(self, vals): """在写入时自动更新合同状态""" today = fields.Date.today() update_state = False - if 'date_start' in vals: + if "date_start" in vals: update_state = True - if 'date_end' in vals: + if "date_end" in vals: update_state = True - if 'termination_date' in vals: + if "termination_date" in vals: update_state = True if update_state: for contract in self: # 获取最新的开始日期 - start_date = fields.Date.to_date(vals.get('date_start', contract.date_start)) + start_date = fields.Date.to_date( + vals.get("date_start", contract.date_start) + ) # 获取最新的结束日期(空值视为无限大) - end_date = vals.get('date_end', contract.date_end) + end_date = vals.get("date_end", contract.date_end) end_date = fields.Date.to_date(end_date) if end_date else None # 获取最新的中止时间(空值视为未中止) - termination_date = vals.get('termination_date', contract.termination_date) - termination_date = fields.Date.to_date(termination_date) if termination_date else None + termination_date = vals.get( + "termination_date", contract.termination_date + ) + termination_date = ( + fields.Date.to_date(termination_date) if termination_date else None + ) # 判断合同状态 - if termination_date and termination_date < today: # 新增:优先判断是否已中止 - new_state = 'cancel' + if ( + termination_date and termination_date < today + ): # 新增:优先判断是否已中止 + new_state = "cancel" elif start_date > today: - new_state = 'draft' + new_state = "draft" elif end_date and end_date < today: - new_state = 'close' + new_state = "close" else: - new_state = 'open' + new_state = "open" # 更新当前合同的状态 - if 'state' not in vals: - vals['state'] = new_state + if "state" not in vals: + vals["state"] = new_state return super(HrContract, self).write(vals) - @api.model_create_multi - def create(self, vals): # todo 不触发?? - """在创建时自动更新合同状态""" - today = fields.Date.today() - - start_date = fields.Date.to_date(vals.get('date_start')) - end_date = vals.get('date_end') - end_date = fields.Date.to_date(end_date) if end_date else None - termination_date = vals.get('termination_date') - termination_date = fields.Date.to_date(termination_date) if termination_date else None - - # 根据日期判断状态 - if termination_date and termination_date < today: - vals['state'] = 'cancel' - elif start_date > today: - vals['state'] = 'draft' - elif end_date and end_date < today: - vals['state'] = 'close' - else: - vals['state'] = 'open' - - return super(HrContract, self).create(vals) - def update_contract_states(self): today = date.today() - active_contracts = self.search([ - ('state', 'not in', ['cancel']), - ]) + active_contracts = self.search( + [ + ("state", "not in", ["cancel"]), + ] + ) for contract in active_contracts: - new_state = 'open' if not contract.date_end or contract.date_end >= today else 'close' - if new_state == 'open': - conflicting_contracts = self.search([ - ('id', '!=', contract.id), - ('employee_id', '=', contract.employee_id.id), - ('state', '=', 'open'), - ]) + new_state = ( + "open" + if not contract.date_end or contract.date_end >= today + else "close" + ) + if new_state == "open": + conflicting_contracts = self.search( + [ + ("id", "!=", contract.id), + ("employee_id", "=", contract.employee_id.id), + ("state", "=", "open"), + ] + ) if conflicting_contracts: continue contract.state = new_state - @api.depends_context('uid', 'company') - @api.depends('company_id') + @api.depends_context("uid", "company") + @api.depends("company_id") def _compute_is_company(self): active_company_ids = self.env.companies for employee in self: employee.is_company = employee.company_id in active_company_ids def _search_part_of_company(self, operator, value): - if operator not in ('=', '!=') or not isinstance(value, bool): - raise UserError(('Operation not supported')) + if operator not in ("=", "!=") or not isinstance(value, bool): + raise UserError(("Operation not supported")) company_ids = self.env.companies.ids # 获取公司ID列表 # 处理反向操作符 if not value: - operator = '!=' if operator == '=' else '=' + operator = "!=" if operator == "=" else "=" # 使用company_id in company_ids的结构 - if operator == '=': - return [('company_id', 'in', company_ids)] + if operator == "=": + return [("company_id", "in", company_ids)] else: # operator == '!=' - return [('company_id', 'not in', company_ids)] + return [("company_id", "not in", company_ids)] # @api.onchange('resource_calendar_id') # def _onchange_resource_calendar_id(self): - # if self.resource_calendar_id: - # self.employee_id.sudo().write({'resource_calendar_id': self.resource_calendar_id.id}) + # if self.resource_calendar_id: + # self.employee_id.sudo().write({'resource_calendar_id': self.resource_calendar_id.id}) - @api.depends('contract_type_id') + @api.depends("contract_type_id") def _compute_simplified_name(self): for record in self: if record.contract_type_id and record.employee_id: - record.name = record.contract_type_id.name + '合同' + record.name = record.contract_type_id.name + "合同" else: - record.name = ' ' + record.name = " " if record.contract_type_id: - if record.contract_type_id.name == '实习协议': + if record.contract_type_id.name == "实习协议": record.is_internship = True else: record.is_internship = False - @api.depends('contract_type_id') + @api.depends("contract_type_id") def _compute_name(self): for record in self: if record.contract_type_id and record.employee_id: - record.name = record.employee_id.name + record.contract_type_id.name + '合同' + record.name = ( + record.employee_id.name + record.contract_type_id.name + "合同" + ) else: - record.name = ' ' + record.name = " " if record.contract_type_id: - if record.contract_type_id.name == '实习协议': + if record.contract_type_id.name == "实习协议": record.is_internship = True else: record.is_internship = False @@ -257,35 +303,74 @@ class HrContract(models.Model): def update_contract(self): contract_ids = self.env["hr.contract"].browse( - self._context.get('active_ids', self._context.get('active_id'))) + self._context.get("active_ids", self._context.get("active_id")) + ) for contract in contract_ids: company_id = contract.employee_id.company_id - resource_calendar_id = self.env['resource.calendar'].search([('company_id', '=', company_id.id)], limit=1) + resource_calendar_id = self.env["resource.calendar"].search( + [("company_id", "=", company_id.id)], limit=1 + ) contract.resource_calendar_id = resource_calendar_id.id - @api.onchange('salary_group_id') + @api.onchange("salary_group_id") def _compute_salary_group_id(self): for contract_id in self: - employee = self.env['hr.employee'].search([('id', '=', contract_id.employee_id.id)], limit=1) + employee = self.env["hr.employee"].search( + [("id", "=", contract_id.employee_id.id)], limit=1 + ) if employee: employee.salary_group_id = contract_id.salary_group_id.id else: employee.salary_group_id = False - @api.onchange('is_annual_salary') + @api.onchange("is_annual_salary") def _compute_is_annual_salary(self): for contract_id in self: - employee = self.env['hr.employee'].search([('id', '=', contract_id.employee_id.id)], limit=1) + employee = self.env["hr.employee"].search( + [("id", "=", contract_id.employee_id.id)], limit=1 + ) if employee: employee.is_annual_salary = contract_id.is_annual_salary else: employee.is_annual_salary = False - @api.model - def create(self, vals): - contract = super(HrContract, self).create(vals) - if contract.employee_id: - contract.employee_id.write({ - 'contract_id': contract.id, - }) - return contract + @api.model_create_multi + def create(self, vals_list): + today = fields.Date.today() + + # 先处理状态 + for vals in vals_list: + start_date = ( + fields.Date.to_date(vals.get("date_start")) + if vals.get("date_start") + else None + ) + end_date = ( + fields.Date.to_date(vals.get("date_end")) + if vals.get("date_end") + else None + ) + termination_date = ( + fields.Date.to_date(vals.get("termination_date")) + if vals.get("termination_date") + else None + ) + + if termination_date and termination_date < today: + vals["state"] = "cancel" + elif start_date and start_date > today: + vals["state"] = "draft" + elif end_date and end_date < today: + vals["state"] = "close" + else: + vals["state"] = "open" + + # 创建合同 + contracts = super().create(vals_list) + + # 更新员工合同字段 + for contract in contracts: + if contract.employee_id: + contract.employee_id.write({"contract_id": contract.id}) + + return contracts diff --git a/yuthon_property/views/property_accounts_receivable_views.xml b/yuthon_property/views/property_accounts_receivable_views.xml index 9da15f90a..01fca119c 100644 --- a/yuthon_property/views/property_accounts_receivable_views.xml +++ b/yuthon_property/views/property_accounts_receivable_views.xml @@ -1,107 +1,105 @@ - property.accounts.receivable.tree - property.accounts.receivable - - - - - - - - - - - - - - - - - - - - - - - - - -