feat(employee): Create User button and form.

(cherry picked from commit 3b521b74ea)
This commit is contained in:
Krishna Shirsath
2026-02-17 13:14:31 +05:30
committed by Mergify
parent cd1dfeeab3
commit cd0a25ca17
3 changed files with 182 additions and 33 deletions

View File

@@ -45,6 +45,54 @@ frappe.ui.form.on("Employee", {
refresh: function (frm) {
frm.fields_dict.date_of_birth.datepicker.update({ maxDate: new Date() });
if (!frm.is_new() && !frm.doc.user_id) {
frm.add_custom_button(__("Create User"), () => {
const dialog = new frappe.ui.Dialog({
title: __("Create User"),
fields: [
{
fieldtype: "Data",
fieldname: "email",
label: __("Email"),
reqd: 1,
default: frm.doc.company_email || frm.doc.personal_email || frm.doc.user_id,
},
{
fieldtype: "Check",
fieldname: "create_user_permission",
label: __("Create User Permission"),
default: 0,
},
],
primary_action_label: __("Create"),
primary_action: (values) => {
if (!values.email) {
frappe.msgprint(__("Email is required to create a user."));
return;
}
frappe
.call({
method: "erpnext.setup.doctype.employee.employee.create_user",
args: {
employee: frm.doc.name,
email: values.email,
create_user_permission: values.create_user_permission ? 1 : 0,
},
freeze: true,
freeze_message: __("Creating User..."),
})
.then(() => {
dialog.hide();
frm.reload_doc();
});
},
});
dialog.show();
});
}
},
prefered_contact_email: function (frm) {
@@ -77,24 +125,6 @@ frappe.ui.form.on("Employee", {
},
});
},
create_user: function (frm) {
if (!frm.doc.prefered_email) {
frappe.throw(__("Please enter Preferred Contact Email"));
}
frappe.call({
method: "erpnext.setup.doctype.employee.employee.create_user",
args: {
employee: frm.doc.name,
email: frm.doc.prefered_email,
},
freeze: true,
freeze_message: __("Creating User..."),
callback: function (r) {
frm.reload_doc();
},
});
},
});
cur_frm.cscript = new erpnext.setup.EmployeeController({

View File

@@ -28,7 +28,6 @@
"status",
"erpnext_user",
"user_id",
"create_user",
"create_user_permission",
"company_details_section",
"company",
@@ -285,12 +284,6 @@
"label": "User ID",
"options": "User"
},
{
"depends_on": "eval:(!doc.user_id)",
"fieldname": "create_user",
"fieldtype": "Button",
"label": "Create User"
},
{
"default": "1",
"depends_on": "user_id",
@@ -823,7 +816,7 @@
"image_field": "image",
"is_tree": 1,
"links": [],
"modified": "2025-08-29 11:52:12.819878",
"modified": "2026-02-16 13:06:01.752904",
"modified_by": "Administrator",
"module": "Setup",
"name": "Employee",

View File

@@ -8,7 +8,7 @@ from frappe.permissions import (
get_doc_permissions,
remove_user_permission,
)
from frappe.utils import cstr, getdate, today, validate_email_address
from frappe.utils import cint, cstr, getdate, today, validate_email_address
from frappe.utils.nestedset import NestedSet
from erpnext.utilities.transaction_base import delete_events
@@ -23,6 +23,93 @@ class InactiveEmployeeStatusError(frappe.ValidationError):
class Employee(NestedSet):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.setup.doctype.employee_education.employee_education import EmployeeEducation
from erpnext.setup.doctype.employee_external_work_history.employee_external_work_history import (
EmployeeExternalWorkHistory,
)
from erpnext.setup.doctype.employee_internal_work_history.employee_internal_work_history import (
EmployeeInternalWorkHistory,
)
attendance_device_id: DF.Data | None
bank_ac_no: DF.Data | None
bank_name: DF.Data | None
bio: DF.TextEditor | None
blood_group: DF.Literal["", "A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"]
branch: DF.Link | None
cell_number: DF.Data | None
company: DF.Link
company_email: DF.Data | None
contract_end_date: DF.Date | None
create_user_permission: DF.Check
ctc: DF.Currency
current_accommodation_type: DF.Literal["", "Rented", "Owned"]
current_address: DF.SmallText | None
date_of_birth: DF.Date
date_of_issue: DF.Date | None
date_of_joining: DF.Date
date_of_retirement: DF.Date | None
department: DF.Link | None
designation: DF.Link | None
education: DF.Table[EmployeeEducation]
emergency_phone_number: DF.Data | None
employee: DF.Data | None
employee_name: DF.Data | None
employee_number: DF.Data | None
encashment_date: DF.Date | None
external_work_history: DF.Table[EmployeeExternalWorkHistory]
family_background: DF.SmallText | None
feedback: DF.SmallText | None
final_confirmation_date: DF.Date | None
first_name: DF.Data
gender: DF.Link
health_details: DF.SmallText | None
held_on: DF.Date | None
holiday_list: DF.Link | None
iban: DF.Data | None
image: DF.AttachImage | None
internal_work_history: DF.Table[EmployeeInternalWorkHistory]
last_name: DF.Data | None
leave_encashed: DF.Literal["", "Yes", "No"]
lft: DF.Int
marital_status: DF.Literal["", "Single", "Married", "Divorced", "Widowed"]
middle_name: DF.Data | None
naming_series: DF.Literal["HR-EMP-"]
new_workplace: DF.Data | None
notice_number_of_days: DF.Int
old_parent: DF.Data | None
passport_number: DF.Data | None
permanent_accommodation_type: DF.Literal["", "Rented", "Owned"]
permanent_address: DF.SmallText | None
person_to_be_contacted: DF.Data | None
personal_email: DF.Data | None
place_of_issue: DF.Data | None
prefered_contact_email: DF.Literal["", "Company Email", "Personal Email", "User ID"]
prefered_email: DF.Data | None
reason_for_leaving: DF.SmallText | None
relation: DF.Data | None
relieving_date: DF.Date | None
reports_to: DF.Link | None
resignation_letter_date: DF.Date | None
rgt: DF.Int
salary_currency: DF.Link | None
salary_mode: DF.Literal["", "Bank", "Cash", "Cheque"]
salutation: DF.Link | None
scheduled_confirmation_date: DF.Date | None
status: DF.Literal["Active", "Inactive", "Suspended", "Left"]
unsubscribed: DF.Check
user_id: DF.Link | None
valid_upto: DF.Date | None
# end: auto-generated types
nsm_parent_field = "reports_to"
def autoname(self):
@@ -310,9 +397,28 @@ def deactivate_sales_person(status=None, employee=None):
@frappe.whitelist()
def create_user(employee, user=None, email=None):
def create_user(employee, user=None, email=None, create_user_permission=0):
if not employee:
frappe.throw(_("Employee is required"))
emp = frappe.get_doc("Employee", employee)
if email:
email = cstr(email).strip().lower()
else:
email = emp.prefered_email
if not email:
frappe.throw(_("Email is required to create a user"))
validate_email_address(email, True)
if emp.user_id:
frappe.throw(_("Employee {0} already has a linked user").format(emp.name))
if frappe.db.exists("User", email):
frappe.throw(_("User {0} already exists").format(email))
employee_name = emp.employee_name.split(" ")
middle_name = last_name = ""
@@ -324,14 +430,14 @@ def create_user(employee, user=None, email=None):
first_name = employee_name[0]
if email:
emp.prefered_email = email
frappe.db.set_value("Employee", emp.name, "user_id", email, update_modified=False)
frappe.db.commit()
user = frappe.new_doc("User")
user.update(
{
"name": emp.employee_name,
"email": emp.prefered_email,
"email": email,
"enabled": 1,
"first_name": first_name,
"middle_name": middle_name,
@@ -340,11 +446,31 @@ def create_user(employee, user=None, email=None):
"birth_date": emp.date_of_birth,
"phone": emp.cell_number,
"bio": emp.bio,
"send_welcome_email": 1,
}
)
user.insert()
emp.user_id = user.name
user.append_roles("Employee")
user.insert(ignore_permissions=True)
emp.reload()
emp.company_email = email
if not emp.prefered_contact_email:
emp.prefered_contact_email = "Company Email"
emp.save()
if cint(create_user_permission):
if not frappe.db.exists(
"User Permission",
{"allow": "Employee", "for_value": emp.name, "user": user.name},
):
add_user_permission("Employee", emp.name, user.name)
if not frappe.db.exists(
"User Permission",
{"allow": "Company", "for_value": emp.company, "user": user.name},
):
add_user_permission("Company", emp.company, user.name)
return user.name