Skip to content

Commit a105128

Browse files
FreekHeijtingclaude
andcommitted
feat: V2.5 new skills P0 batch 1 (3 syntax skills)
New skills with full content: - frappe-syntax-doctypes: 35+ fieldtypes, naming rules, child tables, tree, virtual, Custom Fields API, Property Setters - frappe-syntax-reports: Query Report, Script Report, Number Cards, Dashboard Charts, Prepared Reports - frappe-syntax-hooks-events: all doc_events in exact execution order, transaction behavior, extend_doctype_class [v16+] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e33a3db commit a105128

16 files changed

Lines changed: 4565 additions & 17 deletions

File tree

skills/source/syntax/frappe-syntax-doctypes/SKILL.md

Lines changed: 267 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,278 @@ metadata:
1414

1515
# DocType JSON Design
1616

17-
> **STATUS**: Stub - content pending V2.5 development phase.
17+
DocTypes are the foundation of every Frappe application. A DocType defines both the **data model** (database schema) and the **view** (form layout). ALWAYS design DocTypes before writing any controller logic.
1818

1919
## Quick Reference
2020

21-
_Content to be developed._
21+
### DocType JSON Top-Level Properties
2222

23-
## Decision Tree
23+
| Property | Type | Purpose |
24+
|----------|------|---------|
25+
| `name` | str | DocType identifier (singular, e.g. "Sales Invoice") |
26+
| `module` | str | App module this DocType belongs to |
27+
| `is_submittable` | bool | Enables Draft -> Submitted -> Cancelled workflow |
28+
| `is_tree` | bool | Enables NestedSet hierarchy (lft/rgt columns) |
29+
| `is_virtual` | bool | No database table; data from custom backend |
30+
| `issingle` | bool | Single-instance settings document |
31+
| `istable` | bool | Child table DocType (embedded in parent) |
32+
| `is_calendar_and_gantt` | bool | Enables calendar/gantt views |
33+
| `track_changes` | bool | Stores version history on every save |
34+
| `track_seen` | bool | Tracks which users viewed the document |
35+
| `track_views` | bool | Counts total document views |
36+
| `allow_rename` | bool | Permits renaming after creation |
37+
| `allow_copy` | bool | Enables "Duplicate" action |
38+
| `allow_import` | bool | Enables Data Import for this DocType |
39+
| `naming_rule` | str | Naming method selector (see Naming section) |
40+
| `autoname` | str | Naming pattern string |
41+
| `title_field` | str | Field used as display title |
42+
| `search_fields` | str | Comma-separated fields for search results |
43+
| `show_title_field_in_link` | bool | Display title instead of name in Link fields |
44+
| `image_field` | str | Field containing image for avatar display |
45+
| `sort_field` | str | Default sort column |
46+
| `sort_order` | str | "ASC" or "DESC" |
47+
| `default_print_format` | str | Print Format name |
48+
| `max_attachments` | int | Attachment limit |
2449

