Jump to content

Repo comfac-webshop CommonEdits: Difference between revisions

From Game in the Brain Wiki
"Repo analysis: comfac-hrms and comfac-webshop (14 pages)"
 
"Fix markdown code blocks → wikitext syntaxhighlight in Repo analysis pages"
 
Line 29: Line 29:
Find "fields" array and add:
Find "fields" array and add:


```json
<syntaxhighlight lang="json">
{
{
     "fieldname": "warranty_period",
     "fieldname": "warranty_period",
Line 37: Line 37:
     "insert_after": "brand"
     "insert_after": "brand"
}
}
```
</syntaxhighlight>


Run <code>bench migrate</code>
Run <code>bench migrate</code>
Line 45: Line 45:
Edit template <code>webshop/templates/webshop/website_item.html</code>:
Edit template <code>webshop/templates/webshop/website_item.html</code>:


```html
<syntaxhighlight lang="html">
{% if doc.warranty_period %}
{% if doc.warranty_period %}
<div class="product-warranty">
<div class="product-warranty">
Line 52: Line 52:
</div>
</div>
{% endif %}
{% endif %}
```
</syntaxhighlight>


=== How to Verify ===
=== How to Verify ===
Line 74: Line 74:
In checkout template, find address section and add:
In checkout template, find address section and add:


```html
<syntaxhighlight lang="html">
<div class="form-group">
<div class="form-group">
     <label>Delivery Instructions (Optional)</label>
     <label>Delivery Instructions (Optional)</label>
Line 80: Line 80:
               placeholder="e.g., Leave at guard house"></textarea>
               placeholder="e.g., Leave at guard house"></textarea>
</div>
</div>
```
</syntaxhighlight>


=== Step 2: Save to Quotation ===
=== Step 2: Save to Quotation ===
Line 86: Line 86:
In <code>cart.py</code>, find place_order or update_cart function:
In <code>cart.py</code>, find place_order or update_cart function:


```python
<syntaxhighlight lang="python">
@frappe.whitelist()
@frappe.whitelist()
def place_order(delivery_instructions=None):
def place_order(delivery_instructions=None):
Line 103: Line 103:
      
      
     return sales_order.name
     return sales_order.name
```
</syntaxhighlight>


=== Step 3: Add Custom Field to Quotation/Sales Order ===
=== Step 3: Add Custom Field to Quotation/Sales Order ===
Line 132: Line 132:
=== Step 1: Override Payment Request ===
=== Step 1: Override Payment Request ===


```python
<syntaxhighlight lang="python">
import requests
import requests
from erpnext.accounts.doctype.payment_request.payment_request import PaymentRequest
from erpnext.accounts.doctype.payment_request.payment_request import PaymentRequest
Line 158: Line 158:
         )
         )
         return response.json()["data"]["attributes"]["checkout_url"]
         return response.json()["data"]["attributes"]["checkout_url"]
```
</syntaxhighlight>


=== Step 2: Configure Payment Gateway ===
=== Step 2: Configure Payment Gateway ===
Line 171: Line 171:
In payment template:
In payment template:


```html
<syntaxhighlight lang="html">
{% if cart_settings.payment_gateway == "PayMongo" %}
{% if cart_settings.payment_gateway == "PayMongo" %}
     <button class="btn btn-primary" onclick="payWithPayMongo()">
     <button class="btn btn-primary" onclick="payWithPayMongo()">
Line 177: Line 177:
     </button>
     </button>
{% endif %}
{% endif %}
```
</syntaxhighlight>


=== How to Verify ===
=== How to Verify ===
Line 200: Line 200:
In query.py, find product listing query builder:
In query.py, find product listing query builder:


```python
<syntaxhighlight lang="python">
def get_product_list(filters=None, sort_by=None):
def get_product_list(filters=None, sort_by=None):
     query = build_base_query()
     query = build_base_query()
Line 217: Line 217:
      
      
     return query.run()
     return query.run()
```
</syntaxhighlight>


=== Step 2: Add UI Control ===
=== Step 2: Add UI Control ===
Line 223: Line 223:
In all-products template:
In all-products template:


```html
<syntaxhighlight lang="html">
<div class="sort-options">
<div class="sort-options">
     <select id="sort-select" onchange="sortProducts(this.value)">
     <select id="sort-select" onchange="sortProducts(this.value)">
Line 240: Line 240:
}
}
</script>
</script>
```
</syntaxhighlight>


=== How to Verify ===
=== How to Verify ===
Line 265: Line 265:


Subject:
Subject:
```
<syntaxhighlight lang="text">
Thank you for your order #{{ doc.name }} from ComFac!
Thank you for your order #{{ doc.name }} from ComFac!
```
</syntaxhighlight>


Body:
Body:
```html
<syntaxhighlight lang="html">
<h1>Hi {{ doc.customer_name }},</h1>
<h1>Hi {{ doc.customer_name }},</h1>
<p>Thank you for shopping with ComFac Corporation!</p>
<p>Thank you for shopping with ComFac Corporation!</p>
Line 285: Line 285:
     Track Order
     Track Order
</a></p>
</a></p>
```
</syntaxhighlight>


