[IMP] hr: Remove address_home_id field
Improve usability of employee form. It is confusing for end users to create another record to encode the employee address. Move all the private information on the hr.employee record itself. Remove the M2O address_home_id. TaskID: 3101400
This commit is contained in:
@@ -34,9 +34,9 @@
|
||||
'views/hr_work_location_views.xml',
|
||||
'views/hr_views.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'views/res_partner_views.xml',
|
||||
'views/discuss_channel_views.xml',
|
||||
'views/res_users.xml',
|
||||
'views/res_partner_views.xml',
|
||||
'views/hr_templates.xml',
|
||||
'data/hr_data.xml',
|
||||
],
|
||||
|
||||
@@ -6,19 +6,12 @@
|
||||
<field name="name">Administration</field>
|
||||
</record>
|
||||
|
||||
<record id="res_partner_admin_private_address" model="res.partner">
|
||||
<field name="name">Administrator</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="email">admin@example.com</field>
|
||||
<field name="type">private</field>
|
||||
</record>
|
||||
|
||||
<record id="employee_admin" model="hr.employee">
|
||||
<field name="name" eval="obj(ref('base.partner_admin')).name" model="res.partner"/>
|
||||
<field name="department_id" ref="dep_administration"/>
|
||||
<field name="user_id" ref="base.user_admin"/>
|
||||
<field name="address_id" ref="base.main_partner"/>
|
||||
<field name="address_home_id" ref="res_partner_admin_private_address"/>
|
||||
<field name="private_email">admin@example.com</field>
|
||||
<field name="image_1920" eval="obj(ref('base.partner_admin')).image_1920" model="res.partner"/>
|
||||
</record>
|
||||
|
||||
|
||||
+446
-485
File diff suppressed because it is too large
Load Diff
@@ -17,8 +17,8 @@ from . import mail_alias
|
||||
from . import discuss_channel
|
||||
from . import models
|
||||
from . import res_config_settings
|
||||
from . import res_partner
|
||||
from . import res_users
|
||||
from . import res_company
|
||||
from . import res_partner
|
||||
from . import resource
|
||||
from . import ir_ui_menu
|
||||
|
||||
@@ -30,6 +30,10 @@ class HrEmployeePrivate(models.Model):
|
||||
_inherit = ['hr.employee.base', 'mail.thread.main.attachment', 'mail.activity.mixin', 'resource.mixin', 'avatar.mixin']
|
||||
_mail_post_access = 'read'
|
||||
|
||||
@api.model
|
||||
def _lang_get(self):
|
||||
return self.env['res.lang'].get_installed()
|
||||
|
||||
# resource and user
|
||||
# required on the resource, make sure required="True" set in the view
|
||||
name = fields.Char(string="Employee Name", related='resource_id.name', store=True, readonly=False, tracking=True)
|
||||
@@ -41,17 +45,19 @@ class HrEmployeePrivate(models.Model):
|
||||
company_id = fields.Many2one('res.company', required=True)
|
||||
company_country_id = fields.Many2one('res.country', 'Company Country', related='company_id.country_id', readonly=True)
|
||||
company_country_code = fields.Char(related='company_country_id.code', depends=['company_country_id'], readonly=True)
|
||||
# private partner
|
||||
address_home_id = fields.Many2one(
|
||||
'res.partner', 'Address', help='Enter here the private address of the employee, not the one linked to your company.',
|
||||
groups="hr.group_hr_user", tracking=True,
|
||||
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
|
||||
is_address_home_a_company = fields.Boolean(
|
||||
'The employee address has a company linked',
|
||||
compute='_compute_is_address_home_a_company',
|
||||
)
|
||||
private_email = fields.Char(related='address_home_id.email', string="Private Email", groups="hr.group_hr_user")
|
||||
lang = fields.Selection(related='address_home_id.lang', string="Lang", groups="hr.group_hr_user", readonly=False)
|
||||
# private info
|
||||
private_street = fields.Char(string="Private Street", groups="hr.group_hr_user")
|
||||
private_street2 = fields.Char(string="Private Street2", groups="hr.group_hr_user")
|
||||
private_city = fields.Char(string="Private City", groups="hr.group_hr_user")
|
||||
private_state_id = fields.Many2one(
|
||||
"res.country.state", string="Private State",
|
||||
domain="[('country_id', '=?', private_country_id)]",
|
||||
groups="hr.group_hr_user")
|
||||
private_zip = fields.Char(string="Private Zip", groups="hr.group_hr_user")
|
||||
private_country_id = fields.Many2one("res.country", string="Private Country", groups="hr.group_hr_user")
|
||||
private_phone = fields.Char(string="Private Phone", groups="hr.group_hr_user")
|
||||
private_email = fields.Char(string="Private Email", groups="hr.group_hr_user")
|
||||
lang = fields.Selection(selection=_lang_get, string="Lang", groups="hr.group_hr_user")
|
||||
country_id = fields.Many2one(
|
||||
'res.country', 'Nationality (Country)', groups="hr.group_hr_user", tracking=True)
|
||||
gender = fields.Selection([
|
||||
@@ -78,7 +84,7 @@ class HrEmployeePrivate(models.Model):
|
||||
passport_id = fields.Char('Passport No', groups="hr.group_hr_user", tracking=True)
|
||||
bank_account_id = fields.Many2one(
|
||||
'res.partner.bank', 'Bank Account Number',
|
||||
domain="[('partner_id', '=', address_home_id), '|', ('company_id', '=', False), ('company_id', '=', company_id)]",
|
||||
domain="[('partner_id', '=', work_contact_id), '|', ('company_id', '=', False), ('company_id', '=', company_id)]",
|
||||
groups="hr.group_hr_user",
|
||||
tracking=True,
|
||||
help='Employee bank account to pay salaries')
|
||||
@@ -111,7 +117,6 @@ class HrEmployeePrivate(models.Model):
|
||||
help="The employee type. Although the primary purpose may seem to categorize employees, this field has also an impact in the Contract History. Only Employee type is supposed to be under contract and will have a Contract History.")
|
||||
|
||||
job_id = fields.Many2one(tracking=True)
|
||||
phone = fields.Char(related='address_home_id.phone', related_sudo=False, readonly=False, string="Private Phone", groups="hr.group_hr_user")
|
||||
# employee in company
|
||||
child_ids = fields.One2many('hr.employee', 'parent_id', string='Direct subordinates')
|
||||
category_ids = fields.Many2many(
|
||||
@@ -372,7 +377,6 @@ class HrEmployeePrivate(models.Model):
|
||||
onboarding_notes_bodies = {}
|
||||
hr_root_menu = self.env.ref('hr.menu_hr_root')
|
||||
for employee in employees:
|
||||
employee._message_subscribe(employee.address_home_id.ids)
|
||||
# Launch onboarding plans
|
||||
url = '/web#%s' % url_encode({
|
||||
'action': 'hr.plan_wizard_action',
|
||||
@@ -387,16 +391,16 @@ class HrEmployeePrivate(models.Model):
|
||||
return employees
|
||||
|
||||
def write(self, vals):
|
||||
if 'address_home_id' in vals:
|
||||
if 'work_contact_id' in vals:
|
||||
account_id = vals.get('bank_account_id') or self.bank_account_id.id
|
||||
if account_id:
|
||||
bank_account = self.env['res.partner.bank'].browse(account_id)
|
||||
if vals['address_home_id'] != bank_account.partner_id.id:
|
||||
if vals['work_contact_id'] != bank_account.partner_id.id:
|
||||
bank_account.sudo().allow_out_payment = False
|
||||
bank_account.partner_id = vals['address_home_id']
|
||||
self.message_unsubscribe(self.address_home_id.ids)
|
||||
if vals['address_home_id']:
|
||||
self._message_subscribe([vals['address_home_id']])
|
||||
bank_account.partner_id = vals['work_contact_id']
|
||||
self.message_unsubscribe(self.work_contact_id.ids)
|
||||
if vals['work_contact_id']:
|
||||
self._message_subscribe([vals['work_contact_id']])
|
||||
if 'user_id' in vals:
|
||||
# Update the profile pictures with user, except if provided
|
||||
vals.update(self._sync_user(self.env['res.users'].browse(vals['user_id']),
|
||||
@@ -431,8 +435,6 @@ class HrEmployeePrivate(models.Model):
|
||||
'departure_description': False,
|
||||
'departure_date': False
|
||||
})
|
||||
archived_addresses = unarchived_employees.mapped('address_home_id').filtered(lambda addr: not addr.active)
|
||||
archived_addresses.toggle_active()
|
||||
|
||||
archived_employees = self.filtered(lambda e: not e.active)
|
||||
if archived_employees:
|
||||
@@ -474,22 +476,6 @@ class HrEmployeePrivate(models.Model):
|
||||
for employee in self:
|
||||
employee.barcode = '041'+"".join(choice(digits) for i in range(9))
|
||||
|
||||
@api.depends('address_home_id', 'user_partner_id')
|
||||
def _compute_related_contacts(self):
|
||||
super()._compute_related_contacts()
|
||||
for employee in self:
|
||||
employee.related_contact_ids |= employee.address_home_id | employee.user_partner_id
|
||||
|
||||
@api.depends('address_home_id.parent_id')
|
||||
def _compute_is_address_home_a_company(self):
|
||||
"""Checks that chosen address (res.partner) is not linked to a company.
|
||||
"""
|
||||
for employee in self:
|
||||
try:
|
||||
employee.is_address_home_a_company = employee.address_home_id.parent_id.id is not False
|
||||
except AccessError:
|
||||
employee.is_address_home_a_company = False
|
||||
|
||||
def _get_tz(self):
|
||||
# Finds the first valid timezone in his tz, his work hours tz,
|
||||
# the company calendar tz or UTC and returns it as a string
|
||||
|
||||
@@ -31,8 +31,6 @@ class HrEmployeeBase(models.AbstractModel):
|
||||
mobile_phone = fields.Char('Work Mobile', compute="_compute_work_contact_details", store=True, inverse='_inverse_work_contact_details')
|
||||
work_email = fields.Char('Work Email', compute="_compute_work_contact_details", store=True, inverse='_inverse_work_contact_details')
|
||||
work_contact_id = fields.Many2one('res.partner', 'Work Contact', copy=False)
|
||||
related_contact_ids = fields.Many2many('res.partner', 'Related Contacts', compute='_compute_related_contacts')
|
||||
related_contacts_count = fields.Integer('Number of related contacts', compute='_compute_related_contacts_count')
|
||||
work_location_id = fields.Many2one('hr.work.location', 'Work Location', compute="_compute_work_location_id", store=True, readonly=False,
|
||||
domain="[('address_id', '=', address_id), '|', ('company_id', '=', False), ('company_id', '=', company_id)]")
|
||||
user_id = fields.Many2one('res.users')
|
||||
@@ -174,26 +172,6 @@ class HrEmployeeBase(models.AbstractModel):
|
||||
'mobile': employee.mobile_phone,
|
||||
})
|
||||
|
||||
@api.depends('work_contact_id')
|
||||
def _compute_related_contacts(self):
|
||||
for employee in self:
|
||||
employee.related_contact_ids = employee.work_contact_id
|
||||
|
||||
@api.depends('related_contact_ids')
|
||||
def _compute_related_contacts_count(self):
|
||||
for employee in self:
|
||||
employee.related_contacts_count = len(employee.related_contact_ids)
|
||||
|
||||
def action_related_contacts(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': _("Related Contacts"),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'kanban,tree,form',
|
||||
'res_model': 'res.partner',
|
||||
'domain': [('id', 'in', self.related_contact_ids.ids)]
|
||||
}
|
||||
|
||||
@api.depends('company_id')
|
||||
def _compute_address_id(self):
|
||||
for employee in self:
|
||||
|
||||
@@ -25,7 +25,6 @@ class HrEmployeePublic(models.Model):
|
||||
work_phone = fields.Char(readonly=True)
|
||||
work_email = fields.Char(readonly=True)
|
||||
work_contact_id = fields.Many2one(readonly=True)
|
||||
related_contact_ids = fields.Many2many(readonly=True)
|
||||
work_location_id = fields.Many2one(readonly=True)
|
||||
user_id = fields.Many2one(readonly=True)
|
||||
resource_id = fields.Many2one(readonly=True)
|
||||
@@ -57,12 +56,6 @@ class HrEmployeePublic(models.Model):
|
||||
for employee in self:
|
||||
employee.employee_id = self.env['hr.employee'].browse(employee.id)
|
||||
|
||||
@api.depends('user_partner_id')
|
||||
def _compute_related_contacts(self):
|
||||
super()._compute_related_contacts()
|
||||
for employee in self:
|
||||
employee.related_contact_ids |= employee.user_partner_id
|
||||
|
||||
@api.model
|
||||
def _get_fields(self):
|
||||
return ','.join('emp.%s' % name for name, field in self._fields.items() if field.store and field.type not in ['many2many', 'one2many'])
|
||||
|
||||
@@ -2,30 +2,16 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, _
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
|
||||
class Partner(models.Model):
|
||||
_inherit = ['res.partner']
|
||||
|
||||
employee_ids = fields.One2many(
|
||||
'hr.employee', 'address_home_id', string='Employees', groups="hr.group_hr_user",
|
||||
'hr.employee', 'work_contact_id', string='Employees', groups="hr.group_hr_user",
|
||||
help="Related employees based on their private address")
|
||||
employees_count = fields.Integer(compute='_compute_employees_count', groups="hr.group_hr_user")
|
||||
|
||||
def _compute_display_name(self):
|
||||
""" Override to allow an employee to see its private address in his profile.
|
||||
This avoids to relax access rules on `res.parter` and to add an `ir.rule`.
|
||||
(advantage in both security and performance).
|
||||
Use a try/except instead of systematically checking to minimize the impact on performance.
|
||||
"""
|
||||
try:
|
||||
super()._compute_display_name()
|
||||
except AccessError as e:
|
||||
if len(self) == 1 and self in self.env.user.employee_ids.mapped('address_home_id'):
|
||||
super(Partner, self.sudo())._compute_display_name()
|
||||
raise e
|
||||
|
||||
def _compute_employees_count(self):
|
||||
for partner in self:
|
||||
partner.employees_count = len(partner.employee_ids)
|
||||
|
||||
@@ -12,7 +12,6 @@ HR_READABLE_FIELDS = [
|
||||
'active',
|
||||
'child_ids',
|
||||
'employee_id',
|
||||
'address_home_id',
|
||||
'employee_ids',
|
||||
'employee_parent_id',
|
||||
'hr_presence_state',
|
||||
@@ -21,6 +20,7 @@ HR_READABLE_FIELDS = [
|
||||
'can_edit',
|
||||
'is_system',
|
||||
'employee_resource_calendar_id',
|
||||
'work_contact_id',
|
||||
]
|
||||
|
||||
HR_WRITABLE_FIELDS = [
|
||||
@@ -31,6 +31,8 @@ HR_WRITABLE_FIELDS = [
|
||||
'private_state_id',
|
||||
'private_zip',
|
||||
'private_country_id',
|
||||
'private_phone',
|
||||
'private_email',
|
||||
'address_id',
|
||||
'barcode',
|
||||
'birthday',
|
||||
@@ -46,9 +48,7 @@ HR_WRITABLE_FIELDS = [
|
||||
'employee_country_id',
|
||||
'gender',
|
||||
'identification_id',
|
||||
'is_address_home_a_company',
|
||||
'job_title',
|
||||
'private_email',
|
||||
'km_home_work',
|
||||
'marital',
|
||||
'mobile_phone',
|
||||
@@ -56,7 +56,6 @@ HR_WRITABLE_FIELDS = [
|
||||
'employee_parent_id',
|
||||
'passport_id',
|
||||
'permit_no',
|
||||
'employee_phone',
|
||||
'pin',
|
||||
'place_of_birth',
|
||||
'spouse_birthdate',
|
||||
@@ -90,26 +89,25 @@ class User(models.Model):
|
||||
job_title = fields.Char(related='employee_id.job_title', readonly=False, related_sudo=False)
|
||||
work_phone = fields.Char(related='employee_id.work_phone', readonly=False, related_sudo=False)
|
||||
mobile_phone = fields.Char(related='employee_id.mobile_phone', readonly=False, related_sudo=False)
|
||||
employee_phone = fields.Char(related='employee_id.phone', readonly=False, related_sudo=False)
|
||||
work_email = fields.Char(related='employee_id.work_email', readonly=False, related_sudo=False)
|
||||
category_ids = fields.Many2many(related='employee_id.category_ids', string="Employee Tags", readonly=False, related_sudo=False)
|
||||
department_id = fields.Many2one(related='employee_id.department_id', readonly=False, related_sudo=False)
|
||||
address_id = fields.Many2one(related='employee_id.address_id', readonly=False, related_sudo=False)
|
||||
work_contact_id = fields.Many2one(related='employee_id.work_contact_id', readonly=False, related_sudo=False)
|
||||
work_location_id = fields.Many2one(related='employee_id.work_location_id', readonly=False, related_sudo=False)
|
||||
employee_parent_id = fields.Many2one(related='employee_id.parent_id', readonly=False, related_sudo=False)
|
||||
coach_id = fields.Many2one(related='employee_id.coach_id', readonly=False, related_sudo=False)
|
||||
address_home_id = fields.Many2one(related='employee_id.address_home_id', readonly=False, related_sudo=False)
|
||||
private_street = fields.Char(related='address_home_id.street', string="Private Street", readonly=False, related_sudo=False)
|
||||
private_street2 = fields.Char(related='address_home_id.street2', string="Private Street2", readonly=False, related_sudo=False)
|
||||
private_city = fields.Char(related='address_home_id.city', string="Private City", readonly=False, related_sudo=False)
|
||||
private_street = fields.Char(related='employee_id.private_street', string="Private Street", readonly=False, related_sudo=False)
|
||||
private_street2 = fields.Char(related='employee_id.private_street2', string="Private Street2", readonly=False, related_sudo=False)
|
||||
private_city = fields.Char(related='employee_id.private_city', string="Private City", readonly=False, related_sudo=False)
|
||||
private_state_id = fields.Many2one(
|
||||
related='address_home_id.state_id', string="Private State", readonly=False, related_sudo=False,
|
||||
related='employee_id.private_state_id', string="Private State", readonly=False, related_sudo=False,
|
||||
domain="[('country_id', '=?', private_country_id)]")
|
||||
private_zip = fields.Char(related='address_home_id.zip', readonly=False, string="Private Zip", related_sudo=False)
|
||||
private_country_id = fields.Many2one(related='address_home_id.country_id', string="Private Country", readonly=False, related_sudo=False)
|
||||
is_address_home_a_company = fields.Boolean(related='employee_id.is_address_home_a_company', readonly=False, related_sudo=False)
|
||||
private_email = fields.Char(related='address_home_id.email', string="Private Email", readonly=False)
|
||||
private_lang = fields.Selection(related='address_home_id.lang', string="Employee Lang", readonly=False)
|
||||
private_zip = fields.Char(related='employee_id.private_zip', readonly=False, string="Private Zip", related_sudo=False)
|
||||
private_country_id = fields.Many2one(related='employee_id.private_country_id', string="Private Country", readonly=False, related_sudo=False)
|
||||
private_phone = fields.Char(related='employee_id.private_phone', readonly=False, related_sudo=False)
|
||||
private_email = fields.Char(related='employee_id.private_email', string="Private Email", readonly=False)
|
||||
private_lang = fields.Selection(related='employee_id.lang', string="Employee Lang", readonly=False)
|
||||
km_home_work = fields.Integer(related='employee_id.km_home_work', readonly=False, related_sudo=False)
|
||||
# res.users already have a field bank_account_id and country_id from the res.partner inheritance: don't redefine them
|
||||
employee_bank_account_id = fields.Many2one(related='employee_id.bank_account_id', string="Employee's Bank Account Number", related_sudo=False, readonly=False)
|
||||
|
||||
@@ -112,13 +112,12 @@ class TestSelfAccessRights(TestHrCommon):
|
||||
cls.richard_emp = cls.env['hr.employee'].create({
|
||||
'name': 'Richard',
|
||||
'user_id': cls.richard.id,
|
||||
'address_home_id': cls.env['res.partner'].create({'name': 'Richard', 'phone': '21454', 'type': 'private'}).id,
|
||||
'private_phone': '21454',
|
||||
})
|
||||
cls.hubert = new_test_user(cls.env, login='hub', groups='base.group_user', name='Simple employee', email='hub@example.com')
|
||||
cls.hubert_emp = cls.env['hr.employee'].create({
|
||||
'name': 'Hubert',
|
||||
'user_id': cls.hubert.id,
|
||||
'address_home_id': cls.env['res.partner'].create({'name': 'Hubert', 'type': 'private'}).id,
|
||||
})
|
||||
|
||||
cls.protected_fields_emp = OrderedDict([(k, v) for k, v in cls.env['hr.employee']._fields.items() if v.groups == 'hr.group_hr_user'])
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="last_activity_time" invisible="1"/>
|
||||
<field name="last_activity" invisible="1"/>
|
||||
<field name="work_contact_id" invisible="1"/>
|
||||
<header>
|
||||
<button name="%(plan_wizard_action)d" string="Launch Plan" type="action" groups="hr.group_hr_user" attrs="{'invisible': [('active', '=', False)]}"/>
|
||||
</header>
|
||||
@@ -135,15 +136,18 @@
|
||||
<page name="personal_information" string="Private Information" groups="hr.group_hr_user">
|
||||
<group>
|
||||
<group string="Private Contact">
|
||||
<field name="address_home_id"
|
||||
context="{
|
||||
'show_address': 1,
|
||||
'default_type': 'private',
|
||||
'form_view_ref': 'base.res_partner_view_form_private'}"
|
||||
options='{"always_reload": True, "highlight_first_line": True}'/>
|
||||
<label for="private_street" string="Private Address"/>
|
||||
<div class="o_address_format">
|
||||
<field name="private_street" placeholder="Street..." class="o_address_street"/>
|
||||
<field name="private_street2" placeholder="Street 2..." class="o_address_street"/>
|
||||
<field name="private_city" placeholder="City" class="o_address_city"/>
|
||||
<field name="private_state_id" class="o_address_state" placeholder="State" options="{'no_open': True, 'no_quick_create': True}" context="{'default_country_id': private_country_id}"/>
|
||||
<field name="private_zip" placeholder="ZIP" class="o_address_zip"/>
|
||||
<field name="private_country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}'/>
|
||||
</div>
|
||||
<field name="private_email" string="Email"/>
|
||||
<field name="phone" string="Phone" readonly="True"/>
|
||||
<field name="bank_account_id" context="{'default_partner_id': address_home_id}"/>
|
||||
<field name="private_phone" string="Phone"/>
|
||||
<field name="bank_account_id" context="{'default_partner_id': work_contact_id}" options="{'no_quick_create': True}" attrs="{'readonly': [('id', '=', False)]}"/>
|
||||
<field name="lang" string="Language"/>
|
||||
<label for="km_home_work"/>
|
||||
<div class="o_row" name="div_km_home_work">
|
||||
@@ -215,30 +219,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- This part of the view_employee_form is defined separately so that the
|
||||
smartbutton can have lower priority and therefore be last in the list. -->
|
||||
<record id="view_employee_form_smartbutton" model="ir.ui.view">
|
||||
<field name="name">view.employee.form.smartbutton</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="inherit_id" ref="view_employee_form"/>
|
||||
<field name="priority" eval="1000"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="button_box" position="inside">
|
||||
<field name="related_contacts_count" invisible="1"/>
|
||||
<button name="action_related_contacts"
|
||||
class="oe_stat_button"
|
||||
icon="fa-address-card-o"
|
||||
type="object"
|
||||
attrs="{'invisible': ['|', ('id', '=', False), ('related_contacts_count', '=', 0)]}">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value"><field name="related_contacts_count"/></span>
|
||||
<span class="o_stat_text">Contacts</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_employee_view_graph" model="ir.ui.view">
|
||||
<field name="name">hr.employee.view.graph</field>
|
||||
<field name="model">hr.employee</field>
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
<xpath expr="//field[@name='company_id']" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</xpath>
|
||||
<field name="share" position="after">
|
||||
<field name="work_contact_id" invisible="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -134,20 +137,18 @@
|
||||
<group>
|
||||
<group string="Contact Information">
|
||||
<field name="employee_ids" invisible="1"/>
|
||||
<field name="address_home_id" invisible="1"/>
|
||||
<label for="private_street" string="Private Address"/>
|
||||
<div class="o_address_format">
|
||||
<field name="private_street" placeholder="Street..." class="o_address_street"/>
|
||||
<field name="private_street2" placeholder="Street 2..." class="o_address_street"/>
|
||||
<field name="private_city" placeholder="City" class="o_address_city"/>
|
||||
<field name="private_state_id" class="o_address_state" placeholder="State" options="{'no_open': True, 'no_quick_create': True}" context="{'default_country_id': private_country_id}"/>
|
||||
<field name="private_zip" placeholder="ZIP" class="o_address_zip"/>
|
||||
<field name="private_country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}'/>
|
||||
<field name="private_street" placeholder="Street..." class="o_address_street" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="private_street2" placeholder="Street 2..." class="o_address_street" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="private_city" placeholder="City" class="o_address_city" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="private_state_id" class="o_address_state" placeholder="State" options="{'no_open': True, 'no_quick_create': True}" context="{'default_country_id': private_country_id}" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="private_zip" placeholder="ZIP" class="o_address_zip" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="private_country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}' attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
</div>
|
||||
|
||||
<field name="private_email" string="Email" attrs="{'readonly': [('can_edit', '=', False)], 'invisible': [('address_home_id', '=', False)]}"/>
|
||||
<field name="employee_phone" string="Phone" class="o_force_ltr" attrs="{'readonly': [('can_edit', '=', False)], 'invisible': [('address_home_id', '=', False)]}"/>
|
||||
<field name="private_lang" string="Language" attrs="{'readonly': [('can_edit', '=', False)], 'invisible': [('address_home_id', '=', False)]}"/>
|
||||
<field name="private_email" string="Email" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="private_phone" string="Phone" class="o_force_ltr" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="private_lang" string="Language" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="employee_bank_account_id" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="km_home_work" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
</group>
|
||||
|
||||
@@ -21,7 +21,6 @@ class HrDepartureWizard(models.TransientModel):
|
||||
'hr.employee', string='Employee', required=True,
|
||||
default=lambda self: self.env.context.get('active_id', None),
|
||||
)
|
||||
archive_private_address = fields.Boolean('Archive Private Address', default=True)
|
||||
|
||||
def action_register_departure(self):
|
||||
employee = self.employee_id
|
||||
@@ -30,9 +29,3 @@ class HrDepartureWizard(models.TransientModel):
|
||||
employee.departure_reason_id = self.departure_reason_id
|
||||
employee.departure_description = self.departure_description
|
||||
employee.departure_date = self.departure_date
|
||||
|
||||
if self.archive_private_address:
|
||||
# ignore contact links to internal users
|
||||
private_address = employee.address_home_id
|
||||
if private_address and private_address.active and not self.env['res.users'].search([('partner_id', '=', private_address.id)]):
|
||||
private_address.sudo().toggle_active()
|
||||
|
||||
@@ -24,9 +24,7 @@
|
||||
<div class="o_td_label" id="label_info">
|
||||
<span class="o_form_label o_hr_form_label cursor-default">HR Info</span>
|
||||
</div>
|
||||
<div class="column" id="info">
|
||||
<div><field name="archive_private_address"/><label for="archive_private_address"/></div>
|
||||
</div>
|
||||
<div class="column" id="info"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
<xpath expr="//page[@name='hr_settings']//field[@name='employee_type']" position="after">
|
||||
<field name="first_contract_date" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='bank_account_id']" position="replace">
|
||||
<field name="bank_account_id" context="{'display_partner':True}" attrs="{'invisible' : [('address_home_id', '=', False)]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='resource_calendar_id']" position="replace">
|
||||
<field name="calendar_mismatch" invisible="1"/>
|
||||
<label for="resource_calendar_id"/>
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="hr.employee_mit" model="hr.employee">
|
||||
<field name="address_home_id" ref="base.res_partner_address_3"/>
|
||||
<field name="private_email">douglas.fletcher51@example.com</field>
|
||||
<field name="private_phone">(132)-553-7242</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_expense_account_journal" model="account.journal">
|
||||
@@ -15,22 +16,18 @@
|
||||
<field name="alias_name">purchase_expense</field>
|
||||
</record>
|
||||
|
||||
<record id="res_partner_address_fp" model="res.partner">
|
||||
<field name="name">Pieter Parter's Farm</field>
|
||||
<field name="parent_id" ref="base.partner_root"/>
|
||||
<field name="street">Chaussée de Namur, 40</field>
|
||||
<field name="zip">1367</field>
|
||||
<field name="city">Grand-Rosière-Hottomont</field>
|
||||
<field name="country_id" ref="base.be"/>
|
||||
<field name="type">private</field>
|
||||
</record>
|
||||
|
||||
<record id="hr.employee_fme" model="hr.employee">
|
||||
<field name="address_home_id" ref="res_partner_address_fp"/>
|
||||
<field name="private_street">Chaussée de Namur, 40</field>
|
||||
<field name="private_zip">1367</field>
|
||||
<field name="private_city">Grand-Rosière-Hottomont</field>
|
||||
<field name="private_country_id" ref="base.be"/>
|
||||
</record>
|
||||
|
||||
<record id="hr.employee_al" model="hr.employee">
|
||||
<field name="address_home_id" ref="res_partner_address_fp"/>
|
||||
<field name="private_street">Chaussée de Namur, 40</field>
|
||||
<field name="private_zip">1367</field>
|
||||
<field name="private_city">Grand-Rosière-Hottomont</field>
|
||||
<field name="private_country_id" ref="base.be"/>
|
||||
</record>
|
||||
|
||||
<!-- ++++++++++++++ Expense sheet for Admin ++++++++++++++-->
|
||||
|
||||
@@ -614,7 +614,7 @@ class HrExpense(models.Model):
|
||||
'product_uom_id': self.product_uom_id.id,
|
||||
'analytic_distribution': self.analytic_distribution,
|
||||
'expense_id': self.id,
|
||||
'partner_id': False if self.payment_mode == 'company_account' else self.employee_id.sudo().address_home_id.commercial_partner_id.id,
|
||||
'partner_id': False if self.payment_mode == 'company_account' else self.employee_id.sudo().work_contact_id.id,
|
||||
'tax_ids': [Command.set(self.tax_ids.ids)],
|
||||
}
|
||||
|
||||
@@ -1023,7 +1023,7 @@ class HrExpenseSheet(models.Model):
|
||||
@api.depends('employee_id', 'employee_id.department_id')
|
||||
def _compute_from_employee_id(self):
|
||||
for sheet in self:
|
||||
sheet.address_id = sheet.employee_id.sudo().address_home_id
|
||||
sheet.address_id = sheet.employee_id.sudo().work_contact_id
|
||||
sheet.department_id = sheet.employee_id.department_id
|
||||
sheet.user_id = sheet.employee_id.expense_manager_id or sheet.employee_id.parent_id.user_id
|
||||
|
||||
@@ -1399,7 +1399,7 @@ class HrExpenseSheet(models.Model):
|
||||
# to set it to '' which cause no number to be given to the account.move when posted.
|
||||
'journal_id': self.journal_id.id,
|
||||
'move_type': 'in_invoice',
|
||||
'partner_id': self.employee_id.sudo().address_home_id.commercial_partner_id.id,
|
||||
'partner_id': self.employee_id.sudo().work_contact_id.id,
|
||||
'currency_id': self.currency_id.id,
|
||||
'line_ids':[Command.create(expense._prepare_move_line_vals()) for expense in self.expense_line_ids],
|
||||
}
|
||||
@@ -1441,8 +1441,8 @@ class HrExpenseSheet(models.Model):
|
||||
or journal.company_id.account_journal_payment_credit_account_id
|
||||
)
|
||||
else:
|
||||
if not self.employee_id.sudo().address_home_id:
|
||||
raise UserError(_("No Home Address found for the employee %s, please configure one.") % (self.employee_id.name))
|
||||
partner = self.employee_id.sudo().address_home_id.with_company(self.company_id)
|
||||
if not self.employee_id.sudo().work_contact_id:
|
||||
raise UserError(_("No work contact found for the employee %s, please configure one.") % (self.employee_id.name))
|
||||
partner = self.employee_id.sudo().work_contact_id.with_company(self.company_id)
|
||||
account_dest = partner.property_account_payable_id or partner.parent_id.property_account_payable_id
|
||||
return account_dest.id
|
||||
|
||||
@@ -37,7 +37,7 @@ class TestExpenseCommon(AccountTestInvoicingCommon):
|
||||
cls.expense_employee = cls.env['hr.employee'].create({
|
||||
'name': 'expense_employee',
|
||||
'user_id': cls.expense_user_employee.id,
|
||||
'address_home_id': cls.expense_user_employee.partner_id.id,
|
||||
'work_contact_id': cls.expense_user_employee.partner_id.id,
|
||||
'address_id': cls.expense_user_employee.partner_id.id,
|
||||
})
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ class TestExpenses(TestExpenseCommon):
|
||||
'journal_id': self.company_data['default_journal_bank'].id,
|
||||
'payment_ref': 'pay_ref',
|
||||
'amount': -350.0,
|
||||
'partner_id': self.expense_employee.address_home_id.id,
|
||||
'partner_id': self.expense_employee.work_contact_id.id,
|
||||
})
|
||||
|
||||
# Reconcile without the bank reconciliation widget since the widget is in enterprise.
|
||||
|
||||
@@ -14,7 +14,7 @@ class TestExpensesAccessRights(TestExpenseCommon):
|
||||
expense_employee_2 = self.env['hr.employee'].create({
|
||||
'name': 'expense_employee_2',
|
||||
'user_id': self.env.user.id,
|
||||
'address_home_id': self.env.user.partner_id.id,
|
||||
'work_contact_id': self.env.user.partner_id.id,
|
||||
'address_id': self.env.user.partner_id.id,
|
||||
})
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<field name="driver_employee_id" ref="hr.employee_jep"/>
|
||||
</record>
|
||||
|
||||
<!-- recompute driver_employee_id as we assigned a proper address_home_id to some employees -->
|
||||
<!-- recompute driver_employee_id as we assigned a proper work_contact_id to some employees -->
|
||||
<function model="fleet.vehicle.assignation.log" name="_compute_driver_employee_id">
|
||||
<value model="fleet.vehicle.assignation.log" eval="obj().search([('driver_employee_id', '=', False), ('driver_id', '!=', False)]).ids"/>
|
||||
</function>
|
||||
|
||||
@@ -48,9 +48,9 @@ class Employee(models.Model):
|
||||
for employee in self:
|
||||
employee.employee_cars_count = cars_count.get(employee.id, 0)
|
||||
|
||||
@api.constrains('address_home_id')
|
||||
def _check_address_home_id(self):
|
||||
no_address = self.filtered(lambda r: not r.address_home_id)
|
||||
@api.constrains('work_contact_id')
|
||||
def _check_work_contact_id(self):
|
||||
no_address = self.filtered(lambda r: not r.work_contact_id)
|
||||
car_ids = self.env['fleet.vehicle'].sudo().search([
|
||||
('driver_employee_id', 'in', no_address.ids),
|
||||
])
|
||||
@@ -62,16 +62,16 @@ class Employee(models.Model):
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
#Update car partner when it is changed on the employee
|
||||
if 'address_home_id' in vals:
|
||||
if 'work_contact_id' in vals:
|
||||
car_ids = self.env['fleet.vehicle'].sudo().search([
|
||||
('driver_employee_id', 'in', self.ids),
|
||||
('driver_id', 'in', self.mapped('address_home_id').ids),
|
||||
('driver_id', 'in', self.mapped('work_contact_id').ids),
|
||||
])
|
||||
if car_ids:
|
||||
car_ids.write({'driver_id': vals['address_home_id']})
|
||||
car_ids.write({'driver_id': vals['work_contact_id']})
|
||||
if 'mobility_card' in vals:
|
||||
#NOTE: keeping it as a search on driver_id but we might be able to use driver_employee_id in the future
|
||||
vehicles = self.env['fleet.vehicle'].search([('driver_id', 'in', (self.user_id.partner_id | self.sudo().address_home_id).ids)])
|
||||
vehicles = self.env['fleet.vehicle'].search([('driver_id', 'in', (self.user_id.partner_id | self.sudo().work_contact_id).ids)])
|
||||
vehicles._compute_mobility_card()
|
||||
return res
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class FleetVehicle(models.Model):
|
||||
for vehicle in self:
|
||||
if vehicle.driver_id:
|
||||
vehicle.driver_employee_id = self.env['hr.employee'].search([
|
||||
('address_home_id', '=', vehicle.driver_id.id),
|
||||
('work_contact_id', '=', vehicle.driver_id.id),
|
||||
], limit=1)
|
||||
else:
|
||||
vehicle.driver_employee_id = False
|
||||
@@ -37,7 +37,7 @@ class FleetVehicle(models.Model):
|
||||
for vehicle in self:
|
||||
if vehicle.future_driver_id:
|
||||
vehicle.future_driver_employee_id = self.env['hr.employee'].search([
|
||||
('address_home_id', '=', vehicle.future_driver_id.id),
|
||||
('work_contact_id', '=', vehicle.future_driver_id.id),
|
||||
], limit=1)
|
||||
else:
|
||||
vehicle.future_driver_employee_id = False
|
||||
@@ -47,7 +47,7 @@ class FleetVehicle(models.Model):
|
||||
for vehicle in self:
|
||||
employee = self.env['hr.employee']
|
||||
if vehicle.driver_id:
|
||||
employee = employee.search([('address_home_id', '=', vehicle.driver_id.id)], limit=1)
|
||||
employee = employee.search([('work_contact_id', '=', vehicle.driver_id.id)], limit=1)
|
||||
if not employee:
|
||||
employee = employee.search([('user_id.partner_id', '=', vehicle.driver_id.id)], limit=1)
|
||||
vehicle.mobility_card = employee.mobility_card
|
||||
@@ -57,7 +57,7 @@ class FleetVehicle(models.Model):
|
||||
partner = False
|
||||
if vals['driver_employee_id']:
|
||||
employee = self.env['hr.employee'].sudo().browse(vals['driver_employee_id'])
|
||||
partner = employee.address_home_id.id
|
||||
partner = employee.work_contact_id.id
|
||||
vals['driver_id'] = partner
|
||||
elif 'driver_id' in vals:
|
||||
# Reverse the process if we can find a single employee
|
||||
@@ -65,7 +65,7 @@ class FleetVehicle(models.Model):
|
||||
if vals['driver_id']:
|
||||
# Limit to 2, we only care about the first one if he is the only one
|
||||
employee_ids = self.env['hr.employee'].sudo().search([
|
||||
('address_home_id', '=', vals['driver_id'])
|
||||
('work_contact_id', '=', vals['driver_id'])
|
||||
], limit=2)
|
||||
if len(employee_ids) == 1:
|
||||
employee = employee_ids[0].id
|
||||
@@ -76,7 +76,7 @@ class FleetVehicle(models.Model):
|
||||
partner = False
|
||||
if vals['future_driver_employee_id']:
|
||||
employee = self.env['hr.employee'].sudo().browse(vals['future_driver_employee_id'])
|
||||
partner = employee.address_home_id.id
|
||||
partner = employee.work_contact_id.id
|
||||
vals['future_driver_id'] = partner
|
||||
elif 'future_driver_id' in vals:
|
||||
# Reverse the process if we can find a single employee
|
||||
@@ -84,7 +84,7 @@ class FleetVehicle(models.Model):
|
||||
if vals['future_driver_id']:
|
||||
# Limit to 2, we only care about the first one if he is the only one
|
||||
employee_ids = self.env['hr.employee'].sudo().search([
|
||||
('address_home_id', '=', vals['future_driver_id'])
|
||||
('work_contact_id', '=', vals['future_driver_id'])
|
||||
], limit=2)
|
||||
if len(employee_ids) == 1:
|
||||
employee = employee_ids[0].id
|
||||
|
||||
@@ -12,10 +12,10 @@ class FleetVehicleAssignationLog(models.Model):
|
||||
|
||||
@api.depends('driver_id')
|
||||
def _compute_driver_employee_id(self):
|
||||
employees = self.env['hr.employee'].search([('address_home_id', 'in', self.driver_id.ids)])
|
||||
employees = self.env['hr.employee'].search([('work_contact_id', 'in', self.driver_id.ids)])
|
||||
|
||||
for log in self:
|
||||
employee = employees.filtered(lambda e: e.address_home_id.id == log.driver_id.id)
|
||||
employee = employees.filtered(lambda e: e.work_contact_id.id == log.driver_id.id)
|
||||
log.driver_employee_id = employee and employee[0] or False
|
||||
|
||||
def _compute_attachment_number(self):
|
||||
|
||||
@@ -16,7 +16,7 @@ class FleetVehicleLogServices(models.Model):
|
||||
internals = self.filtered(lambda r: r.purchaser_employee_id)
|
||||
super(FleetVehicleLogServices, (self - internals))._compute_purchaser_id()
|
||||
for service in internals:
|
||||
service.purchaser_id = service.purchaser_employee_id.address_home_id
|
||||
service.purchaser_id = service.purchaser_employee_id.work_contact_id
|
||||
|
||||
@api.depends('vehicle_id')
|
||||
def _compute_purchaser_employee_id(self):
|
||||
|
||||
@@ -18,7 +18,7 @@ class HrDepartureWizard(models.TransientModel):
|
||||
"""Find all fleet.vehichle.assignation.log records that link to the employee, if there is no
|
||||
end date or end date > departure date, update the date. Also check fleet.vehicle to see if
|
||||
there is any record with its dirver_id to be the employee, set them to False."""
|
||||
drivers = self.employee_id.user_id.partner_id | self.employee_id.sudo().address_home_id
|
||||
drivers = self.employee_id.user_id.partner_id | self.employee_id.sudo().work_contact_id
|
||||
assignations = self.env['fleet.vehicle.assignation.log'].search([('driver_id', 'in', drivers.ids)])
|
||||
for assignation in assignations:
|
||||
if self.departure_date and (not assignation.date_end or assignation.date_end > self.departure_date):
|
||||
|
||||
@@ -1587,7 +1587,7 @@ class HolidaysRequest(models.Model):
|
||||
if leave.user_id:
|
||||
recipient = leave.user_id.partner_id.id
|
||||
elif leave.employee_id:
|
||||
recipient = leave.employee_id.address_home_id.id
|
||||
recipient = leave.employee_id.work_contact_id.id
|
||||
|
||||
if recipient:
|
||||
self.env['mail.thread'].sudo().message_notify(
|
||||
|
||||
@@ -586,11 +586,20 @@ class Applicant(models.Model):
|
||||
def _get_employee_create_vals(self):
|
||||
self.ensure_one()
|
||||
address_id = self.partner_id.address_get(['contact'])['contact']
|
||||
address_sudo = self.env['res.partner'].sudo().browse(address_id)
|
||||
return {
|
||||
'name': self.partner_name or self.partner_id.display_name,
|
||||
'job_id': self.job_id.id,
|
||||
'job_title': self.job_id.name,
|
||||
'address_home_id': address_id,
|
||||
'private_street': address_sudo.street,
|
||||
'private_street2': address_sudo.street2,
|
||||
'private_city': address_sudo.city,
|
||||
'private_state_id': address_sudo.state_id,
|
||||
'private_zip': address_sudo.zip,
|
||||
'private_country_id': address_sudo.country_id,
|
||||
'private_phone': address_sudo.phone,
|
||||
'private_email': address_sudo.email,
|
||||
'lang': address_sudo.lang,
|
||||
'department_id': self.department_id.id,
|
||||
'address_id': self.company_id.partner_id.id,
|
||||
'work_email': self.department_id.company_id.email or self.email_from, # To have a valid email address by default
|
||||
|
||||
Reference in New Issue
Block a user