Jump to content

Repo SharedConcepts

From Game in the Brain Wiki

Repo_SharedConcepts — Patterns Across Projects

This page documents patterns and concepts that appear across multiple repositories in the ComFac ecosystem.

Frappe Framework Patterns

DocType: The Core Abstraction

A DocType is Frappe's fundamental building block. It combines:

  • Database table — Schema definition
  • Form UI — Layout and fields
  • Permissions — Access control
  • Workflow — States and transitions
  • Controller — Python class for business logic

Key insight: Editing a DocType JSON changes the database schema. Editing the Python controller changes behavior.

DocType File Locations

app_name/
└── app_name/
    └── doctype/
        └── doctype_name/
            ├── doctype_name.json      # Schema (fields, permissions)
            ├── doctype_name.py        # Controller (validations, methods)
            ├── doctype_name_list.js   # List view customization
            ├── doctype_name_calendar.js  # Calendar view
            └── test_doctype_name.py   # Unit tests

hooks.py: The Wiring Diagram

Every Frappe app has a hooks.py that registers:

Hook Type Purpose Example
doc_events React to document changes Send email when Order submitted
scheduler_events Background jobs Daily report generation
override_doctype_class Replace core behavior Custom Employee validation
doctype_js Client-side scripts Form field visibility
website_generators Public pages Product pages

Request Flow in Frappe

HTTP Request
    ↓
Frappe Router
    ↓
Permission Check
    ↓
Controller Method (whitelisted)
    ↓
Document Load/Save (if DocType)
    ↓
Database (MariaDB)
    ↓
Response (JSON/HTML)

Common Database Operations

Operation Code Use When
Get single doc frappe.get_doc("Doctype", "name") You need the full object with methods
Query multiple frappe.get_all("Doctype", filters={}) Read-only list, respects permissions
Raw SQL frappe.db.sql("SELECT ...") Complex queries (avoid if possible)
Single value frappe.db.get_value("Doctype", "name", "field") Just need one field

Extension Patterns

The Override Pattern

Instead of modifying core code, create an override:

# In your app: my_app/overrides/employee.py
from erpnext.setup.doctype.employee.employee import Employee

class CustomEmployee(Employee):
    def validate(self):
        super().validate()  # Call original
        # Add your custom validation
        if self.date_of_birth and self.date_of_birth > today():
            frappe.throw("Date of birth cannot be in the future")

Register in hooks.py:

override_doctype_class = {
    "Employee": "my_app.overrides.employee.CustomEmployee"
}

The Event Hook Pattern

Add behavior without changing the original class:

# hooks.py
doc_events = {
    "Sales Order": {
        "on_submit": "my_app.hooks.send_notification_email"
    }
}

# my_app/hooks.py
def send_notification_email(doc, method=None):
    frappe.sendmail(
        recipients=[doc.contact_email],
        subject=f"Order {doc.name} confirmed!",
        message="..."
    )

Custom Fields Pattern

Add fields without forking the DocType:

Method Best For Persistence
Desk UI (Customize Form) Quick additions Database only
Fixtures Version controlled Exportable JSON
Patch Data migration One-time setup

Python Patterns

Imports You Will See Everywhere

import frappe                    # The framework
from frappe import _             # Translation function
from frappe.utils import today, getdate, flt, cint  # Utilities

The frappe.throw Pattern

if not self.customer:
    frappe.throw(_("Customer is required"), title=_("Missing Field"))

Always use _("...") for translatable strings.

Naming Conventions

Element Convention Example
DocType names Title Case "Leave Application"
Field names snake_case "employee_name"
Python files snake_case "leave_application.py"
Class names PascalCase class LeaveApplication

Git-Mediawiki Workflow

How This Wiki Works

  1. Content is written as .wiki files (MediaWiki wikitext)
  2. Files are stored in a git repository (wiki-gi7b-org/)
  3. git push syncs to live MediaWiki at wiki.gi7b.org

File Naming

Wiki Page File Path
PageName PageName.wiki
Namespace:Page Namespace/Page.wiki
Page/Subpage Page/Subpage.wiki

Commit Convention

# After completing a repo analysis
git add Repo/AppName/
git commit -m "Repo:AppName — full structural analysis (6 pages)"
git push

# After updating index
git add Repo_Index.wiki Repo_SharedConcepts.wiki
git commit -m "Repo:Index + SharedConcepts — updated after AppName analysis"
git push

Reading Dependencies

requirements.txt / pyproject.toml

When you see a dependency, ask:

  1. Is it a Frappe app? (frappe, erpnext, payments)
    • These extend the framework
  2. Is it a Python library? (requests, pandas)
    • These provide specific functionality
  3. Is it for development? (pytest, black)
    • These are dev-only, not runtime

package.json (Node.js)

  • Dependencies — Required at runtime
  • devDependencies — Build/test only
  • Look for frappe-ui — Frappe's Vue component library

Development Workflow

Typical Edit Cycle

  1. Understand — Read relevant wiki page
  2. Locate — Find the file to edit (use DirectoryMap)
  3. Edit — Make minimal changes
  4. Test — Run bench start, check browser
  5. Migrate — If DocType changed: bench migrate
  6. Build — If JS/CSS changed: bench build
  7. Commit — Git commit with clear message

Common bench Commands

Command When to Use
bench start Start development server
bench migrate Sync DocTypes, run patches
bench build Compile frontend assets
bench --site [site] install-app [app] Install app on site
bench --site [site] console Interactive Python shell
bench --site [site] mariadb Direct database access

Quick Decision Guide

"I want to add a field to a form"

  1. Is it a core field? → Edit DocType JSON
  2. Is it custom/temporary? → Use Customize Form (Desk UI)
  3. Needs to be version controlled? → Use fixtures

"I want to change validation logic"

  1. For standard DocTypes → Override class in overrides/
  2. For custom DocTypes → Edit the DocType's .py controller
  3. For cross-cutting concerns → Use doc_events hook

"I want to run code on a schedule"

  1. Add to scheduler_events in hooks.py
  2. Choose frequency: all, hourly, daily, weekly, monthly

"I want to add a web page"

  1. Public page → Create in www/
  2. Auto-generated per record → Use website_generators
  3. API endpoint → Use @frappe.whitelist()

Resources