A custom Frappe / ERPNext app for California Burrito's maintenance operations. It manages outlets, assets, preventive-maintenance (PM) programs, reactive tickets, and work orders.
| Item | Value |
|---|---|
| Cloud URL | https://maintainance.m.frappe.cloud |
| deepikasinghns1@gmail.com | |
| Password | Cbassesment@2026 |
| GitHub Repo | https://github.com/dhruvk2002/maintenance_ops |
- Frappe v15 + ERPNext v15
- Custom app:
maintenance_opsv0.0.1 - MariaDB 12.3 (local) / Frappe Cloud managed DB
- Python 3.11
maintenance_ops/
├── maintenance_ops/ # Python package
│ ├── doctype/ # 12 custom DocTypes
│ │ ├── asset/
│ │ ├── asset_category/
│ │ ├── city/
│ │ ├── exception_record/
│ │ ├── maintenance_program/
│ │ ├── maintenance_program_task/
│ │ ├── maintenance_team_member/
│ │ ├── maintenance_ticket/
│ │ ├── maintenance_work_order/
│ │ ├── outlet/
│ │ ├── work_order_checklist_result/
│ │ └── zonal_office/
│ ├── report/ # 2 custom Reports
│ │ ├── due_overdue_work_orders/
│ │ └── ticket_aging_summary/
│ ├── bootstrap.py # Seed data from datasets
│ ├── services.py # PM generation + escalation logic
│ ├── events.py # Doc event hooks
│ ├── routing.py # Team assignment logic
│ ├── scheduling.py # PM due-date scheduling
│ └── hooks.py
- Python 3.11, Node 18, MariaDB (running on port 3307 with socket
/tmp/mariadb3307.sock) - Frappe Bench installed
cd frappe-bench/apps
git clone https://github.com/dhruvk2002/maintenance_opsbench new-site maintenanceops.localhost \
--db-port 3307 \
--db-root-username <mariadb_user> \
--mariadb-root-password <mariadb_password>bench get-app erpnext --branch version-15
bench --site maintenanceops.localhost install-app erpnext
bench --site maintenanceops.localhost install-app maintenance_ops
bench --site maintenanceops.localhost migratebench --site maintenanceops.localhost consoleInside the console:
from maintenance_ops.bootstrap import seed_from_datasets
seed_from_datasets("/path/to/datasets")
# Expected output:
# cities=5, zonal_offices=?, outlets=133, asset_categories=19,
# assets=142, maintenance_programs=35, team_members=41, exceptions=18bench startOpen http://maintenanceops.localhost:8000 and log in as Administrator.
Open https://assesment.m.frappe.cloud and log in with the credentials from the table above.
- Go to Maintenance Ops > Masters > Outlet → expect 133 records
- Go to Maintenance Ops > Masters > Asset → expect 142 records
- Go to Maintenance Ops > Masters > Maintenance Program → expect 35 records
- Go to Maintenance Ops > Masters > Maintenance Team Member → expect 41 records
- Go to Maintenance Ops > Masters > City → expect 5 records
- Go to Maintenance Ops > Transactions > Maintenance Ticket
- Click New
- Fill in:
- Outlet: pick any outlet (e.g.
CB-001) - Asset: pick any asset linked to that outlet
- Description:
AC unit not cooling - Reported By: any name
- Outlet: pick any outlet (e.g.
- Click Save
- Expected: A Maintenance Work Order is automatically created (type =
Reactive) and linked to the ticket. Check the linked Work Order field on the ticket form.
- Go to Maintenance Ops > Transactions > Maintenance Work Order
- Note the current count
- Open bench console (local) or use the Frappe API endpoint:
bench --site maintenanceops.localhost consolefrom maintenance_ops.services import generate_due_pm_work_orders
result = generate_due_pm_work_orders()
print(result)- Refresh the Work Order list → new Preventive type work orders should appear for programs that are due today.
- Open any Maintenance Work Order
- Walk through status transitions:
Draft→ Submit →Open- Open → set Assigned To (team member) → Start →
In Progress - In Progress → fill Completion Notes → Complete →
Completed
- Expected: Status field updates correctly at each step;
completed_ondate is set when completed.
- Open bench console (local):
from maintenance_ops.services import escalate_overdue_work_orders
result = escalate_overdue_work_orders()
print(result) # returns count of work orders escalated- Any Work Order with
due_date < todayand statusOpenorIn Progressshould have its priority bumped toHigh(orCriticalif alreadyHigh).
- Go to Maintenance Ops > Reports > Due Overdue Work Orders
- Apply filters (optional: filter by outlet or date range)
- Expected: Table showing work orders with columns — Outlet, Asset, Type, Due Date, Status, Days Overdue, Priority
- Go to Maintenance Ops > Reports > Ticket Aging Summary
- Expected: Grouped summary of tickets by age bucket (e.g. 0–7 days, 8–15 days, 15+ days), showing open vs closed counts.
- Go to Maintenance Ops > Masters > Exception Record
- Expected: ~18 records representing rows from the source dataset that could not be cleanly mapped (duplicate assets, missing outlets, etc.)
- Each record has a reason field explaining why it was flagged.
| Event | Function | What it does |
|---|---|---|
| Daily | services.generate_due_pm_work_orders |
Creates PM work orders for programs due today |
| Daily | services.escalate_overdue_work_orders |
Escalates priority on overdue open work orders |
| Rule | Implementation |
|---|---|
| Reactive ticket → auto work order | events.on_ticket_after_insert |
| Work order priority from asset category | api.default_priority_for_asset_category |
| PM due date from last completion + frequency | api.pm_due_date |
| Team member routing by outlet/zone | routing.py |
| City code normalisation (aliases) | config.CITY_ALIASES |
| DocType | Type | Purpose |
|---|---|---|
| City | Master | City master |
| Zonal Office | Master | Zone grouping for outlets |
| Outlet | Master | Individual restaurant/outlet |
| Asset Category | Master | Category of equipment |
| Asset | Master | Individual piece of equipment |
| Maintenance Team Member | Master | Technician/engineer |
| Maintenance Program | Master | PM schedule (asset × frequency) |
| Maintenance Program Task | Child | Task checklist for a program |
| Maintenance Ticket | Transaction | Reactive fault report |
| Maintenance Work Order | Transaction | Planned or reactive work item |
| Work Order Checklist Result | Child | Checklist completion per work order |
| Exception Record | Log | Bad/unmappable rows from seed data |