Frappe ViewsJavascript

How to Create a Custom Calendar View for a DocType in Frappe/ERPNext

Calendar View

Learn to configure a custom calendar view in Frappe/ERPNext by creating a doctype_calendar.js file and a get_events Python method. Guide covers field mapping and filters.

Frappe Framework provides a powerful, out-of-the-box calendar view that can be configured for any DocType. This feature is ideal for visualizing records that have a start and end date, such as tasks, meetings, appointments, or timesheets.

To enable this view, you need to create a simple JavaScript configuration file that tells the framework how to map your DocType's fields to the calendar's properties. This snippet demonstrates the complete client-side configuration required.

timesheet_calendar.jsjavascript
1frappe.views.calendar["Timesheet"] = { // Doctype Name
2 field_map: {
3 "start": "start_date", //datefield
4 "end": "end_date", // datefield
5 "id": "name",
6 "allDay": "allDay",
7 "child_name": "name",
8 "title": "title"
9 },
10 //optional
11 style_map: {
12 "0": "info",
13 "1": "standard",
14 "2": "danger"
15 },
16 gantt: true,
17 filters: [
18 {
19 "fieldtype": "Link",
20 "fieldname": "project",
21 "options": "Project",
22 "label": __("Project")
23 },
24 {
25 "fieldtype": "Link",
26 "fieldname": "employee",
27 "options": "Employee",
28 "label": __("Employee")
29 }
30 ],
31 // Custom Function created in [docmodule].[doctype].[docname].py file
32 get_events_method: "erpnext.projects.doctype.timesheet.timesheet.get_events"
33}

Understanding This Code

What It Does

This script configures the calendar view for a specified DocType (e.g., 'Timesheet'). It maps DocType fields to calendar event properties like start date, end date, and title, sets up user filters, and specifies the server-side Python method responsible for fetching the event data.

When To Use

Use this script when you need to provide users with a visual, date-based representation of records from a DocType. It's ideal for tracking appointments, project tasks, leave applications, or any time-sensitive data.

Prerequisites

  • A Frappe DocType with at least one Date or Datetime field to serve as the start date.
  • A corresponding server-side Python method to fetch and return event data.

Key Concepts

Important ideas to understand in this code

frappe.views.calendar

A global JavaScript object in the Frappe Framework where developers define custom view configurations. By adding a key with your DocType's name, you instruct the framework on how to render it in a calendar format.

Learn more

field_map

This object is crucial for the calendar view. It maps the standard calendar event properties (like 'start', 'end', 'title') to the actual fieldnames in your DocType, telling the calendar which data to display where.

Learn more

get_events_method

This property specifies the dotted path to the Python function on the server that will be called to fetch the calendar events. This function must be whitelisted and must accept 'start' and 'end' date arguments.

Learn more

filters

An optional array of objects that defines filter fields to be displayed above the calendar. This allows users to narrow down the displayed events based on criteria like a linked DocType.

Learn more

Step-by-Step Tutorial

Follow along to understand how this code works

1

Create the Calendar JavaScript File

In your custom app, navigate to your DocType's folder (e.g., `my_app/my_app/doctype/my_doctype/`). Create a new file named `my_doctype_calendar.js`. This naming convention is essential for Frappe to automatically load the script.

javascript
// File: my_app/my_app/doctype/my_doctype/my_doctype_calendar.js
Next Step
2

Define the Client-Side Configuration

In the new JS file, add the configuration object. Replace 'My DocType' with your DocType's name. Map the `start`, `end`, and `title` fields to the corresponding fieldnames in your DocType. Finally, specify the Python method path that will fetch the data.

javascript
frappe.views.calendar["My DocType"] = {
    field_map: {
        "start": "your_start_date_field",
        "end": "your_end_date_field", // Optional
        "id": "name",
        "title": "your_title_field"
    },
    get_events_method: "my_app.my_app.doctype.my_doctype.my_doctype.get_events"
};
Next Step
3

Create the Server-Side Python Method

Open the `my_doctype.py` file. Create a Python function named `get_events`. This function must be whitelisted using the `@frappe.whitelist()` decorator and must accept `start`, `end`, and optional `filters` as arguments. It should return a list of dictionaries.

python
import frappe
from frappe.utils import get_datetime

@frappe.whitelist()
def get_events(start, end, filters=None):
    # Query your DocType for records between the given dates
    event_docs = frappe.get_all(
        "My DocType",
        fields=["name", "your_title_field", "your_start_date_field", "your_end_date_field"],
        filters=[
            {"your_start_date_field": ["<=", end]},
            {"your_end_date_field": [">=", start]}
        ]
    )

    events = []
    for doc in event_docs:
        events.append({
            "name": doc.name,
            "title": doc.your_title_field,
            "start": get_datetime(doc.your_start_date_field),
            "end": get_datetime(doc.your_end_date_field),
        })
    
    return events
Next Step
4

Build, Migrate, and Test

After saving both files, run `bench build` to bundle your new JavaScript asset and `bench migrate` to apply any server-side changes. Clear your browser cache and navigate to your DocType's list view. You should now see the 'Calendar' view option.

bash
bench build && bench migrate

Common Issues & Solutions

Troubleshoot problems you might encounter