Repo comfac-webshop ExtensionPoints
Repo:comfac-webshop/ExtensionPoints — Extension and Customization Points
The Safe Edit Zone
Frappe Override Pattern
Like comfac-hrms, webshop uses the "override instead of modify" pattern:
| Location | What to Put There |
|---|---|
webshop/webshop/doctype/override_doctype/ |
Override ERPNext classes |
webshop/webshop/crud_events/ |
Event handlers for sync logic |
webshop/public/js/ |
Custom client-side JavaScript |
webshop/templates/ |
Custom Jinja templates |
webshop/www/ |
New web pages or route overrides |
| Custom Fields (via UI) | Non-core fields |
Files You Should NOT Edit Directly
- ERPNext core (Item, Quotation, etc.)
- Frappe framework
- Third-party libraries
Hooks & Events
Current Hooks in webshop/hooks.py
| Hook Type | Purpose | Current Usage |
|---|---|---|
after_install |
Post-install setup | Create default Webshop Settings |
on_logout |
Cleanup | Clear cart count cookie |
on_session_creation |
Initialize | Update debtors account, set cart count |
update_website_context |
Template data | Add cart info to all pages |
website_generators |
Auto-routes | Website Item, Item Group pages |
override_doctype_class |
Class overrides | Item, Item Group, Payment Request |
doctype_js |
Client scripts | Item, Homepage forms |
doc_events |
Server events | Item sync, Quotation validation |
has_website_permission |
Access control | Website Item, Item Group visibility |
Document Event Hooks
| DocType | Event | Handler | Purpose |
|---|---|---|---|
| Item | on_update | crud_events.item.update_website_item |
Sync to Website Item |
| Item | on_update | crud_events.item.invalidate_item_variants_cache |
Clear cache |
| Item | before_rename | crud_events.item.validate_duplicate_website_item |
Prevent conflicts |
| Item | after_rename | crud_events.item.invalidate_item_variants_cache |
Clear cache |
| Sales Taxes Template | on_update | webshop_settings.validate_cart_settings |
Validate config |
| Quotation | validate | crud_events.quotation.validate_shopping_cart_items |
Cart validation |
| Price List | validate | crud_events.price_list.check_impact_on_cart |
Warn users |
| Tax Rule | validate | crud_events.tax_rule.validate_use_for_cart |
Compatibility check |
Session Hooks
| Hook | When Fired | Handler |
|---|---|---|
on_session_creation |
User logs in | Update debtors account, set cart count |
on_logout |
User logs out | Clear cart count cookie |
Override Patterns
Pattern 1: Override ERPNext DocType
Current: Item override in webshop/webshop/doctype/override_doctype/item.py
```python from erpnext.stock.doctype.item.item import Item
class WebshopItem(Item):
def on_update(self):
super().on_update() # Call parent
# Custom: Auto-create Website Item
self.create_website_item()
def create_website_item(self):
if not frappe.db.exists("Website Item", {"item_code": self.name}):
# Create logic here
pass
```
Registration in hooks.py:
```python override_doctype_class = {
"Item": "webshop.webshop.doctype.override_doctype.item.WebshopItem",
} ```
Pattern 2: Add Custom Cart Validation
Goal: Minimum order amount check
Steps:
- Edit
webshop/webshop/crud_events/quotation.py:
```python def validate_shopping_cart_items(doc, method=None):
"""Existing validation"""
# ... existing code ...
# Add custom validation
if doc.order_type == "Shopping Cart":
minimum_order = 1000 # PHP
if doc.total < minimum_order:
frappe.throw(_(
f"Minimum order amount is {minimum_order} PHP"
))
```
- Already registered in hooks.py:
```python doc_events = {
"Quotation": {
"validate": ["webshop.webshop.crud_events.quotation.validate_shopping_cart_items"]
}
} ```
Pattern 3: Custom Product Filter
Goal: Add "New Arrivals" filter
Create: webshop/webshop/product_data_engine/filters.py
```python def apply_new_arrivals_filter(query, filters):
"""Show items created in last 30 days"""
from datetime import datetime, timedelta
thirty_days_ago = datetime.now() - timedelta(days=30)
query = query.where(
frappe.qb.DocType("Website Item").creation >= thirty_days_ago
)
return query
```
Use in template:
Add to product listing template to call custom filter.
Pattern 4: Custom Payment Gateway Integration
Goal: Add Philippines-specific payment method (e.g., GCash)
Override Payment Request:
Edit webshop/webshop/doctype/override_doctype/payment_request.py:
```python from erpnext.accounts.doctype.payment_request.payment_request import PaymentRequest
class WebshopPaymentRequest(PaymentRequest):
def on_submit(self):
super().on_submit()
if self.payment_gateway == "GCash":
# Generate GCash payment URL
self.payment_url = generate_gcash_url(self)
def get_payment_url(self):
if self.payment_gateway == "GCash":
return self.payment_url
return super().get_payment_url()
```
Adding New Web Pages
Create a New Page: Order Tracking
Step 1: Create controller webshop/www/track-order/index.py:
```python import frappe from frappe import _
def get_context(context):
context.no_cache = 1
order_id = frappe.form_dict.get('order')
if order_id:
context.order = frappe.get_doc("Sales Order", order_id)
context.tracking_info = get_tracking_info(order_id)
return context
def get_tracking_info(order_id):
# Custom tracking logic pass
```
Step 2: Create template webshop/www/track-order/index.html:
```html {% extends "templates/web_base.html" %}
{% block page_content %}
Track Your Order
{% if order %}
Order #Template:Order.name
Status: Template:Order.status
{% else %}
<form method="GET">
<input type="text" name="order" placeholder="Enter Order Number">
<button type="submit">Track</button>
</form>
{% endif %}
{% endblock %} ```
Step 3: Access at /track-order
Custom Fields Best Practice
| Approach | When to Use | How |
|---|---|---|
| Custom Field (UI) | Quick additions | Desk → Customize Form |
| Fixtures | Version-controlled fields | Add to hooks.py fixtures |
| DocType JSON edit | Core app changes | Edit .json, migrate |
Export Custom Fields as Fixtures
In webshop/hooks.py:
```python fixtures = [
{
"dt": "Custom Field",
"filters": "module", "=", "Webshop"
}
] ```
Then run: bench export-fixtures
Template Overrides
Override Product Card
Create: webshop/templates/webshop/item_card.html
Copy original from Frappe and modify:
```html
<a href="Template:Item.route"> <img src="Template:Item.website image or '/assets/webshop/images/fallback.png'" alt="Template:Item.web item name">
</a>
```
JavaScript Customization
Add Custom Cart Behavior
Edit webshop/public/js/cart.js:
```javascript // Add to existing file or create new frappe.ready(function() {
// Custom: Show confirmation modal for expensive items
$('.add-to-cart').on('click', function(e) {
var price = $(this).data('price');
if (price > 50000) { // PHP 50,000
if (!confirm('This item costs ₱' + price + '. Add to cart?')) {
e.preventDefault();
return false;
}
}
});
}); ```
Register in webshop/hooks.py:
```python web_include_js = [
"web.bundle.js", "webshop/js/cart.js" # Add custom file
] ```
Related Pages
- Repo_comfac-webshop_Overview — Project overview
- Repo_comfac-webshop_DirectoryMap — Directory structure and key files
- Repo_comfac-webshop_EntryPoints — How the app starts
- Repo_comfac-webshop_DataModel — DocTypes and data model
- Repo_comfac-webshop_CommonEdits — Common edit recipes
- Repo_comfac-hrms_ExtensionPoints — Extension points for comfac-hrms