25-
_Content to be developed._
50+
### Common Fieldtypes (Quick Lookup)
51+
52+
| Fieldtype | Stores | DB Column |
53+
|-----------|--------|-----------|
54+
| Data | Text up to 140 chars | VARCHAR(140) |
55+
| Link | Reference to another DocType | VARCHAR(140) |
56+
| Dynamic Link | Reference to any DocType | VARCHAR(140) |
57+
| Select | Single choice from options | VARCHAR(140) |
58+
| Table | Child table rows | Separate table |
59+
| Table MultiSelect | Multi-select link rows | Separate table |
60+
| Check | Boolean 0/1 | TINYINT |
61+
| Int | Whole number | INT |
62+
| Float | Decimal (9 places) | DECIMAL |
63+
| Currency | Money value (6 decimals) | DECIMAL |
64+
| Date | Calendar date | DATE |
65+
| Datetime | Date + time | DATETIME |
66+
| Text Editor | Rich text (HTML) | LONGTEXT |
67+
| Attach | File reference | VARCHAR(140) |
68+
| Small Text | Short multi-line text | TEXT |
69+
| Long Text | Unlimited text | LONGTEXT |
70+
71+
> Full fieldtype reference with all 35+ types: [references/fieldtypes.md](references/fieldtypes.md)
72+
73+
### Essential Field Properties
74+
75+
| Property | Type | Purpose |
76+
|----------|------|---------|
77+
| `reqd` | bool | Field is mandatory |
78+
| `unique` | bool | Database UNIQUE constraint |
79+
| `search_index` | bool | Database INDEX for faster queries |
80+
| `in_list_view` | bool | Show in list view columns |
81+
| `in_standard_filter` | bool | Show as filter in list view |
82+
| `in_preview` | bool | Show in document preview |
83+
| `allow_on_submit` | bool | Editable after submission |
84+
| `read_only` | bool | Not editable by user |
85+
| `hidden` | bool | Not visible on form |
86+
| `depends_on` | str | Visibility condition (e.g. `eval:doc.status=="Active"`) |
87+
| `mandatory_depends_on` | str | Conditional mandatory |
88+
| `read_only_depends_on` | str | Conditional read-only |
89+
| `fetch_from` | str | Auto-populate from linked doc (e.g. `customer.customer_name`) |
90+
| `fetch_if_empty` | bool | Only fetch when field is empty |
91+
| `options` | str | Fieldtype-specific (DocType name, select options, etc.) |
92+
| `default` | str | Default value (supports `__user`, `Today`, etc.) |
93+
| `description` | str | Help text below field |
94+
| `collapsible` | bool | Section starts collapsed (Section Break only) |
95+
96+
## Decision Tree: Which DocType Type?
97+
98+
```
99+
Need to store data?
100+
├─ YES: Need multiple records?
101+
│ ├─ YES: Need submit/cancel workflow?
102+
│ │ ├─ YES → Standard DocType + is_submittable=1
103+
│ │ └─ NO: Need hierarchy/tree?
104+
│ │ ├─ YES → Tree DocType (is_tree=1)
105+
│ │ └─ NO: Embedded in parent?
106+
│ │ ├─ YES → Child DocType (istable=1)
107+
│ │ └─ NO → Standard DocType
108+
│ └─ NO: Single config/settings → Single DocType (issingle=1)
109+
└─ NO: Data from external source → Virtual DocType (is_virtual=1)
110+
```
111+
112+
## Naming Rules
113+
114+
ALWAYS set `naming_rule` on the DocType. The `autoname` field holds the pattern.
115+
116+
| naming_rule Value | autoname Pattern | Example Output |
117+
|-------------------|------------------|----------------|
118+
| Set by User | _(empty)_ | User types name manually |
119+
| Autoincrement | _(empty)_ | `1`, `2`, `3` |
120+
| By Fieldname | `field:{fieldname}` | Value of that field |
121+
| By Naming Series | `naming_series:` | `INV-2024-00001` (from series field) |
122+
| Expression | `PRE-.#####` | `PRE-00001`, `PRE-00002` |
123+
| Expression (Old Style) | `{prefix}-{YYYY}-{#####}` | `INV-2024-00001` |
124+
| Random | `hash` | Random 10-char string |
125+
| UUID | _(empty)_ | `550e8400-e29b-...` |
126+
| By Script | _(custom)_ | Controller `autoname()` decides |
127+
128+
> NEVER use Autoincrement in production -- gaps appear when records are deleted. Use Expression or Naming Series instead.
129+
130+
> Full naming reference: [references/naming.md](references/naming.md)
131+
132+
## Child Table Design
133+
134+
A Child DocType is a DocType with `istable=1`. It ALWAYS belongs to a parent.
135+
136+
**Parent side** -- add a field with:
137+
- `fieldtype`: `Table` (or `Table MultiSelect`)
138+
- `options`: Child DocType name
139+
140+
**Child records automatically get**:
141+
- `parent` -- name of the parent document
142+
- `parenttype` -- DocType of the parent
143+
- `parentfield` -- fieldname of the Table field in parent
144+
- `idx` -- row order (1-based)
145+
146+
```python
147+
# Adding child rows programmatically
148+
doc = frappe.get_doc("Sales Invoice", "INV-001")
149+
doc.append("items", {
150+
"item_code": "ITEM-001",
151+
"qty": 5,
152+
"rate": 100.0
153+
})
154+
doc.save()
155+
```
156+
157+
> NEVER create a Child DocType without `istable=1`. NEVER reference a non-child DocType in a Table field.
158+
159+
### Table vs Table MultiSelect
160+
161+
| Aspect | Table | Table MultiSelect |
162+
|--------|-------|-------------------|
163+
| UI | Full editable grid with "Add Row" | Tag-style picker, no "Add Row" |
164+
| Child DocType | Full child with many fields | Typically 1 Link field only |
165+
| Use case | Line items, detail rows | Multi-select references |
166+
167+
## Single DocType (Settings Pattern)
168+
169+
Set `issingle=1`. Data is stored in `tabSingles` as key-value pairs, NOT in a dedicated table.
170+
171+
```python
172+
# Access Single DocType
173+
settings = frappe.get_single("My Settings")
174+
value = settings.some_field
175+
176+
# Or directly
177+
value = frappe.db.get_single_value("My Settings", "some_field")
178+
```
179+
180+
- NEVER expect a list view for Single DocTypes -- they have exactly one instance.
181+
- ALWAYS use for app-wide configuration (API keys, default values, feature toggles).
182+
183+
## Tree DocType (NestedSet)
184+
185+
Set `is_tree=1`. Frappe adds `lft`, `rgt`, `parent_{doctype_fieldname}`, `old_parent` columns automatically.
186+
187+
- ALWAYS define a `parent_field` in the DocType JSON (e.g. `parent_account` for Chart of Accounts).
188+
- The NestedSet model uses `lft`/`rgt` integers for efficient subtree queries.
189+
- NEVER manually edit `lft`/`rgt` values. Use `frappe.utils.nestedset.rebuild_tree()` if corrupted.
190+
191+
```python
192+
# Get all descendants
193+
descendants = frappe.get_all("Account",
194+
filters={"lft": [">", node.lft], "rgt": ["<", node.rgt]})
195+
196+
# Get ancestors (path to root)
197+
ancestors = frappe.get_all("Account",
198+
filters={"lft": ["<", node.lft], "rgt": [">", node.rgt]},
199+
order_by="lft asc")
200+
```
201+
202+
## Virtual DocType
203+
204+
Set `is_virtual=1`. No database table is created. ALWAYS implement these controller methods:
205+
206+
```python
207+
class MyVirtualDoc(Document):
208+
def db_insert(self, *args, **kwargs):
209+
# Persist to your custom backend
210+
pass
211+
212+
def load_from_db(self):
213+
# Load document data from your source
214+
pass
215+
216+
def db_update(self, *args, **kwargs):
217+
# Update in your custom backend
218+
pass
219+
220+
def delete(self):
221+
# Remove from your custom backend
222+
pass
223+
224+
@staticmethod
225+
def get_list(args):
226+
# Return list of documents
227+
pass
228+
229+
@staticmethod
230+
def get_count(args):
231+
# Return total count
232+
pass
233+
234+
@staticmethod
235+
def get_stats(args):
236+
# Return statistics
237+
pass
238+
```
239+
240+
> NEVER use `frappe.db.*` calls for Virtual DocType data -- they only work with the site database, not your custom backend.
241+
242+
## Customization APIs
243+
244+
### Custom Fields (Programmatic)
245+
246+
```python
247+
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
248+
249+
# Dict format: {DocType: [field_dicts]}
250+
create_custom_fields({
251+
"Sales Invoice": [
252+
dict(fieldname="custom_tracking", label="Tracking ID",
253+
fieldtype="Data", insert_after="naming_series")
254+
],
255+
"Purchase Order": [
256+
dict(fieldname="custom_vendor_ref", label="Vendor Ref",
257+
fieldtype="Data", insert_after="supplier")
258+
]
259+
}, update=True)
260+
```
261+
262+
### Property Setter (Programmatic)
263+
264+
```python
265+
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
266+
267+
# Change a field property on an existing DocType
268+
make_property_setter("Sales Invoice", "customer", "reqd", 1, "Check")
269+
make_property_setter("Sales Invoice", "posting_date", "default", "Today", "Text")
270+
```
271+
272+
> Full customization reference: [references/customization.md](references/customization.md)
273+
274+
## Critical Rules
275+
276+
1. ALWAYS name DocTypes in **singular** form ("Sales Invoice", not "Sales Invoices").
277+
2. ALWAYS use the `tab` prefix mentally -- the DB table is `tabSales Invoice`.
278+
3. NEVER exceed 140 characters for Data/Link/Select field values.
279+
4. ALWAYS set `search_index=1` on fields used in frequent filters or `get_list` calls.
280+
5. ALWAYS set `in_standard_filter=1` on fields users frequently filter by.
281+
6. NEVER use `allow_on_submit=1` on child table fields that affect calculations without recalculating totals.
282+
7. ALWAYS set `fetch_if_empty=1` alongside `fetch_from` unless you want to overwrite user edits.
283+
8. NEVER define `depends_on` with raw Python -- use `eval:doc.fieldname == "value"` syntax.
26284

27285
## See Also
28286

29-
_Cross-references to be added._
287+
- [references/fieldtypes.md](references/fieldtypes.md) -- Complete fieldtype reference
288+
- [references/naming.md](references/naming.md) -- All naming methods with examples
289+
- [references/examples.md](references/examples.md) -- Real DocType JSON examples
290+
- [references/anti-patterns.md](references/anti-patterns.md) -- Common schema design mistakes
291+
- [references/customization.md](references/customization.md) -- Custom Fields and Property Setter APIs

0 commit comments

Comments
 (0)