Repo comfac-hrms CommonEdits
Repo:comfac-hrms/CommonEdits — Common Edit Scenarios
This page contains practical recipes for common customization tasks.
Scenario 1: Adding a New Field to a Form
Goal
Add "Emergency Contact Phone" field to the Employee form.
Files to Touch
hrms/setup.pyOR Frappe Desk UI- (Optional)
hrms/overrides/employee_master.pyfor validation
Method A: Via Frappe Desk (Quickest)
- Log in as Administrator
- Go to Employee list
- Click Menu → Customize
- In "Customize Form", scroll to bottom
- Click Add Row:
- Label: Emergency Contact Phone
- Fieldtype: Data
- Options: Phone
- Insert After: emergency_contact_name
- Click Update
Method B: Via Code (Reproducible)
Create hrms/setup.py if not exists:
```python import frappe
def setup_custom_fields():
custom_fields = {
"Employee": [
{
"fieldname": "custom_emergency_phone",
"label": "Emergency Contact Phone",
"fieldtype": "Data",
"options": "Phone",
"insert_after": "emergency_contact_name",
"translatable": 0
}
]
}
for doctype, fields in custom_fields.items():
for field in fields:
if not frappe.db.exists("Custom Field", f"{doctype}-{field['fieldname']}"):
frappe.get_doc({
"doctype": "Custom Field",
"dt": doctype,
**field
}).insert()
frappe.db.commit()
```
Add to hooks.py:
```python after_install = "hrms.setup.setup_custom_fields" ```
How to Verify
- Go to Employee form
- Check if new field appears after "Emergency Contact Name"
- Create test employee, fill in emergency phone
- Verify it saves and appears in list view if configured
---
Scenario 2: Changing Validation Logic
Goal
Require manager approval for leave applications longer than 7 days.
Files to Touch
hrms/hr/doctype/leave_application/leave_application.py
What to Change
Find the validate() method or add to it:
```python def validate(self):
# ... existing validation code ...
# Custom validation
if self.total_leave_days > 7 and not self.leave_approver:
frappe.throw(_(
"Leave applications longer than 7 days require a leave approver."
))
```
How to Verify
- Create leave application for 10 days
- Try to submit without selecting approver
- Should get error message
- Select approver, submit should work
---
Scenario 3: Adding a New Report
Goal
Create a report showing employees with negative leave balances.
Files to Touch
hrms/hr/report/negative_leave_balance/(new directory)hrms/hr/report/negative_leave_balance/negative_leave_balance.jsonhrms/hr/report/negative_leave_balance/negative_leave_balance.py
What to Create
negative_leave_balance.json:
```json {
"add_total_row": 0,
"columns": [],
"creation": "2024-01-01 00:00:00.000000",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"modified": "2024-01-01 00:00:00.000000",
"modified_by": "Administrator",
"module": "HR",
"name": "Negative Leave Balance",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Leave Ledger Entry",
"report_name": "Negative Leave Balance",
"report_type": "Script Report",
"roles": [
{"role": "HR Manager"},
{"role": "HR User"}
]
} ```
negative_leave_balance.py:
```python import frappe from frappe import _
def execute(filters=None):
columns = [
{"label": _("Employee"), "fieldname": "employee", "fieldtype": "Link", "options": "Employee", "width": 150},
{"label": _("Employee Name"), "fieldname": "employee_name", "fieldtype": "Data", "width": 200},
{"label": _("Leave Type"), "fieldname": "leave_type", "fieldtype": "Link", "options": "Leave Type", "width": 150},
{"label": _("Balance"), "fieldname": "balance", "fieldtype": "Float", "width": 120},
]
data = frappe.db.sql("""
SELECT
employee,
(SELECT employee_name FROM tabEmployee e WHERE e.name = lle.employee) as employee_name,
leave_type,
SUM(leaves) as balance
FROM `tabLeave Ledger Entry` lle
GROUP BY employee, leave_type
HAVING balance < 0
ORDER BY balance ASC
""", as_dict=True)
return columns, data
```
How to Verify
- Run
bench migrate - Go to HR module → Reports
- Look for "Negative Leave Balance"
- Run report, verify data
---
Scenario 4: Modifying a Print Format
Goal
Add company logo to Salary Slip print format.
Files to Touch
- Frappe Desk UI (Print Format Builder)
What to Change
- Go to Payroll → Salary Slip
- Open any salary slip
- Click Print → Customize
- In Print Format Builder:
- Drag "Image" field to header
- Set image source to
Template:Frappe.db.get value("Company", doc.company, "company logo") - Adjust size and position
- Save as new print format or update standard
Alternative: Raw HTML
Edit print format HTML:
```html
<img src="Template:Frappe.db.get value('Company', doc.company, 'company logo')" style="max-height: 60px;">
Salary Slip
```
How to Verify
- Open any salary slip
- Click Print
- Verify logo appears in preview
- Check PDF export
---
Scenario 5: Adding a New DocType
Goal
Create "Employee Training Record" DocType to track completed trainings.
Files to Touch
hrms/hr/doctype/employee_training_record/(new directory)hrms/hr/doctype/employee_training_record/employee_training_record.jsonhrms/hr/doctype/employee_training_record/employee_training_record.py
What to Create
Option A: Via Frappe Desk (Recommended)
- Go to DocType List (search in awesome bar)
- Click New
- Fill:
- Name: Employee Training Record
- Module: HR
- Fields:
- Employee (Link → Employee)
- Training Name (Data)
- Training Date (Date)
- Trainer (Data)
- Certificate (Attach)
- Status (Select: Completed/In Progress/Planned)
- Save, then
bench export-fixturesOR manually create files
Option B: Manual JSON
Create employee_training_record.json:
```json {
"actions": [],
"autoname": "format:TRN-{YYYY}-{#####}",
"creation": "2024-01-01 00:00:00.000000",
"doctype": "DocType",
"engine": "InnoDB",
"fields": [
{
"fieldname": "employee",
"fieldtype": "Link",
"label": "Employee",
"options": "Employee",
"reqd": 1
},
{
"fieldname": "training_name",
"fieldtype": "Data",
"label": "Training Name",
"reqd": 1
},
{
"fieldname": "training_date",
"fieldtype": "Date",
"label": "Training Date"
},
{
"fieldname": "trainer",
"fieldtype": "Data",
"label": "Trainer"
},
{
"fieldname": "certificate",
"fieldtype": "Attach",
"label": "Certificate"
},
{
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "Planned\nIn Progress\nCompleted"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-01-01 00:00:00.000000",
"module": "HR",
"name": "Employee Training Record",
"naming_rule": "Expression",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "HR Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 0,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "HR User",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
} ```
Create employee_training_record.py:
```python import frappe from frappe.model.document import Document
class EmployeeTrainingRecord(Document):
def validate(self):
# Custom validation
if self.status == "Completed" and not self.certificate:
frappe.msgprint(_("Warning: No certificate attached for completed training."))
```
How to Verify
- Run
bench migrate - Go to HR module
- Search for "Employee Training Record"
- Create test record
- Verify validations work
---
Scenario 6: Changing a Workflow
Goal
Add "Pending HR Review" step to Leave Application workflow.
Files to Touch
- Frappe Desk → Workflow List
What to Change
- Go to Workflow list
- Open Leave Application
- Add new state:
- State: Pending HR Review
- Update Field: Status
- Update Value: Pending HR Review
- Add new transitions:
- From: Open → To: Pending HR Review, Action: Send to HR, Condition: doc.total_leave_days > 5
- From: Pending HR Review → To: Approved, Action: HR Approve
- From: Pending HR Review → To: Rejected, Action: HR Reject
- Save
How to Verify
- Create leave application > 5 days
- Submit, should go to "Pending HR Review"
- Verify HR Manager can approve/reject
- Check that shorter leaves skip this step
---
Scenario 7: Adding a Server Script
Goal
Auto-calculate leave balance when leave application is created.
Files to Touch
hrms/hr/doctype/leave_application/leave_application.py
What to Change
Add to LeaveApplication class:
```python def before_insert(self):
"""Auto-calculate leave balance before saving"""
if self.employee and self.leave_type:
balance = get_leave_balance(self.employee, self.leave_type, self.from_date)
self.leave_balance = balance
def get_leave_balance(employee, leave_type, date):
"""Helper function to calculate balance"""
result = frappe.db.sql("""
SELECT SUM(leaves) as balance
FROM `tabLeave Ledger Entry`
WHERE employee = %s AND leave_type = %s AND transaction_date <= %s
""", (employee, leave_type, date), as_dict=True)
return result[0].balance or 0
```
How to Verify
- Create new leave application
- Select employee and leave type
- Leave Balance field should auto-populate
---
Scenario 8: Connecting to Another App
Goal
Link Employee to comfac-webshop Customer account.
Files to Touch
- Custom field in Employee (via desk or code)
- (Optional)
hrms/overrides/employee_master.py
What to Change
Add custom field to Employee:
- Fieldname:
webshop_customer - Label: Webshop Customer Account
- Fieldtype: Link
- Options: Customer (from ERPNext)
Add to hrms/overrides/employee_master.py:
```python def after_insert(self):
"""Create webshop customer for new employees"""
if not self.webshop_customer:
customer = frappe.get_doc({
"doctype": "Customer",
"customer_name": self.employee_name,
"customer_type": "Individual",
"customer_group": "Employee",
"territory": "Philippines"
})
customer.insert(ignore_permissions=True)
# Link back to employee
self.db_set("webshop_customer", customer.name)
```
Add to hooks.py:
```python doc_events = {
"Employee": {
"after_insert": "hrms.overrides.employee_master.after_insert"
}
} ```
How to Verify
- Create new employee
- Check if Customer is auto-created
- Verify link appears in Employee form
- Check customer appears in ERPNext Sales module
Related Pages
- Repo_comfac-hrms_Overview — Project overview
- Repo_comfac-hrms_DirectoryMap — Directory structure
- Repo_comfac-hrms_EntryPoints — How app starts, config files
- Repo_comfac-hrms_DataModel — DocTypes and data structures
- Repo_comfac-hrms_ExtensionPoints — Hooks and customization