2. code convention
Frappe Code Convention - Quy Ước Lập Trình
1. Cấu Trúc Module
1.1 Tên Module
1.2 Cấu Trúc Thư Mục Module
module_name/
├── __init__.py
├── hooks.py
├── modules.txt
├── patches.txt
├── doctype/
├── report/
├── dashboard_chart/
├── workspace/
├── public/
│ ├── css/
│ └── js/
└── templates/
2. Quy Ước DocType
2.1 Tên DocType
2.2 Thuộc Tính DocType
# Trong file .json của DocType
{
"doctype": "DocType",
"name": "_customer",
"module": "SalesManagement",
"custom": 0,
"is_submittable": 0,
"is_child_table": 0,
"track_changes": 1,
"track_seen": 1
}
3. Quy Ước Field
3.1 Naming Convention
- Primary Key:
{table_name}_id
- Code Field:
{table_name}_code
- Name Field:
{table_name}_name
- Foreign Key:
{related_table}_id
3.2 Ví Dụ Cụ Thể
# Bảng "_test" (tab_test)
- test_id # Primary identifier
- test_code # Unique code
- test_name # Display name
- test_description # Description
- test_status # Status field
- test_type_id # FK to "_type" table
- created_by_id # FK to User
- modified_by_id # FK to User
# Bảng "_type" (tab_type)
- type_id # Primary identifier
- type_code # Unique code
- type_name # Display name
3.3 Field Types và Properties
# String Fields
{
"fieldname": "customer_code",
"fieldtype": "Data",
"label": "Customer Code",
"reqd": 1,
"unique": 1,
"length": 20
}
# Link Fields (Foreign Key)
{
"fieldname": "customer_type_id",
"fieldtype": "Link",
"label": "Customer Type",
"options": "_customer_type",
"reqd": 1
}
# Select Fields
{
"fieldname": "customer_status",
"fieldtype": "Select",
"label": "Status",
"options": "Active\nInactive\nSuspended",
"default": "Active"
}
4. Quy Ước File và Folder
4.1 Python Files
- Controllers:
{doctype_name}.py
- Format: snake_case
- Ví dụ:
_customer.py, _sales_order.py
4.2 JavaScript Files
- Client Scripts:
{doctype_name}.js
- Format: snake_case
- Ví dụ:
_customer.js, _sales_order.js
4.3 JSON Files
- DocType Definition:
{doctype_name}.json
- Ví dụ:
_customer.json
5. Quy Ước Database
5.1 Indexes
# Trong DocType JSON
"indexes": [
{
"columns": ["customer_code"],
"unique": 1
},
{
"columns": ["customer_type_id", "customer_status"]
}
]
5.2 Constraints
- Unique Fields: Luôn đặt unique constraint cho code fields
- Required Fields: Đánh dấu rõ ràng các field bắt buộc
- Default Values: Đặt giá trị mặc định hợp lý
6. Quy Ước Code Python
6.1 Class Names
# Controller Classes
class _Customer(Document):
def validate(self):
self.validate_customer_code()
def validate_customer_code(self):
if not self.customer_code:
self.customer_code = self.generate_customer_code()
6.2 Method Names
6.3 Import Convention
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import nowdate, getdate, flt, cint
7. Quy Ước JavaScript
7.1 Client Script Structure
frappe.ui.form.on('_Customer', {
refresh: function(frm) {
// Form refresh logic
},
customer_type_id: function(frm) {
// Field change logic
},
validate: function(frm) {
// Client-side validation
}
});
8. Quy Ước Permission
8.1 Role Naming
8.2 Permission Structure
# Trong DocType permissions
{
"role": "Sales User",
"read": 1,
"write": 1,
"create": 1,
"delete": 0,
"submit": 0,
"cancel": 0,
"amend": 0
}
9. Quy Ước Report
9.1 Report Names
9.2 Report Fields
columns = [
{
"fieldname": "customer_code",
"label": _("Customer Code"),
"fieldtype": "Link",
"options": "_customer",
"width": 120
}
]
10. Quy Ước Documentation
def validate_customer_code(self):
"""
Validate customer code format and uniqueness
Returns:
None
Raises:
frappe.ValidationError: If code format is invalid
"""
pass
# Validate customer information before saving
if self.customer_type_id:
self.validate_customer_type()
# TODO: Add email validation
# FIXME: Handle duplicate code edge case
11. Quy Ước Testing
11.1 Test File Names
11.2 Test Class Structure
import unittest
import frappe
class TestCustomer(unittest.TestCase):
def setUp(self):
# Test setup code
pass
def test_customer_creation(self):
# Test customer creation
pass
def tearDown(self):
# Cleanup code
pass
12. Best Practices
- Sử dụng indexes cho các field thường xuyên query
- Tránh N+1 queries bằng cách sử dụng
frappe.get_all() với fields parameter
- Cache dữ liệu static với
frappe.cache()
12.2 Security
12.3 Maintainability
- Viết code có thể đọc được
- Sử dụng meaningful variable names
- Tách logic phức tạp thành methods nhỏ
- Documentation đầy đủ
12.4 Error Handling
try:
# Business logic
pass
except frappe.ValidationError:
frappe.throw(_("Validation failed: {0}").format(error_message))
except Exception as e:
frappe.log_error(message=str(e), title="Customer Creation Failed")
frappe.throw(_("An error occurred while creating customer"))
try:
# Business logic
pass
except frappe.ValidationError:
frappe.throw(_("Validation failed: {0}").format(error_message))
except Exception as e:
frappe.log_error(message=str(e), title="Customer Creation Failed")
frappe.throw(_("An error occurred while creating customer"))