=== Method 2: Via Code ===
=== Method 2: Via Code ===
Line 291: Line 291:
Create <code>webshop/webshop/notification/order_confirmation/order_confirmation.json</code>:
Create <code>webshop/webshop/notification/order_confirmation/order_confirmation.json</code>:


```json
<syntaxhighlight lang="json">
{
{
     "name": "Order Confirmation - ComFac",
     "name": "Order Confirmation - ComFac",
Line 299: Line 299:
     "message": "...template HTML..."
     "message": "...template HTML..."
}
}
```
</syntaxhighlight>


=== How to Verify ===
=== How to Verify ===
Line 326: Line 326:
In product page template:
In product page template:


```html
<syntaxhighlight lang="html">
<section class="product-reviews">
<section class="product-reviews">
     <h3>Customer Reviews</h3>
     <h3>Customer Reviews</h3>
Line 372: Line 372:
</section>
</section>
{% endif %}
{% endif %}
```
</syntaxhighlight>


=== Step 3: Add Review Submission Handler ===
=== Step 3: Add Review Submission Handler ===
Line 378: Line 378:
Create whitelisted function:
Create whitelisted function:


```python
<syntaxhighlight lang="python">
@frappe.whitelist()
@frappe.whitelist()
def submit_review(website_item, rating, review):
def submit_review(website_item, rating, review):
Line 394: Line 394:
      
      
     return {"message": "Review submitted for moderation"}
     return {"message": "Review submitted for moderation"}
```
</syntaxhighlight>


=== How to Verify ===
=== How to Verify ===
Line 417: Line 417:
=== Template Changes ===
=== Template Changes ===


```html
<syntaxhighlight lang="html">
{% set stock_info = get_web_item_qty_in_stock(doc.item_code, doc.website_warehouse) %}
{% set stock_info = get_web_item_qty_in_stock(doc.item_code, doc.website_warehouse) %}


Line 436: Line 436:
     <button class="btn btn-secondary" disabled>Notify Me When Available</button>
     <button class="btn btn-secondary" disabled>Notify Me When Available</button>
{% endif %}
{% endif %}
```
</syntaxhighlight>


=== How to Verify ===
=== How to Verify ===

Latest revision as of 16:40, 9 March 2026

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

  1. webshop/webshop/doctype/website_item/website_item.json
  2. OR use Frappe Desk Customize Form

Method: Via Desk (Recommended)

  1. Go to Website Item list
  2. Click Customize
  3. Add field:
    • Label: Warranty Period
    • Fieldtype: Select
    • Options: 1 Year\n2 Years\n3 Years\n5 Years
    • Insert After: brand
  4. 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

  1. Edit a Website Item, set warranty period
  2. View product page
  3. Verify warranty displays correctly

---

Scenario 2: Customizing the Checkout Flow

Goal

Add "Delivery Instructions" field to checkout.

Files to Touch

  1. webshop/www/checkout/index.html
  2. webshop/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

  1. Add item to cart
  2. Go to checkout
  3. Enter delivery instructions
  4. Place order
  5. Check Sales Order for saved instructions

---

Scenario 3: Adding a New Payment Gateway

Goal

Integrate Philippine payment gateway (e.g., PayMongo).

Files to Touch

  1. webshop/webshop/doctype/override_doctype/payment_request.py
  2. webshop/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:

  1. Go to Payment Gateway Account
  2. Create new: PayMongo
  3. 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

  1. Configure PayMongo test credentials
  2. Add item to cart
  3. Checkout and select PayMongo
  4. Verify redirect to PayMongo checkout

---

Scenario 4: Custom Product Filter/Sort

Goal

Add "Sort by Price: Low to High" option.

Files to Touch

  1. webshop/webshop/product_data_engine/query.py
  2. webshop/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

  1. Visit /all-products
  2. Select different sort options
  3. Verify products reorder correctly

---

Scenario 5: Custom Email Template

Goal

Customize order confirmation email.

Files to Touch

  1. Frappe Desk → Email Template
  2. OR webshop/webshop/notification/order_confirmation/

Method 1: Via Desk

  1. Go to Email Template list
  2. Find Order Confirmation
  3. 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

  1. Place test order
  2. Check email received
  3. Verify custom template applied

---

Scenario 6: Adding Product Reviews

Goal

Enable and display customer reviews.

Files to Touch

  1. Frappe Desk → Webshop Settings
  2. 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

  1. Enable reviews in settings
  2. View product page
  3. Submit review as logged-in user
  4. Verify review saved (as unpublished)
  5. Publish review from desk
  6. Verify appears on product page

---

Scenario 7: Stock Alert/Backorder Message

Goal

Custom message when item is out of stock.

Files to Touch

  1. webshop/templates/webshop/website_item.html
  2. webshop/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

  1. Set item stock to 0
  2. View product page
  3. Verify "Out of Stock" message
  4. Check "on_backorder" checkbox
  5. Verify "Backorder" message appears