Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
773d1a0
feat: allow guest checkout in place_order
Feb 16, 2026
88cf468
refactor: rename app from webshop to shop
Feb 16, 2026
cb084a3
feat: implement guest checkout and manual shipping charges
Feb 16, 2026
3695a66
refactor: rename webshop to shop in all files
Feb 16, 2026
3c8a43b
fix: handle missing website item data in decorate_quotation_doc
Feb 16, 2026
b6ed040
fix: more robust check for web_item_data in decorate_quotation_doc
Feb 16, 2026
a7ee04b
feat: integrate shipping rules for guest checkout and fix cart rendering
Feb 16, 2026
ff6e0e9
fix: enable guest checkout by whitelisting methods and updating front…
Feb 16, 2026
36dc5dd
fix: ensure guests have permission to access their cart quotations an…
Feb 16, 2026
65a6ab4
fix: ensure all backend document fetches for guests use ignore_permis…
Feb 17, 2026
a819970
fix: whitelist dropdown and address methods for guests and refine JS …
Feb 17, 2026
b23fef1
feat: implement mobile signup via phone number and password
Feb 17, 2026
04a8b69
fix: bypass permission checks for Shop Settings and refine mobile signup
Feb 17, 2026
8e7d758
fix(revert): remove invalid ignore_permissions arg from get_cached_doc
Feb 17, 2026
5cee84a
chore: use standardized settings fetcher in cart.py
Feb 17, 2026
0bd38b8
fix: robust Shop Settings fetch for guests and add Guest role permiss…
Feb 17, 2026
4abc287
fix: remove all guest redirects and force guest customer linkage
Feb 17, 2026
d7e580a
feat: seamless guest-to-mobile signup flow for Add to Cart
Feb 17, 2026
a9b47ec
fix: call bind_add_to_cart_action and consolidate All Add to Cart red…
Feb 17, 2026
57a52ce
fix: redirect wishlist guests to mobile signup
Feb 17, 2026
c3e3798
fix: standardize JS namespaces and add debug logs for guest redirect
Feb 17, 2026
72c9d9a
fix: use Administrator context for mobile signup to bypass Guest perm…
Feb 17, 2026
c7e2031
fix: robust mobile signup with manual customer creation to avoid User…
Feb 17, 2026
ad5f053
fix: link new address to current party in add_new_address
Feb 17, 2026
bc78b29
feat: implement UPI static QR code payment flow
Feb 18, 2026
2915d14
refactor: include transaction reference in UPI QR code for better tra…
Feb 18, 2026
25916ad
feat: implement state-wise shipping rules
Feb 19, 2026
bc0d9e1
fix: add missing patch to patches.txt
Feb 19, 2026
edf43b3
fix: change state field to Data type to avoid Missing DocType error
Feb 19, 2026
39995b8
refactor: ensure shipping rules are automatically re-validated on add…
Feb 19, 2026
097a850
fix: ensure shipping rule and summary are refreshed on address change
Feb 19, 2026
d47298b
style: hide manual shipping method selector as selection is now autom…
Feb 19, 2026
cfae71d
feat: mobile-first UI overhaul with sticky bar, card layouts, and UPI…
Feb 19, 2026
bddc014
fix: improve mobile cart layout with proper flex card display for ite…
Feb 19, 2026
80fd236
fix: properly stack cart item rows on mobile with block display and c…
Feb 19, 2026
82b1159
fix: reduce no-image placeholder height and improve All Products mobi…
Feb 19, 2026
a7803c6
fix: correct list-row mobile layout - widen image col, stack button b…
Feb 19, 2026
785b9dc
fix: hide Go to Cart button by default, show only after Add to Cart i…
Feb 19, 2026
85ba282
fix: always hide Go to Cart on initial list render
Feb 19, 2026
6ecd9e2
fix: always show Products, Cart, and Wishlist in navbar
Feb 19, 2026
6117645
feat: add mobile bottom navigation bar with Home, Products, Cart, Wis…
Feb 19, 2026
089927e
fix: use frappe.db.get_single_value for UPI settings and add debug lo…
Feb 19, 2026
74360bb
fix: use ignore_permissions to dynamically load Sales Order on UPI pa…
Feb 19, 2026
289ac68
fix: always show order details on UPI page; separate order-not-found …
Feb 19, 2026
921502d
fix: mobile cart totals and shipping charges for guests; added state …
Feb 19, 2026
7b174b1
fix: resolve 500 error caused by indentation and logging
Feb 19, 2026
6590b33
fix: auto-set shipping address for logged-in users to ensure shipping…
Feb 20, 2026
2078f54
fix: reload quotation doc after auto-setting addresses to ensure UI r…
Feb 20, 2026
ea9ec0e
fix: robustness improvement for repeat orders - default shipping addr…
Feb 20, 2026
3c5fbf4
fix: explicit copy of shipping rule and taxes from quotation to sales…
Feb 20, 2026
46b3ff9
fix: remove manual tax copy loop from place_order to prevent crash, r…
Feb 20, 2026
e737344
fix: safely copy shipping address text and taxes to sales order to en…
Feb 20, 2026
9944acc
fix: safe address handling in get_cart_quotation to prevent 417 error…
Feb 20, 2026
534c1de
fix: remove tax copy loop again, but keep explicit address text copy …
Feb 20, 2026
c589482
fix: add cache busting to UPI redirect and debug logs to ensure fresh…
Feb 20, 2026
19c6f4f
feat: remove pay via upi app button as requested
Feb 20, 2026
48862cb
fix: add no_cache=1 for dynamic order number + make QR code static (U…
Feb 20, 2026
7b6fd9b
fix: rewrite UPI page to use AJAX for dynamic order data - bypasses a…
Feb 20, 2026
b9df7af
fix: shipping rule state priority + style I Have Paid button green
Feb 20, 2026
1722ead
feat: UPI payment confirmation - deep link button, transaction form, …
Feb 23, 2026
2195932
feat: auto-generate UPI reference ID, embed in deep link, auto-redire…
Feb 24, 2026
03f1fb0
fix: use Sales Order name as UPI reference instead of random ID, simp…
Feb 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions cleanup_rename.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

import os

target_dir = os.path.abspath("shop")

replacements = {
"webshop_settings": "shop_settings",
"Webshop": "Shop",
"webshop_cart": "shop_cart",
"webshop-web.bundle": "shop-web.bundle"
}

print(f"Scanning {target_dir}...")

for root, dirs, files in os.walk(target_dir):
for f_name in files:
if f_name.endswith(('.py', '.js', '.json', '.html', '.css', '.scss', '.md', '.txt')):
f_path = os.path.join(root, f_name)
try:
with open(f_path, 'r', encoding='utf-8') as f:
content = f.read()

new_content = content
for old, new in replacements.items():
new_content = new_content.replace(old, new)

if new_content != content:
print(f"Modifying content in {f_name}")
with open(f_path, 'w', encoding='utf-8') as f:
f.write(new_content)
except Exception as e:
print(f"Skipping {f_path}: {e}")
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[project]
name = "webshop"
name = "shop"
authors = [
{ name = "Frappe Technologies Pvt. Ltd.", email = "contact@frappe.io"}
]
Expand Down
62 changes: 62 additions & 0 deletions rename_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

import os

target_dir = os.path.abspath("shop")

# Content Replacements
replacements = {
"webshop.webshop": "shop.shop",
# 'app_name = "webshop"': 'app_name = "shop"', # Handled
"from webshop": "from shop",
"import webshop": "import shop",
'"module": "Webshop"': '"module": "Shop"',
"webshop.patches": "shop.patches",
"webshop-web.bundle.css": "shop-web.bundle.css",
"webshop-web.bundle.scss": "shop-web.bundle.scss",
"webshop_cart.scss": "shop_cart.scss",
# Javascript namespace
"frappe.provide(\"webshop.webshop": "frappe.provide(\"shop.shop",
"webshop.webshop.shopping_cart": "shop.shop.shopping_cart",
"webshop.webshop.": "shop.shop."
}

print(f"Scanning {target_dir}...")

# 1. Replace Content
for root, dirs, files in os.walk(target_dir):
for f_name in files:
if f_name.endswith(('.py', '.js', '.json', '.html', '.css', '.scss', '.md', '.txt')):
f_path = os.path.join(root, f_name)
try:
with open(f_path, 'r', encoding='utf-8') as f:
content = f.read()

new_content = content
for old, new in replacements.items():
new_content = new_content.replace(old, new)

if new_content != content:
print(f"Modifying content in {f_name}")
with open(f_path, 'w', encoding='utf-8') as f:
f.write(new_content)
except Exception as e:
print(f"Skipping {f_path}: {e}")

# 2. Rename Files and Directories
# Process bottom-up to handle children before parents
for root, dirs, files in os.walk(target_dir, topdown=False):
for f_name in files:
if "webshop" in f_name:
new_name = f_name.replace("webshop", "shop")
old_path = os.path.join(root, f_name)
new_path = os.path.join(root, new_name)
print(f"Renaming file {old_path} -> {new_path}")
os.rename(old_path, new_path)

for d_name in dirs:
if "webshop" in d_name:
new_name = d_name.replace("webshop", "shop")
old_path = os.path.join(root, d_name)
new_path = os.path.join(root, new_name)
print(f"Renaming directory {old_path} -> {new_path}")
os.rename(old_path, new_path)
File renamed without changes.
File renamed without changes.
78 changes: 78 additions & 0 deletions shop/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from . import __version__ as _version

app_name = "shop"
app_title = "Shop"
app_publisher = "Frappe Technologies Pvt. Ltd."
app_description = "Open Source eCommerce Platform"
app_email = "contact@frappe.io"
app_license = "GNU General Public License (v3)"
app_version = _version

required_apps = ["payments", "erpnext"]

web_include_css = "shop-web.bundle.css"

web_include_js = "web.bundle.js"

after_install = "shop.setup.install.after_install"
on_logout = "shop.shop.shopping_cart.utils.clear_cart_count"
on_session_creation = [
"shop.shop.utils.portal.update_debtors_account",
"shop.shop.shopping_cart.utils.set_cart_count",
]
update_website_context = [
"shop.shop.shopping_cart.utils.update_website_context",
]

website_generators = ["Website Item", "Item Group"]

override_doctype_class = {
"Payment Request": "shop.shop.doctype.override_doctype.payment_request.PaymentRequest",
"Item Group": "shop.shop.doctype.override_doctype.item_group.ShopItemGroup",
"Item": "shop.shop.doctype.override_doctype.item.ShopItem",
}

doctype_js = {
"Item": "public/js/override/item.js",
"Homepage": "public/js/override/homepage.js",
}

doc_events = {
"Item": {
"on_update": [
"shop.shop.crud_events.item.update_website_item.execute",
"shop.shop.crud_events.item.invalidate_item_variants_cache.execute",
],
"before_rename": [
"shop.shop.crud_events.item.validate_duplicate_website_item.execute",
],
"after_rename": [
"shop.shop.crud_events.item.invalidate_item_variants_cache.execute",
],
},
"Sales Taxes and Charges Template": {
"on_update": [
"shop.shop.doctype.shop_settings.shop_settings.validate_cart_settings",
],
},
"Quotation": {
"validate": [
"shop.shop.crud_events.quotation.validate_shopping_cart_items.execute",
],
},
"Price List": {
"validate": [
"shop.shop.crud_events.price_list.check_impact_on_cart.execute"
],
},
"Tax Rule": {
"validate": [
"shop.shop.crud_events.tax_rule.validate_use_for_cart.execute",
],
},
}

has_website_permission = {
"Website Item": "shop.shop.doctype.website_item.website_item.has_website_permission_for_website_item",
"Item Group": "shop.shop.doctype.website_item.website_item.has_website_permission_for_item_group"
}
1 change: 1 addition & 0 deletions shop/modules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Shop
9 changes: 9 additions & 0 deletions shop/patches.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[pre_model_sync]

[post_model_sync]

shop.patches.add_homepage_field #09-05-2024
shop.patches.enable_allow_to_guest_view_for_item_group
shop.patches.clear_cache_for_item_group_route
shop.patches.add_shipping_rule_state_field
shop.patches.add_upi_fields_to_sales_order
File renamed without changes.
6 changes: 6 additions & 0 deletions shop/patches/add_shipping_rule_state_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import frappe
from shop.setup.install import add_custom_fields

def execute():
frappe.reload_doc("shop", "doctype", "shipping_rule_state")
add_custom_fields()
46 changes: 46 additions & 0 deletions shop/patches/add_upi_fields_to_sales_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields

def execute():
"""Add UPI payment tracking fields to Sales Order."""
custom_fields = {
"Sales Order": [
{
"fieldname": "upi_payment_section",
"fieldtype": "Section Break",
"label": "UPI Payment Details",
"insert_after": "payment_schedule",
"collapsible": 1,
},
{
"fieldname": "upi_transaction_id",
"fieldtype": "Data",
"label": "UPI Transaction ID",
"insert_after": "upi_payment_section",
"read_only": 1,
},
{
"fieldname": "upi_payment_date",
"fieldtype": "Datetime",
"label": "UPI Payment Date",
"insert_after": "upi_transaction_id",
"read_only": 1,
},
{
"fieldname": "column_break_upi",
"fieldtype": "Column Break",
"insert_after": "upi_payment_date",
},
{
"fieldname": "upi_payment_status",
"fieldtype": "Select",
"label": "UPI Payment Status",
"options": "\nPending\nPaid",
"insert_after": "column_break_upi",
"read_only": 1,
"in_list_view": 1,
},
]
}

create_custom_fields(custom_fields)
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

import frappe

from webshop.webshop.doctype.website_item.website_item import make_website_item
from shop.shop.doctype.website_item.website_item import make_website_item


def execute():
"""
Convert all Item links to Website Item link values in
exisitng 'Item Card Group' Web Page Block data.
"""
frappe.reload_doc("webshop", "web_template", "item_card_group")
frappe.reload_doc("shop", "web_template", "item_card_group")

blocks = frappe.db.get_all(
"Web Page Block",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field

from webshop.webshop.utils.setup import has_ecommerce_fields
from shop.shop.utils.setup import has_ecommerce_fields

def execute():
"Add Field Filters, that are not standard fields in Website Item, as Custom Fields."
Expand Down Expand Up @@ -42,7 +42,7 @@ def get_table_multiselect_data(docfield):

return table_multiselect_data

settings_doctype = "E Commerce Settings" if has_ecommerce_fields() else "Webshop Settings"
settings_doctype = "E Commerce Settings" if has_ecommerce_fields() else "Shop Settings"

settings = frappe.get_doc(settings_doctype)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import frappe

from webshop.webshop.doctype.website_item.website_item import make_website_item
from shop.shop.doctype.website_item.website_item import make_website_item


def execute():
if frappe.get_all("Website Item", limit=1):
return

frappe.reload_doc("webshop", "doctype", "website_item")
frappe.reload_doc("webshop", "doctype", "website_item_tabbed_section")
frappe.reload_doc("webshop", "doctype", "website_offer")
frappe.reload_doc("webshop", "doctype", "recommended_items")
frappe.reload_doc("webshop", "doctype", "webshop_settings")
frappe.reload_doc("shop", "doctype", "website_item")
frappe.reload_doc("shop", "doctype", "website_item_tabbed_section")
frappe.reload_doc("shop", "doctype", "website_offer")
frappe.reload_doc("shop", "doctype", "recommended_items")
frappe.reload_doc("shop", "doctype", "shop_settings")
frappe.reload_doc("stock", "doctype", "item")

item_fields = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import frappe
from frappe.utils import cint

from webshop.webshop.utils.setup import has_ecommerce_fields
from shop.shop.utils.setup import has_ecommerce_fields

def execute():
frappe.reload_doc("webshop", "doctype", "webshop_settings")
frappe.reload_doc("shop", "doctype", "shop_settings")
frappe.reload_doc("portal", "doctype", "website_filter_field")
frappe.reload_doc("portal", "doctype", "website_attribute")

Expand Down Expand Up @@ -35,7 +35,7 @@ def execute():
"save_quotations_as_draft",
]

settings_doctype = "E Commerce Settings" if has_ecommerce_fields() else "Webshop Settings"
settings_doctype = "E Commerce Settings" if has_ecommerce_fields() else "Shop Settings"

settings = frappe.get_doc(settings_doctype)

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ $(() => {
primary_action: function() {
let data = d.get_values();
frappe.call({
method: "webshop.webshop.doctype.item_review.item_review.add_item_review",
method: "shop.shop.doctype.item_review.item_review.add_item_review",
args: {
web_item: $btn.attr('data-web-item'),
title: data.title,
Expand Down Expand Up @@ -66,7 +66,7 @@ $(() => {
let me = this;

frappe.call({
method: "webshop.webshop.doctype.item_review.item_review.get_item_reviews",
method: "shop.shop.doctype.item_review.item_review.get_item_reviews",
args: {
web_item: $btn.attr('data-web-item'),
start: me.start,
Expand Down
2 changes: 2 additions & 0 deletions shop/public/js/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if (!window.shop) window.shop = {}
if (!frappe.boot) frappe.boot = {}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ frappe.ui.form.on("Item", {
if (!frm.doc.published_in_website) {
frm.add_custom_button(__("Publish in Website"), function() {
frappe.call({
method: "webshop.webshop.doctype.website_item.website_item.make_website_item",
method: "shop.shop.doctype.website_item.website_item.make_website_item",
args: {
doc: frm.doc,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
webshop.ProductGrid = class {
shop.ProductGrid = class {
/* Options:
- items: Items
- settings: Webshop Settings
- settings: Shop Settings
- products_section: Products Wrapper
- preference: If preference is not grid view, render but hide
*/
Expand Down
Loading