Repo comfac-webshop CommonEdits
Repo:comfac-webshop/CommonEdits — Common Edit Scenarios
This page contains practical recipes for common e-commerce customization tasks.
Scenario 1: Adding a Custom Product Field
Goal
Add "Warranty Period" field to Website Items.
Files to Touch
webshop/webshop/doctype/website_item/website_item.json- OR use Frappe Desk Customize Form
Method: Via Desk (Recommended)
- Go to Website Item list
- Click Customize
- Add field:
- Label: Warranty Period
- Fieldtype: Select
- Options: 1 Year\n2 Years\n3 Years\n5 Years
- Insert After: brand
- Save
Method: Via Code
Edit webshop/webshop/doctype/website_item/website_item.json:
Find "fields" array and add:
{
"fieldname": "warranty_period",
"fieldtype": "Select",
"label": "Warranty Period",
"options": "1 Year\n2 Years\n3 Years\n5 Years",
"insert_after": "brand"
}
Run bench migrate
Display on Product Page
Edit template webshop/templates/webshop/website_item.html:
{% if doc.warranty_period %}
<div class="product-warranty">
<i class="icon-shield"></i>
Warranty: {{ doc.warranty_period }}
</div>
{% endif %}
How to Verify
- Edit a Website Item, set warranty period
- View product page
- Verify warranty displays correctly
---
Scenario 2: Customizing the Checkout Flow
Goal
Add "Delivery Instructions" field to checkout.
Files to Touch
webshop/www/checkout/index.htmlwebshop/webshop/shopping_cart/cart.py
Step 1: Add Field to Template
In checkout template, find address section and add:
<div class="form-group">
<label>Delivery Instructions (Optional)</label>
<textarea class="form-control" name="delivery_instructions"
placeholder="e.g., Leave at guard house"></textarea>
</div>
Step 2: Save to Quotation
In cart.py, find place_order or update_cart function:
@frappe.whitelist()
def place_order(delivery_instructions=None):
quotation = _get_cart_quotation()
# Add custom field
if delivery_instructions:
quotation.custom_delivery_instructions = delivery_instructions
# Convert to Sales Order
sales_order = frappe.get_doc(
make_sales_order(quotation.name)
)
sales_order.custom_delivery_instructions = delivery_instructions
sales_order.insert()
return sales_order.name
Step 3: Add Custom Field to Quotation/Sales Order
Via Desk → Customize Form → Quotation:
- Add field: custom_delivery_instructions (Text)
Repeat for Sales Order.
How to Verify
- Add item to cart
- Go to checkout
- Enter delivery instructions
- Place order
- Check Sales Order for saved instructions
---
Scenario 3: Adding a New Payment Gateway
Goal
Integrate Philippine payment gateway (e.g., PayMongo).
Files to Touch
webshop/webshop/doctype/override_doctype/payment_request.pywebshop/templates/webshop/checkout/payment.html
Step 1: Override Payment Request
import requests
from erpnext.accounts.doctype.payment_request.payment_request import PaymentRequest
class WebshopPaymentRequest(PaymentRequest):
def get_payment_url(self):
if self.payment_gateway == "PayMongo":
return self.create_paymongo_intent()
return super().get_payment_url()
def create_paymongo_intent(self):
# PayMongo API integration
response = requests.post(
"https://api.paymongo.com/v1/payment_intents",
headers={"Authorization": "Basic " + get_api_key()},
json={
"data": {
"attributes": {
"amount": int(self.grand_total * 100), # cents
"currency": "PHP",
"description": f"Order {self.reference_name}"
}
}
}
)
return response.json()["data"]["attributes"]["checkout_url"]
Step 2: Configure Payment Gateway
In Frappe Desk:
- Go to Payment Gateway Account
- Create new: PayMongo
- Add API credentials in Payment Gateway settings
Step 3: Add to Checkout
In payment template:
{% if cart_settings.payment_gateway == "PayMongo" %}
<button class="btn btn-primary" onclick="payWithPayMongo()">
Pay with PayMongo
</button>
{% endif %}
How to Verify
- Configure PayMongo test credentials
- Add item to cart
- Checkout and select PayMongo
- Verify redirect to PayMongo checkout
---
Scenario 4: Custom Product Filter/Sort
Goal
Add "Sort by Price: Low to High" option.
Files to Touch
webshop/webshop/product_data_engine/query.pywebshop/templates/webshop/all-products.html
Step 1: Add Sort Logic
In query.py, find product listing query builder:
def get_product_list(filters=None, sort_by=None):
query = build_base_query()
# Apply filters
if filters:
query = apply_filters(query, filters)
# Apply sorting
if sort_by == "price_asc":
query = query.orderby("price", order=frappe.qb.asc)
elif sort_by == "price_desc":
query = query.orderby("price", order=frappe.qb.desc)
elif sort_by == "newest":
query = query.orderby("creation", order=frappe.qb.desc)
return query.run()
Step 2: Add UI Control
In all-products template:
<div class="sort-options">
<select id="sort-select" onchange="sortProducts(this.value)">
<option value="relevance">Relevance</option>
<option value="price_asc">Price: Low to High</option>
<option value="price_desc">Price: High to Low</option>
<option value="newest">Newest First</option>
</select>
</div>
<script>
function sortProducts(sortBy) {
const url = new URL(window.location);
url.searchParams.set('sort_by', sortBy);
window.location = url;
}
</script>
How to Verify
- Visit /all-products
- Select different sort options
- Verify products reorder correctly
---
Scenario 5: Custom Email Template
Goal
Customize order confirmation email.
Files to Touch
- Frappe Desk → Email Template
- OR
webshop/webshop/notification/order_confirmation/
Method 1: Via Desk
- Go to Email Template list
- Find Order Confirmation
- Edit subject and body:
Subject:
Thank you for your order #{{ doc.name }} from ComFac!
Body:
<h1>Hi {{ doc.customer_name }},</h1>
<p>Thank you for shopping with ComFac Corporation!</p>
<h3>Order Details:</h3>
<table>
<tr><td>Order Number:</td><td>{{ doc.name }}</td></tr>
<tr><td>Order Date:</td><td>{{ doc.transaction_date }}</td></tr>
<tr><td>Total:</td><td>₱{{ doc.grand_total }}</td></tr>
</table>
<p>You can track your order at:
<a href="{{ frappe.utils.get_url() }}/track-order?order={{ doc.name }}">
Track Order
</a></p>
Method 2: Via Code
Create webshop/webshop/notification/order_confirmation/order_confirmation.json:
{
"name": "Order Confirmation - ComFac",
"subject": "Thank you for your order #{{ doc.name }}!",
"document_type": "Sales Order",
"event": "New",
"message": "...template HTML..."
}
How to Verify
- Place test order
- Check email received
- Verify custom template applied
---
Scenario 6: Adding Product Reviews
Goal
Enable and display customer reviews.
Files to Touch
- Frappe Desk → Webshop Settings
webshop/templates/webshop/website_item.html
Step 1: Enable in Settings
Desk → Webshop Settings:
- Check "Enable Reviews"
Step 2: Display Reviews
In product page template:
<section class="product-reviews">
<h3>Customer Reviews</h3>
{% set reviews = frappe.get_all("Item Review",
filters={"website_item": doc.name, "published": 1},
fields=["customer", "rating", "review", "creation"]
) %}
{% if reviews %}
<div class="average-rating">
{{ get_average_rating(reviews) }} / 5
({{ reviews|length }} reviews)
</div>
{% for review in reviews %}
<div class="review">
<div class="stars">{{ "★" * review.rating }}</div>
<p>{{ review.review }}</p>
<small>By {{ review.customer }} on {{ review.creation }}</small>
</div>
{% endfor %}
{% else %}
<p>No reviews yet. Be the first!</p>
{% endif %}
</section>
{% if frappe.session.user != "Guest" %}
<section class="write-review">
<h4>Write a Review</h4>
<form id="review-form">
<div class="rating-input">
<label>Rating:</label>
<select name="rating">
<option value="5">5 - Excellent</option>
<option value="4">4 - Good</option>
<option value="3">3 - Average</option>
<option value="2">2 - Poor</option>
<option value="1">1 - Terrible</option>
</select>
</div>
<textarea name="review" placeholder="Share your experience..."></textarea>
<button type="submit">Submit Review</button>
</form>
</section>
{% endif %}
Step 3: Add Review Submission Handler
Create whitelisted function:
@frappe.whitelist()
def submit_review(website_item, rating, review):
customer = get_customer_from_user()
review_doc = frappe.get_doc({
"doctype": "Item Review",
"website_item": website_item,
"customer": customer,
"rating": int(rating),
"review": review,
"published": 0 # Requires moderation
})
review_doc.insert()
return {"message": "Review submitted for moderation"}
How to Verify
- Enable reviews in settings
- View product page
- Submit review as logged-in user
- Verify review saved (as unpublished)
- Publish review from desk
- Verify appears on product page
---
Scenario 7: Stock Alert/Backorder Message
Goal
Custom message when item is out of stock.
Files to Touch
webshop/templates/webshop/website_item.htmlwebshop/public/js/product_page.js
Template Changes
{% set stock_info = get_web_item_qty_in_stock(doc.item_code, doc.website_warehouse) %}
{% if stock_info.in_stock %}
<div class="stock-status in-stock">
<i class="icon-check"></i> In Stock ({{ stock_info.stock_qty }} available)
</div>
<button class="btn btn-primary add-to-cart">Add to Cart</button>
{% elif doc.on_backorder %}
<div class="stock-status backorder">
<i class="icon-clock"></i> Backorder: Ships in 2-3 weeks
</div>
<button class="btn btn-warning add-to-cart">Pre-order</button>
{% else %}
<div class="stock-status out-of-stock">
<i class="icon-x"></i> Out of Stock
</div>
<button class="btn btn-secondary" disabled>Notify Me When Available</button>
{% endif %}
How to Verify
- Set item stock to 0
- View product page
- Verify "Out of Stock" message
- Check "on_backorder" checkbox
- Verify "Backorder" message appears
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_ExtensionPoints — Hooks and customization points
- Repo_comfac-hrms_CommonEdits — Common edits for comfac-hrms