Job Card System in ERPNext Manufacturing: How to Track Production Time
The Job Card system in manufacturing is a document-based workflow that tracks individual production operations against Work Orders, capturing granular employee time logs while enforcing workstation capacity constraints to prevent scheduling conflicts.
The Job Card serves as the operational backbone of ERPNext's manufacturing module, bridging Work Orders, Bill of Materials (BOM), and shop floor resources. As implemented in the frappe/erpnext repository, this system enables discrete manufacturing environments to monitor production time, material transfers, and employee productivity through a structured status lifecycle defined in erpnext/manufacturing/doctype/job_card/job_card.py.
What Is a Job Card in ERPNext?
A Job Card represents a single operation required to fulfill a Work Order. It links the Work Order, BOM, specific Workstation, assigned employees, and the time logs that record exactly how long each step required. Each card moves through a defined status lifecycle managed by the status field:
- Open: Created but not started
- Work In Progress: Materials transferred and time logging active
- Material Transferred: All required raw materials moved to the Work-In-Progress (WIP) warehouse
- On Hold: Paused by the user via the
is_pausedflag - Completed: Production quantity matches the
for_quantityfield (including process loss) - Cancelled: Discarded via
on_discard
The class definition resides in erpnext/manufacturing/doctype/job_card/job_card.py, which declares critical fields including operation, workstation, time_logs, and status.
How Production Time Tracking Works
The Time Log Data Structure
Production time is stored in a child table called Job Card Time Log (time_logs). The schema lives in erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.py and tracks:
from_timeandto_time: Start and end timestampsemployee: The worker assignedtime_in_mins: Calculated durationcompleted_qty: Units produced during this log entry
Recording Time via API Methods
Operators log time through the add_time_log method or the whitelisted make_time_log endpoint. These functions:
- Create a new row in the
time_logstable or update an existing entry - Calculate duration using
time_diff_in_minutes - Trigger
validate_time_logsto ensure chronological integrity (From time must precede To time) and check for overlapping entries
Aggregation and Validation
After each log entry, the system runs validate_time_logs(save=True) to aggregate total_time_in_mins and store it on the parent Job Card. The method set_expected_and_actual_time identifies the earliest from_time and latest to_time across all logs, populating the actual_start_date and actual_end_date fields while computing total required minutes for the operation.
Workstation Capacity and Overlap Prevention
ERPNext prevents double-booking of workstations through capacity validation logic in job_card.py. The get_overlap_for function gathers all existing logs that intersect with a proposed new time window. The has_overlap method then evaluates the workstation's production capacity (default value of 1) and raises OverlapError if the simultaneous usage would exceed this limit.
This ensures that two employees cannot be assigned to the same workstation at the same time unless the capacity setting explicitly allows it.
Pausing and Resuming Production
The system supports interrupted workflows through two whitelisted methods exposed to the UI:
pause_job: Setsis_paused = 1and creates a zero-quantity log ending at the pause momentresume_job: Clears the pause flag and generates a new log starting when work resumes
These methods allow accurate tracking of active production time versus idle time.
Integration with Work Orders and Stock
When a Job Card is submitted (on_submit), the system:
- Validates required quality inspections
- Updates the linked Work Order via
update_work_order - Records material transfers through
set_transferred_qty - Creates semi-finished goods movements via
make_stock_entry_for_semi_fg_item, which generates a Manufacture Stock Entry to move items forward after completion
Production Reporting and Analytics
Aggregated metrics are exposed through the Job Card Summary report located at erpnext/manufacturing/report/job_card_summary/job_card_summary.py. This report pulls total_time_in_mins, total_completed_qty, and related fields to provide production efficiency metrics across operations.
Practical Implementation Examples
Creating a Job Card from a Work Order
import frappe
# Assume a Work Order already exists
wo_name = "WO‑0001"
# Create a new Job Card for the first operation
job_card = frappe.get_doc({
"doctype": "Job Card",
"work_order": wo_name,
"operation": "Cutting",
"for_quantity": 100,
"company": "My Company",
"workstation_type": "Cutting Station"
})
job_card.insert()
job_card.submit()
print("Created Job Card:", job_card.name)
Starting a Timer for an Employee
frappe.call({
method: "erpnext.manufacturing.doctype.job_card.job_card.start_timer",
args: {
job_card_id: "JC‑00001",
start_time: frappe.datetime.now_datetime(),
employees: [{ employee: "EMP‑001" }]
},
callback: function(r) {
frappe.msgprint("Timer started for employee.");
}
});
Completing a Job Card via REST API
curl -X POST https://erp.mycompany.com/api/method/erpnext.manufacturing.doctype.job_card.job_card.complete_job_card \
-d "job_card_id=JC-00001" \
-d "end_time=2026-05-20 15:30:00" \
-d "qty=100" \
-d "auto_submit=1"
Querying Production Time Server-Side
jc = frappe.get_doc("Job Card", "JC-00001")
print("Total minutes spent:", jc.total_time_in_mins)
print("Started at:", jc.actual_start_date, "Ended at:", jc.actual_end_date)
Summary
- The Job Card is the discrete operational unit in ERPNext manufacturing, linking Work Orders to specific workstations and employees
- Production time is captured in the
Job Card Time Logchild table with automatic aggregation intototal_time_in_mins - Workstation capacity validation prevents scheduling conflicts through
get_overlap_forandhas_overlap - Pause and resume functionality allows accurate tracking of productive versus non-productive time
- Completion triggers stock entries and Work Order updates via
make_stock_entry_for_semi_fg_itemandupdate_work_order
Frequently Asked Questions
What is the difference between a Work Order and a Job Card in ERPNext?
A Work Order represents the entire production request for a finished good, while a Job Card represents a single operation within that routing. One Work Order can generate multiple Job Cards (one per operation), each tracking specific employees, workstations, and time logs for that discrete step.
How does ERPNext prevent two employees from logging time on the same workstation simultaneously?
The system checks workstation capacity using has_overlap in job_card.py. If the number of concurrent time logs exceeds the workstation's capacity (default 1), the system raises an OverlapError. This enforces sequential or capacity-planned usage of constrained resources.
Can a Job Card be paused mid-operation, and how does that affect time tracking?
Yes. Calling the whitelisted pause_job method sets is_paused = 1 and closes the current time log at the pause timestamp. When resume_job is invoked, a new log begins. This creates a clean separation between productive time and idle time, ensuring accurate efficiency reporting without distorting the total operation duration.
Where can managers view aggregated production time across multiple Job Cards?
Navigate to Manufacturing > Reports > Job Card Summary, which executes the report defined in erpnext/manufacturing/report/job_card_summary/job_card_summary.py. This report aggregates total_time_in_mins, total_completed_qty, and actual versus expected times across filtered Job Cards for shop floor analysis.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →