From 773d1a0ea9ae48863b9868e611cdf76c5431b2db Mon Sep 17 00:00:00 2001 From: Balaji K Date: Mon, 16 Feb 2026 12:01:50 +0530 Subject: [PATCH 01/62] feat: allow guest checkout in place_order --- webshop/webshop/shopping_cart/cart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webshop/webshop/shopping_cart/cart.py b/webshop/webshop/shopping_cart/cart.py index f4ed155e42..9fd7555667 100644 --- a/webshop/webshop/shopping_cart/cart.py +++ b/webshop/webshop/shopping_cart/cart.py @@ -86,7 +86,7 @@ def get_billing_addresses(party=None): ] -@frappe.whitelist() +@frappe.whitelist(allow_guest=True) def place_order(): quotation = _get_cart_quotation() cart_settings = frappe.get_cached_doc("Webshop Settings") From 88cf468bfab4e9c2e6bfad772710084d38ea4e2a Mon Sep 17 00:00:00 2001 From: Balaji K Date: Mon, 16 Feb 2026 13:39:30 +0530 Subject: [PATCH 02/62] refactor: rename app from webshop to shop --- cleanup_rename.py | 32 +++++++ pyproject.toml | 2 +- rename_app.py | 62 ++++++++++++++ {webshop => shop}/__init__.py | 0 {webshop => shop}/config/__init__.py | 0 shop/hooks.py | 78 ++++++++++++++++++ shop/modules.txt | 1 + shop/patches.txt | 7 ++ {webshop => shop}/patches/__init__.py | 0 .../patches/add_homepage_field.py | 0 .../clear_cache_for_item_group_route.py | 0 ...ebsite_item_in_item_card_group_template.py | 2 +- ...py_custom_field_filters_to_website_item.py | 4 +- .../patches/create_website_items.py | 4 +- ...able_allow_to_guest_view_for_item_group.py | 0 .../fetch_thumbnail_in_website_items.py | 0 .../make_homepage_products_website_items.py | 0 .../patches/populate_e_commerce_settings.py | 6 +- .../patches/shopping_cart_to_ecommerce.py | 0 {webshop => shop}/public/.gitkeep | 0 .../public/images/cart-empty-state.png | Bin .../public/js/customer_reviews.js | 4 +- {webshop => shop}/public/js/init.js | 0 .../public/js/override/homepage.js | 0 {webshop => shop}/public/js/override/item.js | 2 +- .../public/js/product_ui/grid.js | 2 +- .../public/js/product_ui/list.js | 2 +- .../public/js/product_ui/search.js | 0 .../public/js/product_ui/views.js | 2 +- {webshop => shop}/public/js/shopping_cart.js | 16 ++-- {webshop => shop}/public/js/wishlist.js | 16 ++-- shop/public/scss/shop-web.bundle.scss | 1 + .../public/scss/shop_cart.scss | 0 {webshop => shop}/public/web.bundle.js | 0 {webshop => shop}/setup/install.py | 10 +-- {webshop/templates => shop/shop}/__init__.py | 0 {webshop/webshop => shop/shop}/api.py | 8 +- .../shop/crud_events}/__init__.py | 0 .../shop/crud_events/item}/__init__.py | 0 .../item/invalidate_item_variants_cache.py | 2 +- .../crud_events/item/update_website_item.py | 0 .../item/validate_duplicate_website_item.py | 0 .../shop/crud_events/price_list}/__init__.py | 0 .../price_list/check_impact_on_cart.py | 6 +- .../shop/crud_events/quotation}/__init__.py | 0 .../quotation/validate_shopping_cart_items.py | 4 +- .../shop/crud_events/tax_rule}/__init__.py | 0 .../tax_rule/validate_use_for_cart.py | 2 +- .../shop/doctype}/__init__.py | 0 .../homepage_featured_product}/__init__.py | 0 .../homepage_featured_product.json | 2 +- .../homepage_featured_product.py | 0 .../shop/doctype/item_review}/__init__.py | 0 .../shop}/doctype/item_review/item_review.js | 0 .../doctype/item_review/item_review.json | 2 +- .../shop}/doctype/item_review/item_review.py | 2 +- .../doctype/item_review/test_item_review.py | 14 ++-- .../doctype/override_doctype}/__init__.py | 0 .../shop}/doctype/override_doctype/item.py | 12 +-- .../doctype/override_doctype/item_group.py | 14 ++-- .../override_doctype/payment_request.py | 4 +- .../doctype/recommended_items}/__init__.py | 0 .../recommended_items/recommended_items.json | 2 +- .../recommended_items/recommended_items.py | 0 .../shop/doctype/shop_settings}/__init__.py | 0 .../doctype/shop_settings/shop_settings.js | 2 +- .../doctype/shop_settings/shop_settings.json | 4 +- .../doctype/shop_settings/shop_settings.py | 12 +-- .../shop_settings/test_shop_settings.py | 18 ++-- .../shop/doctype/website_item}/__init__.py | 0 .../website_item/templates/website_item.html | 0 .../templates/website_item_row.html | 0 .../doctype/website_item/test_website_item.py | 60 +++++++------- .../doctype/website_item/website_item.js | 4 +- .../doctype/website_item/website_item.json | 2 +- .../doctype/website_item/website_item.py | 18 ++-- .../doctype/website_item/website_item_list.js | 0 .../website_item_tabbed_section}/__init__.py | 0 .../website_item_tabbed_section.json | 2 +- .../website_item_tabbed_section.py | 0 .../shop/doctype/website_offer}/__init__.py | 0 .../doctype/website_offer/website_offer.json | 2 +- .../doctype/website_offer/website_offer.py | 0 .../shop/doctype/wishlist}/__init__.py | 0 .../shop}/doctype/wishlist/test_wishlist.py | 4 +- .../shop}/doctype/wishlist/wishlist.js | 0 .../shop}/doctype/wishlist/wishlist.json | 2 +- .../shop}/doctype/wishlist/wishlist.py | 0 .../shop/doctype/wishlist_item}/__init__.py | 0 .../doctype/wishlist_item/wishlist_item.json | 2 +- .../doctype/wishlist_item/wishlist_item.py | 0 .../webshop => shop/shop}/legacy_search.py | 0 .../shop}/product_data_engine/filters.py | 6 +- .../shop}/product_data_engine/query.py | 14 ++-- .../test_item_group_product_data_engine.py | 6 +- .../test_product_data_engine.py | 30 +++---- .../webshop => shop/shop}/redisearch_utils.py | 6 +- .../shop/shopping_cart}/__init__.py | 0 .../shop}/shopping_cart/cart.py | 16 ++-- .../shop}/shopping_cart/product_info.py | 8 +- .../shop}/shopping_cart/test_shopping_cart.py | 14 ++-- .../shop}/shopping_cart/utils.py | 4 +- .../shop/utils}/__init__.py | 0 .../webshop => shop/shop}/utils/portal.py | 4 +- .../webshop => shop/shop}/utils/product.py | 0 {webshop/webshop => shop/shop}/utils/setup.py | 0 .../shop/variant_selector}/__init__.py | 0 .../variant_selector/item_variants_cache.py | 2 +- .../variant_selector/test_variant_selector.py | 14 ++-- .../shop}/variant_selector/utils.py | 6 +- .../shop/web_template}/__init__.py | 0 .../web_template/hero_slider}/__init__.py | 0 .../web_template/hero_slider/hero_slider.html | 0 .../web_template/hero_slider/hero_slider.json | 2 +- .../web_template/item_card_group}/__init__.py | 0 .../item_card_group/item_card_group.html | 0 .../item_card_group/item_card_group.json | 2 +- .../web_template/product_card}/__init__.py | 0 .../product_card/product_card.html | 0 .../product_card/product_card.json | 2 +- .../product_category_cards}/__init__.py | 0 .../product_category_cards.html | 0 .../product_category_cards.json | 2 +- .../templates}/__init__.py | 0 .../templates/generators/item/item.html | 0 .../generators/item/item_add_to_cart.html | 4 +- .../generators/item/item_configure.html | 0 .../generators/item/item_configure.js | 6 +- .../generators/item/item_details.html | 2 +- .../templates/generators/item/item_image.html | 0 .../generators/item/item_inquiry.html | 0 .../templates/generators/item/item_inquiry.js | 2 +- .../generators/item/item_reviews.html | 2 +- .../generators/item/item_specifications.html | 0 .../templates/generators/item_group.html | 0 .../templates/includes/cart/address_card.html | 0 .../includes/cart/address_picker_card.html | 0 .../templates/includes/cart/cart_address.html | 6 +- .../includes/cart/cart_address_picker.html | 0 .../includes/cart/cart_dropdown.html | 0 .../templates/includes/cart/cart_items.html | 0 .../includes/cart/cart_items_dropdown.html | 0 .../includes/cart/cart_items_total.html | 0 .../templates/includes/cart/cart_macros.html | 0 .../includes/cart/cart_payment_summary.html | 0 .../templates/includes/cart/coupon_code.html | 0 .../templates/includes/cart/place_order.html | 0 .../templates/includes/macros.html | 0 .../includes/navbar/navbar_items.html | 2 +- .../includes/order/order_macros.html | 0 .../templates/includes/order/order_taxes.html | 0 .../templates/includes/product_page.js | 2 +- .../templates/pages}/__init__.py | 0 {webshop => shop}/templates/pages/cart.html | 0 {webshop => shop}/templates/pages/cart.js | 14 ++-- {webshop => shop}/templates/pages/cart.py | 2 +- .../templates/pages/customer_reviews.html | 0 .../templates/pages/customer_reviews.py | 6 +- {webshop => shop}/templates/pages/order.html | 0 {webshop => shop}/templates/pages/order.js | 2 +- {webshop => shop}/templates/pages/order.py | 4 +- .../templates/pages/product_search.html | 0 .../templates/pages/product_search.py | 6 +- .../templates/pages/wishlist.html | 0 {webshop => shop}/templates/pages/wishlist.py | 6 +- {webshop => shop}/www/__init__.py | 0 .../www/all-products/__init__.py | 0 {webshop => shop}/www/all-products/index.html | 0 {webshop => shop}/www/all-products/index.js | 4 +- {webshop => shop}/www/all-products/index.py | 4 +- .../www/all-products/not_found.html | 0 .../www/shop-by-category/__init__.py | 0 .../category_card_section.html | 0 .../www/shop-by-category/index.html | 0 .../www/shop-by-category/index.js | 0 .../www/shop-by-category/index.py | 2 +- webshop/hooks.py | 78 ------------------ webshop/modules.txt | 1 - webshop/patches.txt | 7 -- webshop/public/scss/webshop-web.bundle.scss | 1 - 180 files changed, 427 insertions(+), 333 deletions(-) create mode 100644 cleanup_rename.py create mode 100644 rename_app.py rename {webshop => shop}/__init__.py (100%) rename {webshop => shop}/config/__init__.py (100%) create mode 100644 shop/hooks.py create mode 100644 shop/modules.txt create mode 100644 shop/patches.txt rename {webshop => shop}/patches/__init__.py (100%) rename {webshop => shop}/patches/add_homepage_field.py (100%) rename {webshop => shop}/patches/clear_cache_for_item_group_route.py (100%) rename {webshop => shop}/patches/convert_to_website_item_in_item_card_group_template.py (94%) rename {webshop => shop}/patches/copy_custom_field_filters_to_website_item.py (96%) rename {webshop => shop}/patches/create_website_items.py (94%) rename {webshop => shop}/patches/enable_allow_to_guest_view_for_item_group.py (100%) rename {webshop => shop}/patches/fetch_thumbnail_in_website_items.py (100%) rename {webshop => shop}/patches/make_homepage_products_website_items.py (100%) rename {webshop => shop}/patches/populate_e_commerce_settings.py (92%) rename {webshop => shop}/patches/shopping_cart_to_ecommerce.py (100%) rename {webshop => shop}/public/.gitkeep (100%) rename {webshop => shop}/public/images/cart-empty-state.png (100%) rename {webshop => shop}/public/js/customer_reviews.js (95%) rename {webshop => shop}/public/js/init.js (100%) rename {webshop => shop}/public/js/override/homepage.js (100%) rename {webshop => shop}/public/js/override/item.js (92%) rename {webshop => shop}/public/js/product_ui/grid.js (99%) rename {webshop => shop}/public/js/product_ui/list.js (99%) rename {webshop => shop}/public/js/product_ui/search.js (100%) rename {webshop => shop}/public/js/product_ui/views.js (99%) rename {webshop => shop}/public/js/shopping_cart.js (91%) rename {webshop => shop}/public/js/wishlist.js (91%) create mode 100644 shop/public/scss/shop-web.bundle.scss rename webshop/public/scss/webshop_cart.scss => shop/public/scss/shop_cart.scss (100%) rename {webshop => shop}/public/web.bundle.js (100%) rename {webshop => shop}/setup/install.py (95%) rename {webshop/templates => shop/shop}/__init__.py (100%) rename {webshop/webshop => shop/shop}/api.py (87%) rename {webshop/templates/pages => shop/shop/crud_events}/__init__.py (100%) rename {webshop/webshop => shop/shop/crud_events/item}/__init__.py (100%) rename {webshop/webshop => shop/shop}/crud_events/item/invalidate_item_variants_cache.py (90%) rename {webshop/webshop => shop/shop}/crud_events/item/update_website_item.py (100%) rename {webshop/webshop => shop/shop}/crud_events/item/validate_duplicate_website_item.py (100%) rename {webshop/webshop/crud_events => shop/shop/crud_events/price_list}/__init__.py (100%) rename {webshop/webshop => shop/shop}/crud_events/price_list/check_impact_on_cart.py (67%) rename {webshop/webshop/crud_events/item => shop/shop/crud_events/quotation}/__init__.py (100%) rename {webshop/webshop => shop/shop}/crud_events/quotation/validate_shopping_cart_items.py (82%) rename {webshop/webshop/crud_events/price_list => shop/shop/crud_events/tax_rule}/__init__.py (100%) rename {webshop/webshop => shop/shop}/crud_events/tax_rule/validate_use_for_cart.py (89%) rename {webshop/webshop/crud_events/quotation => shop/shop/doctype}/__init__.py (100%) rename {webshop/webshop/crud_events/tax_rule => shop/shop/doctype/homepage_featured_product}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/homepage_featured_product/homepage_featured_product.json (98%) rename {webshop/webshop => shop/shop}/doctype/homepage_featured_product/homepage_featured_product.py (100%) rename {webshop/webshop/doctype => shop/shop/doctype/item_review}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/item_review/item_review.js (100%) rename {webshop/webshop => shop/shop}/doctype/item_review/item_review.json (99%) rename {webshop/webshop => shop/shop}/doctype/item_review/item_review.py (98%) rename {webshop/webshop => shop/shop}/doctype/item_review/test_item_review.py (87%) rename {webshop/webshop/doctype/homepage_featured_product => shop/shop/doctype/override_doctype}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/override_doctype/item.py (82%) rename {webshop/webshop => shop/shop}/doctype/override_doctype/item_group.py (92%) rename {webshop/webshop => shop/shop}/doctype/override_doctype/payment_request.py (91%) rename {webshop/webshop/doctype/item_review => shop/shop/doctype/recommended_items}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/recommended_items/recommended_items.json (98%) rename {webshop/webshop => shop/shop}/doctype/recommended_items/recommended_items.py (100%) rename {webshop/webshop/doctype/override_doctype => shop/shop/doctype/shop_settings}/__init__.py (100%) rename webshop/webshop/doctype/webshop_settings/webshop_settings.js => shop/shop/doctype/shop_settings/shop_settings.js (97%) rename webshop/webshop/doctype/webshop_settings/webshop_settings.json => shop/shop/doctype/shop_settings/shop_settings.json (99%) rename webshop/webshop/doctype/webshop_settings/webshop_settings.py => shop/shop/doctype/shop_settings/shop_settings.py (94%) rename webshop/webshop/doctype/webshop_settings/test_webshop_settings.py => shop/shop/doctype/shop_settings/test_shop_settings.py (67%) rename {webshop/webshop/doctype/recommended_items => shop/shop/doctype/website_item}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/website_item/templates/website_item.html (100%) rename {webshop/webshop => shop/shop}/doctype/website_item/templates/website_item_row.html (100%) rename {webshop/webshop => shop/shop}/doctype/website_item/test_website_item.py (90%) rename {webshop/webshop => shop/shop}/doctype/website_item/website_item.js (88%) rename {webshop/webshop => shop/shop}/doctype/website_item/website_item.json (99%) rename {webshop/webshop => shop/shop}/doctype/website_item/website_item.py (96%) rename {webshop/webshop => shop/shop}/doctype/website_item/website_item_list.js (100%) rename {webshop/webshop/doctype/webshop_settings => shop/shop/doctype/website_item_tabbed_section}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/website_item_tabbed_section/website_item_tabbed_section.json (96%) rename {webshop/webshop => shop/shop}/doctype/website_item_tabbed_section/website_item_tabbed_section.py (100%) rename {webshop/webshop/doctype/website_item => shop/shop/doctype/website_offer}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/website_offer/website_offer.json (97%) rename {webshop/webshop => shop/shop}/doctype/website_offer/website_offer.py (100%) rename {webshop/webshop/doctype/website_item_tabbed_section => shop/shop/doctype/wishlist}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/wishlist/test_wishlist.py (95%) rename {webshop/webshop => shop/shop}/doctype/wishlist/wishlist.js (100%) rename {webshop/webshop => shop/shop}/doctype/wishlist/wishlist.json (98%) rename {webshop/webshop => shop/shop}/doctype/wishlist/wishlist.py (100%) rename {webshop/webshop/doctype/website_offer => shop/shop/doctype/wishlist_item}/__init__.py (100%) rename {webshop/webshop => shop/shop}/doctype/wishlist_item/wishlist_item.json (99%) rename {webshop/webshop => shop/shop}/doctype/wishlist_item/wishlist_item.py (100%) rename {webshop/webshop => shop/shop}/legacy_search.py (100%) rename {webshop/webshop => shop/shop}/product_data_engine/filters.py (95%) rename {webshop/webshop => shop/shop}/product_data_engine/query.py (95%) rename {webshop/webshop => shop/shop}/product_data_engine/test_item_group_product_data_engine.py (96%) rename {webshop/webshop => shop/shop}/product_data_engine/test_product_data_engine.py (92%) rename {webshop/webshop => shop/shop}/redisearch_utils.py (96%) rename {webshop/webshop/doctype/wishlist => shop/shop/shopping_cart}/__init__.py (100%) rename {webshop/webshop => shop/shop}/shopping_cart/cart.py (97%) rename {webshop/webshop => shop/shop}/shopping_cart/product_info.py (90%) rename {webshop/webshop => shop/shop}/shopping_cart/test_shopping_cart.py (96%) rename {webshop/webshop => shop/shop}/shopping_cart/utils.py (89%) rename {webshop/webshop/doctype/wishlist_item => shop/shop/utils}/__init__.py (100%) rename {webshop/webshop => shop/shop}/utils/portal.py (90%) rename {webshop/webshop => shop/shop}/utils/product.py (100%) rename {webshop/webshop => shop/shop}/utils/setup.py (100%) rename {webshop/webshop/shopping_cart => shop/shop/variant_selector}/__init__.py (100%) rename {webshop/webshop => shop/shop}/variant_selector/item_variants_cache.py (98%) rename {webshop/webshop => shop/shop}/variant_selector/test_variant_selector.py (89%) rename {webshop/webshop => shop/shop}/variant_selector/utils.py (97%) rename {webshop/webshop/utils => shop/shop/web_template}/__init__.py (100%) rename {webshop/webshop/variant_selector => shop/shop/web_template/hero_slider}/__init__.py (100%) rename {webshop/webshop => shop/shop}/web_template/hero_slider/hero_slider.html (100%) rename {webshop/webshop => shop/shop}/web_template/hero_slider/hero_slider.json (99%) rename {webshop/webshop/web_template => shop/shop/web_template/item_card_group}/__init__.py (100%) rename {webshop/webshop => shop/shop}/web_template/item_card_group/item_card_group.html (100%) rename {webshop/webshop => shop/shop}/web_template/item_card_group/item_card_group.json (99%) rename {webshop/webshop/web_template/hero_slider => shop/shop/web_template/product_card}/__init__.py (100%) rename {webshop/webshop => shop/shop}/web_template/product_card/product_card.html (100%) rename {webshop/webshop => shop/shop}/web_template/product_card/product_card.json (96%) rename {webshop/webshop/web_template/item_card_group => shop/shop/web_template/product_category_cards}/__init__.py (100%) rename {webshop/webshop => shop/shop}/web_template/product_category_cards/product_category_cards.html (100%) rename {webshop/webshop => shop/shop}/web_template/product_category_cards/product_category_cards.json (98%) rename {webshop/webshop/web_template/product_card => shop/templates}/__init__.py (100%) rename {webshop => shop}/templates/generators/item/item.html (100%) rename {webshop => shop}/templates/generators/item/item_add_to_cart.html (98%) rename {webshop => shop}/templates/generators/item/item_configure.html (100%) rename {webshop => shop}/templates/generators/item/item_configure.js (97%) rename {webshop => shop}/templates/generators/item/item_details.html (97%) rename {webshop => shop}/templates/generators/item/item_image.html (100%) rename {webshop => shop}/templates/generators/item/item_inquiry.html (100%) rename {webshop => shop}/templates/generators/item/item_inquiry.js (94%) rename {webshop => shop}/templates/generators/item/item_reviews.html (96%) rename {webshop => shop}/templates/generators/item/item_specifications.html (100%) rename {webshop => shop}/templates/generators/item_group.html (100%) rename {webshop => shop}/templates/includes/cart/address_card.html (100%) rename {webshop => shop}/templates/includes/cart/address_picker_card.html (100%) rename {webshop => shop}/templates/includes/cart/cart_address.html (96%) rename {webshop => shop}/templates/includes/cart/cart_address_picker.html (100%) rename {webshop => shop}/templates/includes/cart/cart_dropdown.html (100%) rename {webshop => shop}/templates/includes/cart/cart_items.html (100%) rename {webshop => shop}/templates/includes/cart/cart_items_dropdown.html (100%) rename {webshop => shop}/templates/includes/cart/cart_items_total.html (100%) rename {webshop => shop}/templates/includes/cart/cart_macros.html (100%) rename {webshop => shop}/templates/includes/cart/cart_payment_summary.html (100%) rename {webshop => shop}/templates/includes/cart/coupon_code.html (100%) rename {webshop => shop}/templates/includes/cart/place_order.html (100%) rename {webshop => shop}/templates/includes/macros.html (100%) rename {webshop => shop}/templates/includes/navbar/navbar_items.html (89%) rename {webshop => shop}/templates/includes/order/order_macros.html (100%) rename {webshop => shop}/templates/includes/order/order_taxes.html (100%) rename {webshop => shop}/templates/includes/product_page.js (98%) rename {webshop/webshop/web_template/product_category_cards => shop/templates/pages}/__init__.py (100%) rename {webshop => shop}/templates/pages/cart.html (100%) rename {webshop => shop}/templates/pages/cart.js (93%) rename {webshop => shop}/templates/pages/cart.py (78%) rename {webshop => shop}/templates/pages/customer_reviews.html (100%) rename {webshop => shop}/templates/pages/customer_reviews.py (73%) rename {webshop => shop}/templates/pages/order.html (100%) rename {webshop => shop}/templates/pages/order.js (97%) rename {webshop => shop}/templates/pages/order.py (92%) rename {webshop => shop}/templates/pages/product_search.html (100%) rename {webshop => shop}/templates/pages/product_search.py (94%) rename {webshop => shop}/templates/pages/wishlist.html (100%) rename {webshop => shop}/templates/pages/wishlist.py (91%) rename {webshop => shop}/www/__init__.py (100%) rename {webshop => shop}/www/all-products/__init__.py (100%) rename {webshop => shop}/www/all-products/index.html (100%) rename {webshop => shop}/www/all-products/index.js (82%) rename {webshop => shop}/www/all-products/index.py (72%) rename {webshop => shop}/www/all-products/not_found.html (100%) rename {webshop => shop}/www/shop-by-category/__init__.py (100%) rename {webshop => shop}/www/shop-by-category/category_card_section.html (100%) rename {webshop => shop}/www/shop-by-category/index.html (100%) rename {webshop => shop}/www/shop-by-category/index.js (100%) rename {webshop => shop}/www/shop-by-category/index.py (98%) delete mode 100644 webshop/hooks.py delete mode 100644 webshop/modules.txt delete mode 100644 webshop/patches.txt delete mode 100644 webshop/public/scss/webshop-web.bundle.scss diff --git a/cleanup_rename.py b/cleanup_rename.py new file mode 100644 index 0000000000..eb5eb93025 --- /dev/null +++ b/cleanup_rename.py @@ -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}") diff --git a/pyproject.toml b/pyproject.toml index acc3fbe02d..446f3b0163 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "webshop" +name = "shop" authors = [ { name = "Frappe Technologies Pvt. Ltd.", email = "contact@frappe.io"} ] diff --git a/rename_app.py b/rename_app.py new file mode 100644 index 0000000000..c4e429be6f --- /dev/null +++ b/rename_app.py @@ -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) diff --git a/webshop/__init__.py b/shop/__init__.py similarity index 100% rename from webshop/__init__.py rename to shop/__init__.py diff --git a/webshop/config/__init__.py b/shop/config/__init__.py similarity index 100% rename from webshop/config/__init__.py rename to shop/config/__init__.py diff --git a/shop/hooks.py b/shop/hooks.py new file mode 100644 index 0000000000..679b58157c --- /dev/null +++ b/shop/hooks.py @@ -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" +} diff --git a/shop/modules.txt b/shop/modules.txt new file mode 100644 index 0000000000..fc0949ee69 --- /dev/null +++ b/shop/modules.txt @@ -0,0 +1 @@ +Shop \ No newline at end of file diff --git a/shop/patches.txt b/shop/patches.txt new file mode 100644 index 0000000000..746b2d13d7 --- /dev/null +++ b/shop/patches.txt @@ -0,0 +1,7 @@ +[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 \ No newline at end of file diff --git a/webshop/patches/__init__.py b/shop/patches/__init__.py similarity index 100% rename from webshop/patches/__init__.py rename to shop/patches/__init__.py diff --git a/webshop/patches/add_homepage_field.py b/shop/patches/add_homepage_field.py similarity index 100% rename from webshop/patches/add_homepage_field.py rename to shop/patches/add_homepage_field.py diff --git a/webshop/patches/clear_cache_for_item_group_route.py b/shop/patches/clear_cache_for_item_group_route.py similarity index 100% rename from webshop/patches/clear_cache_for_item_group_route.py rename to shop/patches/clear_cache_for_item_group_route.py diff --git a/webshop/patches/convert_to_website_item_in_item_card_group_template.py b/shop/patches/convert_to_website_item_in_item_card_group_template.py similarity index 94% rename from webshop/patches/convert_to_website_item_in_item_card_group_template.py rename to shop/patches/convert_to_website_item_in_item_card_group_template.py index 40ae1979f9..3182484fe7 100644 --- a/webshop/patches/convert_to_website_item_in_item_card_group_template.py +++ b/shop/patches/convert_to_website_item_in_item_card_group_template.py @@ -3,7 +3,7 @@ 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(): diff --git a/webshop/patches/copy_custom_field_filters_to_website_item.py b/shop/patches/copy_custom_field_filters_to_website_item.py similarity index 96% rename from webshop/patches/copy_custom_field_filters_to_website_item.py rename to shop/patches/copy_custom_field_filters_to_website_item.py index 12157cc292..d667b893bb 100644 --- a/webshop/patches/copy_custom_field_filters_to_website_item.py +++ b/shop/patches/copy_custom_field_filters_to_website_item.py @@ -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." @@ -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) diff --git a/webshop/patches/create_website_items.py b/shop/patches/create_website_items.py similarity index 94% rename from webshop/patches/create_website_items.py rename to shop/patches/create_website_items.py index cdec364da2..008eb700e4 100644 --- a/webshop/patches/create_website_items.py +++ b/shop/patches/create_website_items.py @@ -1,6 +1,6 @@ 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(): @@ -11,7 +11,7 @@ def execute(): 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("webshop", "doctype", "shop_settings") frappe.reload_doc("stock", "doctype", "item") item_fields = [ diff --git a/webshop/patches/enable_allow_to_guest_view_for_item_group.py b/shop/patches/enable_allow_to_guest_view_for_item_group.py similarity index 100% rename from webshop/patches/enable_allow_to_guest_view_for_item_group.py rename to shop/patches/enable_allow_to_guest_view_for_item_group.py diff --git a/webshop/patches/fetch_thumbnail_in_website_items.py b/shop/patches/fetch_thumbnail_in_website_items.py similarity index 100% rename from webshop/patches/fetch_thumbnail_in_website_items.py rename to shop/patches/fetch_thumbnail_in_website_items.py diff --git a/webshop/patches/make_homepage_products_website_items.py b/shop/patches/make_homepage_products_website_items.py similarity index 100% rename from webshop/patches/make_homepage_products_website_items.py rename to shop/patches/make_homepage_products_website_items.py diff --git a/webshop/patches/populate_e_commerce_settings.py b/shop/patches/populate_e_commerce_settings.py similarity index 92% rename from webshop/patches/populate_e_commerce_settings.py rename to shop/patches/populate_e_commerce_settings.py index f5fa326964..f5baeb908d 100644 --- a/webshop/patches/populate_e_commerce_settings.py +++ b/shop/patches/populate_e_commerce_settings.py @@ -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("webshop", "doctype", "shop_settings") frappe.reload_doc("portal", "doctype", "website_filter_field") frappe.reload_doc("portal", "doctype", "website_attribute") @@ -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) diff --git a/webshop/patches/shopping_cart_to_ecommerce.py b/shop/patches/shopping_cart_to_ecommerce.py similarity index 100% rename from webshop/patches/shopping_cart_to_ecommerce.py rename to shop/patches/shopping_cart_to_ecommerce.py diff --git a/webshop/public/.gitkeep b/shop/public/.gitkeep similarity index 100% rename from webshop/public/.gitkeep rename to shop/public/.gitkeep diff --git a/webshop/public/images/cart-empty-state.png b/shop/public/images/cart-empty-state.png similarity index 100% rename from webshop/public/images/cart-empty-state.png rename to shop/public/images/cart-empty-state.png diff --git a/webshop/public/js/customer_reviews.js b/shop/public/js/customer_reviews.js similarity index 95% rename from webshop/public/js/customer_reviews.js rename to shop/public/js/customer_reviews.js index bbef63883e..9168df0110 100644 --- a/webshop/public/js/customer_reviews.js +++ b/shop/public/js/customer_reviews.js @@ -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, @@ -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, diff --git a/webshop/public/js/init.js b/shop/public/js/init.js similarity index 100% rename from webshop/public/js/init.js rename to shop/public/js/init.js diff --git a/webshop/public/js/override/homepage.js b/shop/public/js/override/homepage.js similarity index 100% rename from webshop/public/js/override/homepage.js rename to shop/public/js/override/homepage.js diff --git a/webshop/public/js/override/item.js b/shop/public/js/override/item.js similarity index 92% rename from webshop/public/js/override/item.js rename to shop/public/js/override/item.js index e61f122209..7c4afaf2da 100644 --- a/webshop/public/js/override/item.js +++ b/shop/public/js/override/item.js @@ -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, }, diff --git a/webshop/public/js/product_ui/grid.js b/shop/public/js/product_ui/grid.js similarity index 99% rename from webshop/public/js/product_ui/grid.js rename to shop/public/js/product_ui/grid.js index 0212d823a2..72b27c197c 100644 --- a/webshop/public/js/product_ui/grid.js +++ b/shop/public/js/product_ui/grid.js @@ -1,7 +1,7 @@ webshop.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 */ diff --git a/webshop/public/js/product_ui/list.js b/shop/public/js/product_ui/list.js similarity index 99% rename from webshop/public/js/product_ui/list.js rename to shop/public/js/product_ui/list.js index b4df29d8f2..d509105872 100644 --- a/webshop/public/js/product_ui/list.js +++ b/shop/public/js/product_ui/list.js @@ -1,7 +1,7 @@ webshop.ProductList = class { /* Options: - items: Items - - settings: Webshop Settings + - settings: Shop Settings - products_section: Products Wrapper - preference: If preference is not list view, render but hide */ diff --git a/webshop/public/js/product_ui/search.js b/shop/public/js/product_ui/search.js similarity index 100% rename from webshop/public/js/product_ui/search.js rename to shop/public/js/product_ui/search.js diff --git a/webshop/public/js/product_ui/views.js b/shop/public/js/product_ui/views.js similarity index 99% rename from webshop/public/js/product_ui/views.js rename to shop/public/js/product_ui/views.js index 3863ff8c74..6dd81d4680 100644 --- a/webshop/public/js/product_ui/views.js +++ b/shop/public/js/product_ui/views.js @@ -45,7 +45,7 @@ webshop.ProductView = class { this.disable_view_toggler(true); frappe.call({ - method: "webshop.webshop.api.get_product_filter_data", + method: "shop.shop.api.get_product_filter_data", args: { query_args: args }, diff --git a/webshop/public/js/shopping_cart.js b/shop/public/js/shopping_cart.js similarity index 91% rename from webshop/public/js/shopping_cart.js rename to shop/public/js/shopping_cart.js index 82c8199598..6a7958148b 100644 --- a/webshop/public/js/shopping_cart.js +++ b/shop/public/js/shopping_cart.js @@ -2,8 +2,8 @@ // License: GNU General Public License v3. See license.txt // shopping cart -frappe.provide("webshop.webshop.shopping_cart"); -var shopping_cart = webshop.webshop.shopping_cart; +frappe.provide("shop.shop.shopping_cart"); +var shopping_cart = shop.shop.shopping_cart; var getParams = function (url) { var params = []; @@ -63,7 +63,7 @@ $.extend(shopping_cart, { $(".shopping-cart").on('shown.bs.dropdown', function() { if (!$('.shopping-cart-menu .cart-container').length) { return frappe.call({ - method: 'webshop.webshop.shopping_cart.cart.get_shopping_cart_menu', + method: 'shop.shop.shopping_cart.cart.get_shopping_cart_menu', callback: function(r) { if (r.message) { $('.shopping-cart-menu').html(r.message); @@ -79,14 +79,14 @@ $.extend(shopping_cart, { if (localStorage) { localStorage.setItem("last_visited", window.location.pathname); } - frappe.call('webshop.webshop.api.get_guest_redirect_on_action').then((res) => { + frappe.call('shop.shop.api.get_guest_redirect_on_action').then((res) => { window.location.href = res.message || "/login"; }); } else { shopping_cart.freeze(); return frappe.call({ type: "POST", - method: "webshop.webshop.shopping_cart.cart.update_cart", + method: "shop.shop.shopping_cart.cart.update_cart", args: { item_code: opts.item_code, qty: opts.qty, @@ -175,7 +175,7 @@ $.extend(shopping_cart, { show_cart_navbar: function () { frappe.call({ - method: "webshop.webshop.doctype.webshop_settings.webshop_settings.is_cart_enabled", + method: "shop.shop.doctype.shop_settings.shop_settings.is_cart_enabled", callback: function(r) { $(".shopping-cart").toggleClass('hidden', r.message ? false : true); } @@ -196,7 +196,7 @@ $.extend(shopping_cart, { if (localStorage) { localStorage.setItem("last_visited", window.location.pathname); } - frappe.call('webshop.webshop.api.get_guest_redirect_on_action').then((res) => { + frappe.call('shop.shop.api.get_guest_redirect_on_action').then((res) => { window.location.href = res.message || "/login"; }); return; @@ -209,7 +209,7 @@ $.extend(shopping_cart, { $btn.parent().find('.cart-indicator').removeClass('hidden'); const item_code = $btn.data('item-code'); - webshop.webshop.shopping_cart.update_cart({ + shop.shop.shopping_cart.update_cart({ item_code, qty: 1 }); diff --git a/webshop/public/js/wishlist.js b/shop/public/js/wishlist.js similarity index 91% rename from webshop/public/js/wishlist.js rename to shop/public/js/wishlist.js index c0aa18ba49..1484a16c31 100644 --- a/webshop/public/js/wishlist.js +++ b/shop/public/js/wishlist.js @@ -1,8 +1,8 @@ -frappe.provide("webshop.webshop.wishlist"); -var wishlist = webshop.webshop.wishlist; +frappe.provide("shop.shop.wishlist"); +var wishlist = shop.shop.wishlist; -frappe.provide("webshop.webshop.shopping_cart"); -var shopping_cart = webshop.webshop.shopping_cart; +frappe.provide("shop.shop.shopping_cart"); +var shopping_cart = shop.shop.shopping_cart; $.extend(wishlist, { set_wishlist_count: function(animate=false) { @@ -100,7 +100,7 @@ $.extend(wishlist, { } let success_action = function() { - webshop.webshop.wishlist.set_wishlist_count(true); + shop.shop.wishlist.set_wishlist_count(true); }; if ($wish_icon.hasClass('wished')) { @@ -146,9 +146,9 @@ $.extend(wishlist, { } this.redirect_guest(); } else { - let method = "webshop.webshop.doctype.wishlist.wishlist.add_to_wishlist"; + let method = "shop.shop.doctype.wishlist.wishlist.add_to_wishlist"; if (action === "remove") { - method = "webshop.webshop.doctype.wishlist.wishlist.remove_from_wishlist"; + method = "shop.shop.doctype.wishlist.wishlist.remove_from_wishlist"; } frappe.call({ @@ -174,7 +174,7 @@ $.extend(wishlist, { }, redirect_guest() { - frappe.call('webshop.webshop.api.get_guest_redirect_on_action').then((res) => { + frappe.call('shop.shop.api.get_guest_redirect_on_action').then((res) => { window.location.href = res.message || "/login"; }); }, diff --git a/shop/public/scss/shop-web.bundle.scss b/shop/public/scss/shop-web.bundle.scss new file mode 100644 index 0000000000..27cf0f4e9f --- /dev/null +++ b/shop/public/scss/shop-web.bundle.scss @@ -0,0 +1 @@ +@import "./shop_cart"; \ No newline at end of file diff --git a/webshop/public/scss/webshop_cart.scss b/shop/public/scss/shop_cart.scss similarity index 100% rename from webshop/public/scss/webshop_cart.scss rename to shop/public/scss/shop_cart.scss diff --git a/webshop/public/web.bundle.js b/shop/public/web.bundle.js similarity index 100% rename from webshop/public/web.bundle.js rename to shop/public/web.bundle.js diff --git a/webshop/setup/install.py b/shop/setup/install.py similarity index 95% rename from webshop/setup/install.py rename to shop/setup/install.py index bde3f0f267..f7b28249cc 100644 --- a/webshop/setup/install.py +++ b/shop/setup/install.py @@ -4,7 +4,7 @@ from frappe import _ from frappe.custom.doctype.custom_field.custom_field import create_custom_fields -from webshop.webshop.utils.setup import has_ecommerce_fields +from shop.shop.utils.setup import has_ecommerce_fields def after_install(): run_patches() @@ -20,12 +20,12 @@ def copy_from_ecommerce_settings(): if not has_ecommerce_fields(): return - frappe.reload_doc("webshop", "doctype", "webshop_settings") + frappe.reload_doc("webshop", "doctype", "shop_settings") qb = frappe.qb table = frappe.qb.Table("tabSingles") old_doctype = "E Commerce Settings" - new_doctype = "Webshop Settings" + new_doctype = "Shop Settings" entries = ( qb.from_(table) @@ -211,7 +211,7 @@ def navbar_add_products_link(): def say_thanks(): - click.secho("Thank you for installing Frappe Webshop!", color="green") + click.secho("Thank you for installing Frappe Shop!", color="green") patches = [ @@ -232,7 +232,7 @@ def run_patches(): try: for patch in patches: - frappe.get_attr(f"webshop.patches.{patch}.execute")() + frappe.get_attr(f"shop.patches.{patch}.execute")() finally: frappe.flags.in_patch = False diff --git a/webshop/templates/__init__.py b/shop/shop/__init__.py similarity index 100% rename from webshop/templates/__init__.py rename to shop/shop/__init__.py diff --git a/webshop/webshop/api.py b/shop/shop/api.py similarity index 87% rename from webshop/webshop/api.py rename to shop/shop/api.py index 82650d868d..5082df9228 100644 --- a/webshop/webshop/api.py +++ b/shop/shop/api.py @@ -7,9 +7,9 @@ import frappe from frappe.utils import cint -from webshop.webshop.product_data_engine.filters import ProductFiltersBuilder -from webshop.webshop.product_data_engine.query import ProductQuery -from webshop.webshop.doctype.override_doctype.item_group import get_child_groups_for_website +from shop.shop.product_data_engine.filters import ProductFiltersBuilder +from shop.shop.product_data_engine.query import ProductQuery +from shop.shop.doctype.override_doctype.item_group import get_child_groups_for_website @frappe.whitelist(allow_guest=True) @@ -86,4 +86,4 @@ def get_product_filter_data(query_args=None): @frappe.whitelist(allow_guest=True) def get_guest_redirect_on_action(): - return frappe.db.get_single_value("Webshop Settings", "redirect_on_action") + return frappe.db.get_single_value("Shop Settings", "redirect_on_action") diff --git a/webshop/templates/pages/__init__.py b/shop/shop/crud_events/__init__.py similarity index 100% rename from webshop/templates/pages/__init__.py rename to shop/shop/crud_events/__init__.py diff --git a/webshop/webshop/__init__.py b/shop/shop/crud_events/item/__init__.py similarity index 100% rename from webshop/webshop/__init__.py rename to shop/shop/crud_events/item/__init__.py diff --git a/webshop/webshop/crud_events/item/invalidate_item_variants_cache.py b/shop/shop/crud_events/item/invalidate_item_variants_cache.py similarity index 90% rename from webshop/webshop/crud_events/item/invalidate_item_variants_cache.py rename to shop/shop/crud_events/item/invalidate_item_variants_cache.py index 51d9eba797..bac293b55a 100644 --- a/webshop/webshop/crud_events/item/invalidate_item_variants_cache.py +++ b/shop/shop/crud_events/item/invalidate_item_variants_cache.py @@ -1,5 +1,5 @@ import frappe -from webshop.webshop.variant_selector.item_variants_cache import ( +from shop.shop.variant_selector.item_variants_cache import ( ItemVariantsCacheManager, ) diff --git a/webshop/webshop/crud_events/item/update_website_item.py b/shop/shop/crud_events/item/update_website_item.py similarity index 100% rename from webshop/webshop/crud_events/item/update_website_item.py rename to shop/shop/crud_events/item/update_website_item.py diff --git a/webshop/webshop/crud_events/item/validate_duplicate_website_item.py b/shop/shop/crud_events/item/validate_duplicate_website_item.py similarity index 100% rename from webshop/webshop/crud_events/item/validate_duplicate_website_item.py rename to shop/shop/crud_events/item/validate_duplicate_website_item.py diff --git a/webshop/webshop/crud_events/__init__.py b/shop/shop/crud_events/price_list/__init__.py similarity index 100% rename from webshop/webshop/crud_events/__init__.py rename to shop/shop/crud_events/price_list/__init__.py diff --git a/webshop/webshop/crud_events/price_list/check_impact_on_cart.py b/shop/shop/crud_events/price_list/check_impact_on_cart.py similarity index 67% rename from webshop/webshop/crud_events/price_list/check_impact_on_cart.py rename to shop/shop/crud_events/price_list/check_impact_on_cart.py index 7bc11d3c7d..f6895cd026 100644 --- a/webshop/webshop/crud_events/price_list/check_impact_on_cart.py +++ b/shop/shop/crud_events/price_list/check_impact_on_cart.py @@ -1,12 +1,12 @@ import frappe -from webshop.webshop.doctype.webshop_settings.webshop_settings import ( +from shop.shop.doctype.shop_settings.shop_settings import ( validate_cart_settings, ) def execute(doc, method=None): """ - Check if Price List currency change impacts Webshop Cart + Check if Price List currency change impacts Shop Cart """ if doc.is_new(): return @@ -14,7 +14,7 @@ def execute(doc, method=None): doc_before_save = doc.get_doc_before_save() currency_changed = doc.currency != doc_before_save.currency affects_cart = doc.name == frappe.get_cached_value( - "Webshop Settings", None, "price_list" + "Shop Settings", None, "price_list" ) if currency_changed and affects_cart: diff --git a/webshop/webshop/crud_events/item/__init__.py b/shop/shop/crud_events/quotation/__init__.py similarity index 100% rename from webshop/webshop/crud_events/item/__init__.py rename to shop/shop/crud_events/quotation/__init__.py diff --git a/webshop/webshop/crud_events/quotation/validate_shopping_cart_items.py b/shop/shop/crud_events/quotation/validate_shopping_cart_items.py similarity index 82% rename from webshop/webshop/crud_events/quotation/validate_shopping_cart_items.py rename to shop/shop/crud_events/quotation/validate_shopping_cart_items.py index cb8d5f394a..f1a0a1071d 100644 --- a/webshop/webshop/crud_events/quotation/validate_shopping_cart_items.py +++ b/shop/shop/crud_events/quotation/validate_shopping_cart_items.py @@ -6,7 +6,7 @@ def execute(doc, method=None): if doc.order_type != "Shopping Cart": return - webshop_settings = frappe.get_cached_doc("Webshop Settings") + shop_settings = frappe.get_cached_doc("Shop Settings") for item in doc.items: has_web_item = frappe.db.exists("Website Item", {"item_code": item.item_code}) @@ -15,7 +15,7 @@ def execute(doc, method=None): if template and not has_web_item: has_web_item = frappe.db.exists("Website Item", {"item_code": template}) - if not has_web_item and not webshop_settings.allow_non_website_items_in_cart_quotation: + if not has_web_item and not shop_settings.allow_non_website_items_in_cart_quotation: frappe.throw( _( "Row #{0}: Item {1} must have a Website Item for Shopping Cart Quotations" diff --git a/webshop/webshop/crud_events/price_list/__init__.py b/shop/shop/crud_events/tax_rule/__init__.py similarity index 100% rename from webshop/webshop/crud_events/price_list/__init__.py rename to shop/shop/crud_events/tax_rule/__init__.py diff --git a/webshop/webshop/crud_events/tax_rule/validate_use_for_cart.py b/shop/shop/crud_events/tax_rule/validate_use_for_cart.py similarity index 89% rename from webshop/webshop/crud_events/tax_rule/validate_use_for_cart.py rename to shop/shop/crud_events/tax_rule/validate_use_for_cart.py index b99ac21cff..2c9c897ed0 100644 --- a/webshop/webshop/crud_events/tax_rule/validate_use_for_cart.py +++ b/shop/shop/crud_events/tax_rule/validate_use_for_cart.py @@ -10,7 +10,7 @@ def execute(doc, method=None): if doc.use_for_shopping_cart: return - is_enabled = cint(frappe.db.get_single_value("Webshop Settings", "enabled")) + is_enabled = cint(frappe.db.get_single_value("Shop Settings", "enabled")) if not is_enabled: return diff --git a/webshop/webshop/crud_events/quotation/__init__.py b/shop/shop/doctype/__init__.py similarity index 100% rename from webshop/webshop/crud_events/quotation/__init__.py rename to shop/shop/doctype/__init__.py diff --git a/webshop/webshop/crud_events/tax_rule/__init__.py b/shop/shop/doctype/homepage_featured_product/__init__.py similarity index 100% rename from webshop/webshop/crud_events/tax_rule/__init__.py rename to shop/shop/doctype/homepage_featured_product/__init__.py diff --git a/webshop/webshop/doctype/homepage_featured_product/homepage_featured_product.json b/shop/shop/doctype/homepage_featured_product/homepage_featured_product.json similarity index 98% rename from webshop/webshop/doctype/homepage_featured_product/homepage_featured_product.json rename to shop/shop/doctype/homepage_featured_product/homepage_featured_product.json index fe4bbbfa22..ddc2b820f6 100644 --- a/webshop/webshop/doctype/homepage_featured_product/homepage_featured_product.json +++ b/shop/shop/doctype/homepage_featured_product/homepage_featured_product.json @@ -84,7 +84,7 @@ "links": [], "modified": "2023-12-14 22:33:25.457721", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Homepage Featured Product", "owner": "Administrator", "permissions": [], diff --git a/webshop/webshop/doctype/homepage_featured_product/homepage_featured_product.py b/shop/shop/doctype/homepage_featured_product/homepage_featured_product.py similarity index 100% rename from webshop/webshop/doctype/homepage_featured_product/homepage_featured_product.py rename to shop/shop/doctype/homepage_featured_product/homepage_featured_product.py diff --git a/webshop/webshop/doctype/__init__.py b/shop/shop/doctype/item_review/__init__.py similarity index 100% rename from webshop/webshop/doctype/__init__.py rename to shop/shop/doctype/item_review/__init__.py diff --git a/webshop/webshop/doctype/item_review/item_review.js b/shop/shop/doctype/item_review/item_review.js similarity index 100% rename from webshop/webshop/doctype/item_review/item_review.js rename to shop/shop/doctype/item_review/item_review.js diff --git a/webshop/webshop/doctype/item_review/item_review.json b/shop/shop/doctype/item_review/item_review.json similarity index 99% rename from webshop/webshop/doctype/item_review/item_review.json rename to shop/shop/doctype/item_review/item_review.json index 5d21a6fdd8..e52ead3b42 100644 --- a/webshop/webshop/doctype/item_review/item_review.json +++ b/shop/shop/doctype/item_review/item_review.json @@ -88,7 +88,7 @@ "links": [], "modified": "2023-10-13 17:35:32.281964", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Item Review", "owner": "Administrator", "permissions": [ diff --git a/webshop/webshop/doctype/item_review/item_review.py b/shop/shop/doctype/item_review/item_review.py similarity index 98% rename from webshop/webshop/doctype/item_review/item_review.py rename to shop/shop/doctype/item_review/item_review.py index 840d37b709..7aa9392c8b 100644 --- a/webshop/webshop/doctype/item_review/item_review.py +++ b/shop/shop/doctype/item_review/item_review.py @@ -10,7 +10,7 @@ from frappe.model.document import Document from frappe.utils import cint, flt -from webshop.webshop.doctype.webshop_settings.webshop_settings import ( +from shop.shop.doctype.shop_settings.shop_settings import ( get_shopping_cart_settings, ) diff --git a/webshop/webshop/doctype/item_review/test_item_review.py b/shop/shop/doctype/item_review/test_item_review.py similarity index 87% rename from webshop/webshop/doctype/item_review/test_item_review.py rename to shop/shop/doctype/item_review/test_item_review.py index ce91cf10af..d5457b1fa4 100644 --- a/webshop/webshop/doctype/item_review/test_item_review.py +++ b/shop/shop/doctype/item_review/test_item_review.py @@ -6,16 +6,16 @@ import frappe from frappe.core.doctype.user_permission.test_user_permission import create_user -from webshop.webshop.doctype.webshop_settings.test_webshop_settings import ( - setup_webshop_settings, +from shop.shop.doctype.shop_settings.test_shop_settings import ( + setup_shop_settings, ) -from webshop.webshop.doctype.item_review.item_review import ( +from shop.shop.doctype.item_review.item_review import ( UnverifiedReviewer, add_item_review, get_item_reviews, ) -from webshop.webshop.doctype.website_item.website_item import make_website_item -from webshop.webshop.shopping_cart.cart import get_party +from shop.shop.doctype.website_item.website_item import make_website_item +from shop.shop.shopping_cart.cart import get_party from erpnext.stock.doctype.item.test_item import make_item @@ -26,7 +26,7 @@ def setUp(self): make_website_item(item, save=True) frappe.set_user("Administrator") - setup_webshop_settings({"enable_reviews": 1, "enabled": 1}) + setup_shop_settings({"enable_reviews": 1, "enabled": 1}) frappe.local.shopping_cart_settings = None def tearDown(self): @@ -38,7 +38,7 @@ def tearDown(self): frappe.delete_doc("Item Review", review.name) website_item_doc.delete() - setup_webshop_settings({"enable_reviews": 0}) + setup_shop_settings({"enable_reviews": 0}) def test_add_and_get_item_reviews_from_customer(self): "Add / Get Reviews from a User that is a valid customer (has added to cart or purchased in the past)" diff --git a/webshop/webshop/doctype/homepage_featured_product/__init__.py b/shop/shop/doctype/override_doctype/__init__.py similarity index 100% rename from webshop/webshop/doctype/homepage_featured_product/__init__.py rename to shop/shop/doctype/override_doctype/__init__.py diff --git a/webshop/webshop/doctype/override_doctype/item.py b/shop/shop/doctype/override_doctype/item.py similarity index 82% rename from webshop/webshop/doctype/override_doctype/item.py rename to shop/shop/doctype/override_doctype/item.py index b2cf5d3fce..d35efced7a 100644 --- a/webshop/webshop/doctype/override_doctype/item.py +++ b/shop/shop/doctype/override_doctype/item.py @@ -2,20 +2,20 @@ from frappe import _ from frappe.utils import get_link_to_form from erpnext.stock.doctype.item.item import Item -from webshop.webshop.doctype.override_doctype.item_group import invalidate_cache_for +from shop.shop.doctype.override_doctype.item_group import invalidate_cache_for class DataValidationError(frappe.ValidationError): pass -class WebshopItem(Item): +class ShopItem(Item): def on_update(self): - super(WebshopItem, self).on_update() + super(ShopItem, self).on_update() invalidate_cache_for_item(self) - super(WebshopItem, self).on_update() + super(ShopItem, self).on_update() def before_rename(self, old_name, new_name, merge=False): self.validate_duplicate_website_item_before_merge(old_name, new_name) - return super(WebshopItem, self).before_rename(old_name, new_name, merge) + return super(ShopItem, self).before_rename(old_name, new_name, merge) def validate_duplicate_website_item_before_merge(self, old_name, new_name): """ @@ -42,7 +42,7 @@ def after_rename(self, old_name, new_name, merge): if self.published_in_website: invalidate_cache_for_item(self) - super(WebshopItem, self).after_rename(old_name, new_name, merge) + super(ShopItem, self).after_rename(old_name, new_name, merge) def invalidate_cache_for_item(doc): diff --git a/webshop/webshop/doctype/override_doctype/item_group.py b/shop/shop/doctype/override_doctype/item_group.py similarity index 92% rename from webshop/webshop/doctype/override_doctype/item_group.py rename to shop/shop/doctype/override_doctype/item_group.py index 3d74a58c30..bfc895da0e 100644 --- a/webshop/webshop/doctype/override_doctype/item_group.py +++ b/shop/shop/doctype/override_doctype/item_group.py @@ -5,9 +5,9 @@ from frappe.website.website_generator import WebsiteGenerator from erpnext.setup.doctype.item_group.item_group import ItemGroup from frappe.website.utils import clear_cache -from webshop.webshop.product_data_engine.filters import ProductFiltersBuilder +from shop.shop.product_data_engine.filters import ProductFiltersBuilder -class WebshopItemGroup(ItemGroup, WebsiteGenerator): +class ShopItemGroup(ItemGroup, WebsiteGenerator): nsm_parent_field = "parent_item_group" website = frappe._dict( condition_field="show_in_website", @@ -19,11 +19,11 @@ class WebshopItemGroup(ItemGroup, WebsiteGenerator): def validate(self): self.make_route() WebsiteGenerator.validate(self) - super(WebshopItemGroup, self).validate() + super(ShopItemGroup, self).validate() def on_update(self): invalidate_cache_for(self) - super(WebshopItemGroup, self).on_update() + super(ShopItemGroup, self).on_update() def make_route(self): """Make website route""" @@ -44,13 +44,13 @@ def make_route(self): def on_trash(self): WebsiteGenerator.on_trash(self) - super(WebshopItemGroup, self).on_trash() + super(ShopItemGroup, self).on_trash() def get_context(self, context): context.show_search = True context.body_class = "product-page" context.page_length = ( - cint(frappe.db.get_single_value("Webshop Settings", "products_per_page")) or 6 + cint(frappe.db.get_single_value("Shop Settings", "products_per_page")) or 6 ) context.search_link = "/product_search" @@ -97,7 +97,7 @@ def get_item_for_list_in_html(context): def get_parent_item_groups(item_group_name, from_item=False): - settings = frappe.get_cached_doc("Webshop Settings") + settings = frappe.get_cached_doc("Shop Settings") if settings.enable_field_filters: base_nav_page = {"name": _("Shop by Category"), "route": "/shop-by-category"} diff --git a/webshop/webshop/doctype/override_doctype/payment_request.py b/shop/shop/doctype/override_doctype/payment_request.py similarity index 91% rename from webshop/webshop/doctype/override_doctype/payment_request.py rename to shop/shop/doctype/override_doctype/payment_request.py index 5b84e8bc83..7d3be0ea9f 100644 --- a/webshop/webshop/doctype/override_doctype/payment_request.py +++ b/shop/shop/doctype/override_doctype/payment_request.py @@ -20,7 +20,7 @@ def on_payment_authorized(self, status=None): if frappe.local.session.user == "Guest": return - cart_settings = frappe.get_doc("Webshop Settings") + cart_settings = frappe.get_doc("Shop Settings") if not cart_settings.enabled: return @@ -46,6 +46,6 @@ def get_gateway_details(args): if args.order_type != "Shopping Cart": return super().get_gateway_details(args) - cart_settings = frappe.get_doc("Webshop Settings") + cart_settings = frappe.get_doc("Shop Settings") gateway_account = cart_settings.payment_gateway_account return super().get_payment_gateway_account(gateway_account) diff --git a/webshop/webshop/doctype/item_review/__init__.py b/shop/shop/doctype/recommended_items/__init__.py similarity index 100% rename from webshop/webshop/doctype/item_review/__init__.py rename to shop/shop/doctype/recommended_items/__init__.py diff --git a/webshop/webshop/doctype/recommended_items/recommended_items.json b/shop/shop/doctype/recommended_items/recommended_items.json similarity index 98% rename from webshop/webshop/doctype/recommended_items/recommended_items.json rename to shop/shop/doctype/recommended_items/recommended_items.json index d75562c292..5da4228d25 100644 --- a/webshop/webshop/doctype/recommended_items/recommended_items.json +++ b/shop/shop/doctype/recommended_items/recommended_items.json @@ -77,7 +77,7 @@ "links": [], "modified": "2022-06-28 16:44:24.718728", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Recommended Items", "owner": "Administrator", "permissions": [], diff --git a/webshop/webshop/doctype/recommended_items/recommended_items.py b/shop/shop/doctype/recommended_items/recommended_items.py similarity index 100% rename from webshop/webshop/doctype/recommended_items/recommended_items.py rename to shop/shop/doctype/recommended_items/recommended_items.py diff --git a/webshop/webshop/doctype/override_doctype/__init__.py b/shop/shop/doctype/shop_settings/__init__.py similarity index 100% rename from webshop/webshop/doctype/override_doctype/__init__.py rename to shop/shop/doctype/shop_settings/__init__.py diff --git a/webshop/webshop/doctype/webshop_settings/webshop_settings.js b/shop/shop/doctype/shop_settings/shop_settings.js similarity index 97% rename from webshop/webshop/doctype/webshop_settings/webshop_settings.js rename to shop/shop/doctype/shop_settings/shop_settings.js index 57889c3dd5..5eb35b77fe 100644 --- a/webshop/webshop/doctype/webshop_settings/webshop_settings.js +++ b/shop/shop/doctype/shop_settings/shop_settings.js @@ -1,7 +1,7 @@ // Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -frappe.ui.form.on("Webshop Settings", { +frappe.ui.form.on("Shop Settings", { onload: function(frm) { if(frm.doc.__onload && frm.doc.__onload.quotation_series) { frm.fields_dict.quotation_series.df.options = frm.doc.__onload.quotation_series; diff --git a/webshop/webshop/doctype/webshop_settings/webshop_settings.json b/shop/shop/doctype/shop_settings/shop_settings.json similarity index 99% rename from webshop/webshop/doctype/webshop_settings/webshop_settings.json rename to shop/shop/doctype/shop_settings/shop_settings.json index 024ec2efd3..400f93f63c 100644 --- a/webshop/webshop/doctype/webshop_settings/webshop_settings.json +++ b/shop/shop/doctype/shop_settings/shop_settings.json @@ -389,8 +389,8 @@ "links": [], "modified": "2025-03-22 13:01:51.906319", "modified_by": "Administrator", - "module": "Webshop", - "name": "Webshop Settings", + "module": "Shop", + "name": "Shop Settings", "owner": "Administrator", "permissions": [ { diff --git a/webshop/webshop/doctype/webshop_settings/webshop_settings.py b/shop/shop/doctype/shop_settings/shop_settings.py similarity index 94% rename from webshop/webshop/doctype/webshop_settings/webshop_settings.py rename to shop/shop/doctype/shop_settings/shop_settings.py index 50ea3b11d0..c9cd54b4d7 100644 --- a/webshop/webshop/doctype/webshop_settings/webshop_settings.py +++ b/shop/shop/doctype/shop_settings/shop_settings.py @@ -7,7 +7,7 @@ from frappe.model.document import Document from frappe.utils import comma_and, flt, unique -from webshop.webshop.redisearch_utils import ( +from shop.shop.redisearch_utils import ( create_website_items_index, define_autocomplete_dictionary, get_indexable_web_fields, @@ -19,7 +19,7 @@ class ShoppingCartSetupError(frappe.ValidationError): pass -class WebshopSettings(Document): +class ShopSettings(Document): def onload(self): self.get("__onload").quotation_series = frappe.get_meta("Quotation").get_options("naming_series") @@ -35,10 +35,10 @@ def validate(self): if self.enabled: self.validate_price_list_exchange_rate() - frappe.clear_document_cache("Webshop Settings", "Webshop Settings") + frappe.clear_document_cache("Shop Settings", "Shop Settings") self.is_redisearch_enabled_pre_save = frappe.db.get_single_value( - "Webshop Settings", "is_redisearch_enabled" + "Shop Settings", "is_redisearch_enabled" ) def after_save(self): @@ -160,11 +160,11 @@ def on_change(self): def validate_cart_settings(doc=None, method=None): - frappe.get_doc("Webshop Settings", "Webshop Settings").run_method("validate") + frappe.get_doc("Shop Settings", "Shop Settings").run_method("validate") def get_shopping_cart_settings(): - return frappe.get_cached_doc("Webshop Settings") + return frappe.get_cached_doc("Shop Settings") @frappe.whitelist(allow_guest=True) diff --git a/webshop/webshop/doctype/webshop_settings/test_webshop_settings.py b/shop/shop/doctype/shop_settings/test_shop_settings.py similarity index 67% rename from webshop/webshop/doctype/webshop_settings/test_webshop_settings.py rename to shop/shop/doctype/shop_settings/test_shop_settings.py index 541e956b95..4df4f1aa78 100644 --- a/webshop/webshop/doctype/webshop_settings/test_webshop_settings.py +++ b/shop/shop/doctype/shop_settings/test_shop_settings.py @@ -4,12 +4,12 @@ import frappe -from webshop.webshop.doctype.webshop_settings.webshop_settings import ( +from shop.shop.doctype.shop_settings.shop_settings import ( ShoppingCartSetupError, ) -class TestWebshopSettings(unittest.TestCase): +class TestShopSettings(unittest.TestCase): def tearDown(self): frappe.db.rollback() @@ -17,7 +17,7 @@ def test_tax_rule_validation(self): frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0") frappe.db.commit() # nosemgrep - cart_settings = frappe.get_doc("Webshop Settings") + cart_settings = frappe.get_doc("Shop Settings") cart_settings.enabled = 1 if not frappe.db.get_value("Tax Rule", {"use_for_shopping_cart": 1}, "name"): self.assertRaises(ShoppingCartSetupError, cart_settings.validate_tax_rule) @@ -25,27 +25,27 @@ def test_tax_rule_validation(self): frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 1") def test_invalid_filter_fields(self): - "Check if Item fields are blocked in Webshop Settings filter fields." + "Check if Item fields are blocked in Shop Settings filter fields." from frappe.custom.doctype.custom_field.custom_field import create_custom_field - setup_webshop_settings({"enable_field_filters": 1}) + setup_shop_settings({"enable_field_filters": 1}) create_custom_field( "Item", dict(owner="Administrator", fieldname="test_data", label="Test", fieldtype="Data"), ) - settings = frappe.get_doc("Webshop Settings") + settings = frappe.get_doc("Shop Settings") settings.append("filter_fields", {"fieldname": "test_data"}) self.assertRaises(frappe.ValidationError, settings.save) -def setup_webshop_settings(values_dict): - "Accepts a dict of values that updates Webshop Settings." +def setup_shop_settings(values_dict): + "Accepts a dict of values that updates Shop Settings." if not values_dict: return - doc = frappe.get_doc("Webshop Settings", "Webshop Settings") + doc = frappe.get_doc("Shop Settings", "Shop Settings") doc.update(values_dict) doc.save() diff --git a/webshop/webshop/doctype/recommended_items/__init__.py b/shop/shop/doctype/website_item/__init__.py similarity index 100% rename from webshop/webshop/doctype/recommended_items/__init__.py rename to shop/shop/doctype/website_item/__init__.py diff --git a/webshop/webshop/doctype/website_item/templates/website_item.html b/shop/shop/doctype/website_item/templates/website_item.html similarity index 100% rename from webshop/webshop/doctype/website_item/templates/website_item.html rename to shop/shop/doctype/website_item/templates/website_item.html diff --git a/webshop/webshop/doctype/website_item/templates/website_item_row.html b/shop/shop/doctype/website_item/templates/website_item_row.html similarity index 100% rename from webshop/webshop/doctype/website_item/templates/website_item_row.html rename to shop/shop/doctype/website_item/templates/website_item_row.html diff --git a/webshop/webshop/doctype/website_item/test_website_item.py b/shop/shop/doctype/website_item/test_website_item.py similarity index 90% rename from webshop/webshop/doctype/website_item/test_website_item.py rename to shop/shop/doctype/website_item/test_website_item.py index 6488779b2f..3d10772d46 100644 --- a/webshop/webshop/doctype/website_item/test_website_item.py +++ b/shop/shop/doctype/website_item/test_website_item.py @@ -7,17 +7,17 @@ import frappe from erpnext.controllers.item_variant import create_variant -from webshop.webshop.doctype.webshop_settings.webshop_settings import ( +from shop.shop.doctype.shop_settings.shop_settings import ( get_shopping_cart_settings, ) -from webshop.webshop.doctype.webshop_settings.test_webshop_settings import ( - setup_webshop_settings, +from shop.shop.doctype.shop_settings.test_shop_settings import ( + setup_shop_settings, ) -from webshop.webshop.doctype.website_item.website_item import make_website_item -from webshop.webshop.shopping_cart.product_info import get_product_info_for_website -from webshop.webshop.doctype.override_doctype.item import DataValidationError +from shop.shop.doctype.website_item.website_item import make_website_item +from shop.shop.shopping_cart.product_info import get_product_info_for_website +from shop.shop.doctype.override_doctype.item import DataValidationError from erpnext.stock.doctype.item.test_item import make_item -from webshop.webshop.doctype.override_doctype.item_group import get_parent_item_groups +from shop.shop.doctype.override_doctype.item_group import get_parent_item_groups WEBITEM_DESK_TESTS = ("test_website_item_desk_item_sync", "test_publish_variant_and_template") WEBITEM_PRICE_TESTS = ( @@ -29,7 +29,7 @@ class TestWebsiteItem(unittest.TestCase): @classmethod def setUpClass(cls): - setup_webshop_settings( + setup_shop_settings( { "company": "_Test Company", "enabled": 1, @@ -78,7 +78,7 @@ def setUp(self): def test_index_creation(self): "Check if index is getting created in db." - from webshop.webshop.doctype.website_item.website_item import on_doctype_update + from shop.shop.doctype.website_item.website_item import on_doctype_update on_doctype_update() @@ -195,7 +195,7 @@ def test_website_item_breadcrumbs(self): breadcrumbs = get_parent_item_groups(item.item_group) - settings = frappe.get_cached_doc("Webshop Settings") + settings = frappe.get_cached_doc("Shop Settings") if settings.enable_field_filters: base_breadcrumb = "Shop by Category" else: @@ -215,7 +215,7 @@ def test_website_item_price_for_logged_in_user(self): item_code = "Test Mobile Phone" # show price in webshop settings - setup_webshop_settings({"show_price": 1}) + setup_shop_settings({"show_price": 1}) # price and pricing rule added via setUp @@ -236,7 +236,7 @@ def test_website_item_price_for_logged_in_user(self): # switch to admin and disable show price frappe.set_user("Administrator") - setup_webshop_settings({"show_price": 0}) + setup_shop_settings({"show_price": 0}) # price should not be fetched for logged in user. frappe.set_user("test_contact_customer@example.com") @@ -252,7 +252,7 @@ def test_website_item_price_for_guest_user(self): item_code = "Test Mobile Phone" # show price for guest user in webshop settings - setup_webshop_settings({"show_price": 1, "hide_price_for_guest": 0}) + setup_shop_settings({"show_price": 1, "hide_price_for_guest": 0}) # price and pricing rule added via setUp @@ -270,7 +270,7 @@ def test_website_item_price_for_guest_user(self): # hide price for guest user frappe.set_user("Administrator") - setup_webshop_settings({"hide_price_for_guest": 1}) + setup_shop_settings({"hide_price_for_guest": 1}) frappe.set_user("Guest") # price should not be fetched @@ -295,7 +295,7 @@ def test_website_item_stock_when_out_of_stock(self): frappe.set_user("Administrator") create_regular_web_item() - setup_webshop_settings({"show_stock_availability": 1}) + setup_shop_settings({"show_stock_availability": 1}) frappe.local.shopping_cart_settings = None data = get_product_info_for_website(item_code, skip_quotation_creation=True) @@ -315,7 +315,7 @@ def test_website_item_stock_when_out_of_stock(self): self.assertEqual(data.product_info["stock_qty"], 0) # disable show stock availability - setup_webshop_settings({"show_stock_availability": 0}) + setup_shop_settings({"show_stock_availability": 0}) frappe.local.shopping_cart_settings = None data = get_product_info_for_website(item_code, skip_quotation_creation=True) @@ -343,7 +343,7 @@ def test_website_item_stock_when_in_stock(self): frappe.set_user("Administrator") create_regular_web_item() - setup_webshop_settings({"show_stock_availability": 1}) + setup_shop_settings({"show_stock_availability": 1}) frappe.local.shopping_cart_settings = None # set warehouse @@ -371,7 +371,7 @@ def test_website_item_stock_when_in_stock(self): self.assertFalse(bool(data.product_info["stock_qty"])) # disable show stock availability - setup_webshop_settings({"show_stock_availability": 0}) + setup_shop_settings({"show_stock_availability": 0}) frappe.local.shopping_cart_settings = None data = get_product_info_for_website(item_code, skip_quotation_creation=True) @@ -390,7 +390,7 @@ def test_recommended_item(self): item_code = "Test Mobile Phone" web_item = create_regular_web_item(item_code) - setup_webshop_settings({"enable_recommendations": 1, "show_price": 1}) + setup_shop_settings({"enable_recommendations": 1, "show_price": 1}) # create recommended web item and price for it recommended_web_item = create_regular_web_item("Test Mobile Phone 1") @@ -401,8 +401,8 @@ def test_recommended_item(self): web_item.save() frappe.local.shopping_cart_settings = None - webshop_settings = get_shopping_cart_settings() - recommended_items = web_item.get_recommended_items(webshop_settings) + shop_settings = get_shopping_cart_settings() + recommended_items = web_item.get_recommended_items(shop_settings) # test results if show price is enabled self.assertEqual(len(recommended_items), 1) @@ -415,11 +415,11 @@ def test_recommended_item(self): self.assertEqual(price_info.get("formatted_price"), "₹ 1,000.00") # test results if show price is disabled - setup_webshop_settings({"show_price": 0}) + setup_shop_settings({"show_price": 0}) frappe.local.shopping_cart_settings = None - webshop_settings = get_shopping_cart_settings() - recommended_items = web_item.get_recommended_items(webshop_settings) + shop_settings = get_shopping_cart_settings() + recommended_items = web_item.get_recommended_items(shop_settings) self.assertEqual(len(recommended_items), 1) self.assertFalse(bool(recommended_items[0].get("price_info"))) # price not fetched @@ -435,7 +435,7 @@ def test_recommended_item_for_guest_user(self): web_item = create_regular_web_item(item_code) # price visible to guests - setup_webshop_settings( + setup_shop_settings( {"enable_recommendations": 1, "show_price": 1, "hide_price_for_guest": 0} ) @@ -450,8 +450,8 @@ def test_recommended_item_for_guest_user(self): frappe.set_user("Guest") frappe.local.shopping_cart_settings = None - webshop_settings = get_shopping_cart_settings() - recommended_items = web_item.get_recommended_items(webshop_settings) + shop_settings = get_shopping_cart_settings() + recommended_items = web_item.get_recommended_items(shop_settings) # test results if show price is enabled self.assertEqual(len(recommended_items), 1) @@ -459,12 +459,12 @@ def test_recommended_item_for_guest_user(self): # price hidden from guests frappe.set_user("Administrator") - setup_webshop_settings({"hide_price_for_guest": 1}) + setup_shop_settings({"hide_price_for_guest": 1}) frappe.set_user("Guest") frappe.local.shopping_cart_settings = None - webshop_settings = get_shopping_cart_settings() - recommended_items = web_item.get_recommended_items(webshop_settings) + shop_settings = get_shopping_cart_settings() + recommended_items = web_item.get_recommended_items(shop_settings) # test results if show price is enabled self.assertEqual(len(recommended_items), 1) diff --git a/webshop/webshop/doctype/website_item/website_item.js b/shop/shop/doctype/website_item/website_item.js similarity index 88% rename from webshop/webshop/doctype/website_item/website_item.js rename to shop/shop/doctype/website_item/website_item.js index e82cd1d933..82e5559741 100644 --- a/webshop/webshop/doctype/website_item/website_item.js +++ b/shop/shop/doctype/website_item/website_item.js @@ -19,8 +19,8 @@ frappe.ui.form.on('Website Item', { frappe.set_route("query-report", "Stock Balance"); }, __("View")); - frm.add_custom_button(__("Webshop Settings"), function() { - frappe.set_route("Form", "Webshop Settings"); + frm.add_custom_button(__("Shop Settings"), function() { + frappe.set_route("Form", "Shop Settings"); }, __("View")); }, diff --git a/webshop/webshop/doctype/website_item/website_item.json b/shop/shop/doctype/website_item/website_item.json similarity index 99% rename from webshop/webshop/doctype/website_item/website_item.json rename to shop/shop/doctype/website_item/website_item.json index e5adbd778c..438cabf552 100644 --- a/webshop/webshop/doctype/website_item/website_item.json +++ b/shop/shop/doctype/website_item/website_item.json @@ -349,7 +349,7 @@ "make_attachments_public": 1, "modified": "2024-11-05 13:41:45.347700", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Website Item", "naming_rule": "Expression (old style)", "owner": "Administrator", diff --git a/webshop/webshop/doctype/website_item/website_item.py b/shop/shop/doctype/website_item/website_item.py similarity index 96% rename from webshop/webshop/doctype/website_item/website_item.py rename to shop/shop/doctype/website_item/website_item.py index f907c5efb0..096fbe9d7e 100644 --- a/webshop/webshop/doctype/website_item/website_item.py +++ b/shop/shop/doctype/website_item/website_item.py @@ -14,21 +14,21 @@ from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow from frappe.website.website_generator import WebsiteGenerator -from webshop.webshop.doctype.item_review.item_review import get_item_reviews -from webshop.webshop.redisearch_utils import ( +from shop.shop.doctype.item_review.item_review import get_item_reviews +from shop.shop.redisearch_utils import ( delete_item_from_index, insert_item_to_index, update_index_for_item, ) -from webshop.webshop.shopping_cart.cart import _set_price_list -from webshop.webshop.doctype.override_doctype.item_group import ( +from shop.shop.shopping_cart.cart import _set_price_list +from shop.shop.doctype.override_doctype.item_group import ( get_parent_item_groups, invalidate_cache_for, ) from erpnext.stock.doctype.item.item import Item from erpnext.utilities.product import get_price -from webshop.webshop.shopping_cart.cart import get_party -from webshop.webshop.variant_selector.item_variants_cache import ( +from shop.shop.shopping_cart.cart import get_party +from shop.shop.variant_selector.item_variants_cache import ( ItemVariantsCacheManager, ) @@ -338,7 +338,7 @@ def set_metatags(self, context): context.metatags["og:site_name"] = "ERPNext" def set_shopping_cart_data(self, context): - from webshop.webshop.shopping_cart.product_info import ( + from shop.shop.shopping_cart.product_info import ( get_product_info_for_website, ) @@ -557,7 +557,7 @@ def has_website_permission_for_website_item(doc, ptype, user, verbose=False): if frappe.has_permission("Website Item", ptype=ptype, doc=doc, user=user): return True - if not frappe.db.get_single_value("Webshop Settings", "login_required_to_view_products"): + if not frappe.db.get_single_value("Shop Settings", "login_required_to_view_products"): return True return False @@ -571,7 +571,7 @@ def has_website_permission_for_item_group(doc, ptype, user, verbose=False): if frappe.has_permission("Item Group", ptype=ptype, doc=doc, user=user): return True - if not frappe.db.get_single_value("Webshop Settings", "login_required_to_view_products"): + if not frappe.db.get_single_value("Shop Settings", "login_required_to_view_products"): return True return False diff --git a/webshop/webshop/doctype/website_item/website_item_list.js b/shop/shop/doctype/website_item/website_item_list.js similarity index 100% rename from webshop/webshop/doctype/website_item/website_item_list.js rename to shop/shop/doctype/website_item/website_item_list.js diff --git a/webshop/webshop/doctype/webshop_settings/__init__.py b/shop/shop/doctype/website_item_tabbed_section/__init__.py similarity index 100% rename from webshop/webshop/doctype/webshop_settings/__init__.py rename to shop/shop/doctype/website_item_tabbed_section/__init__.py diff --git a/webshop/webshop/doctype/website_item_tabbed_section/website_item_tabbed_section.json b/shop/shop/doctype/website_item_tabbed_section/website_item_tabbed_section.json similarity index 96% rename from webshop/webshop/doctype/website_item_tabbed_section/website_item_tabbed_section.json rename to shop/shop/doctype/website_item_tabbed_section/website_item_tabbed_section.json index 5e082195b0..a24c33da20 100644 --- a/webshop/webshop/doctype/website_item_tabbed_section/website_item_tabbed_section.json +++ b/shop/shop/doctype/website_item_tabbed_section/website_item_tabbed_section.json @@ -27,7 +27,7 @@ "links": [], "modified": "2021-03-18 20:35:26.991192", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Website Item Tabbed Section", "owner": "Administrator", "permissions": [], diff --git a/webshop/webshop/doctype/website_item_tabbed_section/website_item_tabbed_section.py b/shop/shop/doctype/website_item_tabbed_section/website_item_tabbed_section.py similarity index 100% rename from webshop/webshop/doctype/website_item_tabbed_section/website_item_tabbed_section.py rename to shop/shop/doctype/website_item_tabbed_section/website_item_tabbed_section.py diff --git a/webshop/webshop/doctype/website_item/__init__.py b/shop/shop/doctype/website_offer/__init__.py similarity index 100% rename from webshop/webshop/doctype/website_item/__init__.py rename to shop/shop/doctype/website_offer/__init__.py diff --git a/webshop/webshop/doctype/website_offer/website_offer.json b/shop/shop/doctype/website_offer/website_offer.json similarity index 97% rename from webshop/webshop/doctype/website_offer/website_offer.json rename to shop/shop/doctype/website_offer/website_offer.json index d4f2181aee..18b53fbf91 100644 --- a/webshop/webshop/doctype/website_offer/website_offer.json +++ b/shop/shop/doctype/website_offer/website_offer.json @@ -33,7 +33,7 @@ "links": [], "modified": "2021-04-21 13:56:04.660331", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Website Offer", "owner": "Administrator", "permissions": [], diff --git a/webshop/webshop/doctype/website_offer/website_offer.py b/shop/shop/doctype/website_offer/website_offer.py similarity index 100% rename from webshop/webshop/doctype/website_offer/website_offer.py rename to shop/shop/doctype/website_offer/website_offer.py diff --git a/webshop/webshop/doctype/website_item_tabbed_section/__init__.py b/shop/shop/doctype/wishlist/__init__.py similarity index 100% rename from webshop/webshop/doctype/website_item_tabbed_section/__init__.py rename to shop/shop/doctype/wishlist/__init__.py diff --git a/webshop/webshop/doctype/wishlist/test_wishlist.py b/shop/shop/doctype/wishlist/test_wishlist.py similarity index 95% rename from webshop/webshop/doctype/wishlist/test_wishlist.py rename to shop/shop/doctype/wishlist/test_wishlist.py index b653b88fd6..4f309b40c5 100644 --- a/webshop/webshop/doctype/wishlist/test_wishlist.py +++ b/shop/shop/doctype/wishlist/test_wishlist.py @@ -6,8 +6,8 @@ import frappe from frappe.core.doctype.user_permission.test_user_permission import create_user -from webshop.webshop.doctype.website_item.website_item import make_website_item -from webshop.webshop.doctype.wishlist.wishlist import add_to_wishlist, remove_from_wishlist +from shop.shop.doctype.website_item.website_item import make_website_item +from shop.shop.doctype.wishlist.wishlist import add_to_wishlist, remove_from_wishlist from erpnext.stock.doctype.item.test_item import make_item diff --git a/webshop/webshop/doctype/wishlist/wishlist.js b/shop/shop/doctype/wishlist/wishlist.js similarity index 100% rename from webshop/webshop/doctype/wishlist/wishlist.js rename to shop/shop/doctype/wishlist/wishlist.js diff --git a/webshop/webshop/doctype/wishlist/wishlist.json b/shop/shop/doctype/wishlist/wishlist.json similarity index 98% rename from webshop/webshop/doctype/wishlist/wishlist.json rename to shop/shop/doctype/wishlist/wishlist.json index aef9365647..d2afe6688f 100644 --- a/webshop/webshop/doctype/wishlist/wishlist.json +++ b/shop/shop/doctype/wishlist/wishlist.json @@ -36,7 +36,7 @@ "links": [], "modified": "2021-07-08 13:11:21.693956", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Wishlist", "owner": "Administrator", "permissions": [ diff --git a/webshop/webshop/doctype/wishlist/wishlist.py b/shop/shop/doctype/wishlist/wishlist.py similarity index 100% rename from webshop/webshop/doctype/wishlist/wishlist.py rename to shop/shop/doctype/wishlist/wishlist.py diff --git a/webshop/webshop/doctype/website_offer/__init__.py b/shop/shop/doctype/wishlist_item/__init__.py similarity index 100% rename from webshop/webshop/doctype/website_offer/__init__.py rename to shop/shop/doctype/wishlist_item/__init__.py diff --git a/webshop/webshop/doctype/wishlist_item/wishlist_item.json b/shop/shop/doctype/wishlist_item/wishlist_item.json similarity index 99% rename from webshop/webshop/doctype/wishlist_item/wishlist_item.json rename to shop/shop/doctype/wishlist_item/wishlist_item.json index a8e9052eef..b80ab86c2e 100644 --- a/webshop/webshop/doctype/wishlist_item/wishlist_item.json +++ b/shop/shop/doctype/wishlist_item/wishlist_item.json @@ -137,7 +137,7 @@ "links": [], "modified": "2021-08-09 10:30:41.964802", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Wishlist Item", "owner": "Administrator", "permissions": [], diff --git a/webshop/webshop/doctype/wishlist_item/wishlist_item.py b/shop/shop/doctype/wishlist_item/wishlist_item.py similarity index 100% rename from webshop/webshop/doctype/wishlist_item/wishlist_item.py rename to shop/shop/doctype/wishlist_item/wishlist_item.py diff --git a/webshop/webshop/legacy_search.py b/shop/shop/legacy_search.py similarity index 100% rename from webshop/webshop/legacy_search.py rename to shop/shop/legacy_search.py diff --git a/webshop/webshop/product_data_engine/filters.py b/shop/shop/product_data_engine/filters.py similarity index 95% rename from webshop/webshop/product_data_engine/filters.py rename to shop/shop/product_data_engine/filters.py index c31dd5273b..bce5365504 100644 --- a/webshop/webshop/product_data_engine/filters.py +++ b/shop/shop/product_data_engine/filters.py @@ -8,14 +8,14 @@ class ProductFiltersBuilder: def __init__(self, item_group=None): if not item_group: - self.doc = frappe.get_doc("Webshop Settings") + self.doc = frappe.get_doc("Shop Settings") else: self.doc = frappe.get_doc("Item Group", item_group) self.item_group = item_group def get_field_filters(self): - from webshop.webshop.doctype.override_doctype.item_group import get_child_groups_for_website + from shop.shop.doctype.override_doctype.item_group import get_child_groups_for_website if not self.item_group and not self.doc.enable_field_filters: return @@ -54,7 +54,7 @@ def get_field_filters(self): ) # exclude variants if mentioned in settings - if frappe.db.get_single_value("Webshop Settings", "hide_variants"): + if frappe.db.get_single_value("Shop Settings", "hide_variants"): item_filters["variant_of"] = ["is", "not set"] # Get link field values attached to published items diff --git a/webshop/webshop/product_data_engine/query.py b/shop/shop/product_data_engine/query.py similarity index 95% rename from webshop/webshop/product_data_engine/query.py rename to shop/shop/product_data_engine/query.py index 4fb6c60543..899f57a6f1 100644 --- a/webshop/webshop/product_data_engine/query.py +++ b/shop/shop/product_data_engine/query.py @@ -4,9 +4,9 @@ import frappe from frappe.utils import flt -from webshop.webshop.doctype.item_review.item_review import get_customer -from webshop.webshop.shopping_cart.product_info import get_product_info_for_website -from webshop.webshop.utils.product import get_non_stock_item_status +from shop.shop.doctype.item_review.item_review import get_customer +from shop.shop.shopping_cart.product_info import get_product_info_for_website +from shop.shop.utils.product import get_non_stock_item_status class ProductQuery: @@ -17,11 +17,11 @@ class ProductQuery: conditions (string): Conditions for query building or_conditions (string): Search conditions page_length (Int): Length of page for the query - settings (Document): Webshop Settings DocType + settings (Document): Shop Settings DocType """ def __init__(self): - self.settings = frappe.get_doc("Webshop Settings") + self.settings = frappe.get_doc("Shop Settings") self.page_length = self.settings.products_per_page or 20 self.or_filters = [] @@ -178,7 +178,7 @@ def build_fields_filters(self, filters): def build_item_group_filters(self, item_group): "Add filters for Item group page and include Website Item Groups." - from webshop.webshop.doctype.override_doctype.item_group import get_child_groups_for_website + from shop.shop.doctype.override_doctype.item_group import get_child_groups_for_website item_group_filters = [] @@ -261,7 +261,7 @@ def get_price_discount_info(self, item, price_object, discount_list): def get_stock_availability(self, item): """Modify item object and add stock details.""" - from webshop.templates.pages.wishlist import ( + from shop.templates.pages.wishlist import ( get_stock_availability as get_stock_availability_from_template, ) diff --git a/webshop/webshop/product_data_engine/test_item_group_product_data_engine.py b/shop/shop/product_data_engine/test_item_group_product_data_engine.py similarity index 96% rename from webshop/webshop/product_data_engine/test_item_group_product_data_engine.py rename to shop/shop/product_data_engine/test_item_group_product_data_engine.py index 216e8153d5..3b2bd5ec79 100644 --- a/webshop/webshop/product_data_engine/test_item_group_product_data_engine.py +++ b/shop/shop/product_data_engine/test_item_group_product_data_engine.py @@ -5,8 +5,8 @@ import frappe -from webshop.webshop.api import get_product_filter_data -from webshop.webshop.doctype.website_item.test_website_item import create_regular_web_item +from shop.shop.api import get_product_filter_data +from shop.shop.doctype.website_item.test_website_item import create_regular_web_item test_dependencies = ["Item", "Item Group"] @@ -31,7 +31,7 @@ def setUp(self): frappe.db.set_value("Item Group", "_Test Item Group B - 1", "show_in_website", 1) frappe.db.set_value("Item Group", "_Test Item Group B - 2", "show_in_website", 1) - frappe.db.set_single_value("Webshop Settings", "products_per_page", 10) + frappe.db.set_single_value("Shop Settings", "products_per_page", 10) def tearDown(self): frappe.db.rollback() diff --git a/webshop/webshop/product_data_engine/test_product_data_engine.py b/shop/shop/product_data_engine/test_product_data_engine.py similarity index 92% rename from webshop/webshop/product_data_engine/test_product_data_engine.py rename to shop/shop/product_data_engine/test_product_data_engine.py index d9fb6a152a..c08408feaf 100644 --- a/webshop/webshop/product_data_engine/test_product_data_engine.py +++ b/shop/shop/product_data_engine/test_product_data_engine.py @@ -5,12 +5,12 @@ import frappe -from webshop.webshop.doctype.webshop_settings.test_webshop_settings import ( - setup_webshop_settings, +from shop.shop.doctype.shop_settings.test_shop_settings import ( + setup_shop_settings, ) -from webshop.webshop.doctype.website_item.test_website_item import create_regular_web_item -from webshop.webshop.product_data_engine.filters import ProductFiltersBuilder -from webshop.webshop.product_data_engine.query import ProductQuery +from shop.shop.doctype.website_item.test_website_item import create_regular_web_item +from shop.shop.product_data_engine.filters import ProductFiltersBuilder +from shop.shop.product_data_engine.query import ProductQuery test_dependencies = ["Item", "Item Group"] @@ -36,7 +36,7 @@ def setUpClass(cls): if not frappe.db.exists("Website Item", {"item_code": item_code}): create_regular_web_item(item_code, item_args=item_args, web_args=web_args) - setup_webshop_settings( + setup_shop_settings( { "products_per_page": 4, "enable_field_filters": 1, @@ -179,7 +179,7 @@ def test_product_list_with_attribute_filter(self): def test_product_list_discount_filter_builder(self): "Test if discount filters are fetched correctly." - from webshop.webshop.doctype.website_item.test_website_item import ( + from shop.shop.doctype.website_item.test_website_item import ( make_web_item_price, make_web_pricing_rule, ) @@ -188,7 +188,7 @@ def test_product_list_discount_filter_builder(self): make_web_item_price(item_code=item_code) make_web_pricing_rule(title=f"Test Pricing Rule for {item_code}", item_code=item_code, selling=1) - setup_webshop_settings({"show_price": 1}) + setup_shop_settings({"show_price": 1}) frappe.local.shopping_cart_settings = None engine = ProductQuery() @@ -204,7 +204,7 @@ def test_product_list_discount_filter_builder(self): def test_product_list_with_discount_filters(self): "Test if discount filters are applied correctly." - from webshop.webshop.doctype.website_item.test_website_item import ( + from shop.shop.doctype.website_item.test_website_item import ( make_web_item_price, make_web_pricing_rule, ) @@ -225,7 +225,7 @@ def test_product_list_with_discount_filters(self): selling=1, ) - setup_webshop_settings({"show_price": 1}) + setup_shop_settings({"show_price": 1}) frappe.local.shopping_cart_settings = None engine = ProductQuery() @@ -240,7 +240,7 @@ def test_product_list_with_discount_filters(self): def test_product_list_with_api(self): "Test products listing using API." - from webshop.webshop.api import get_product_filter_data + from shop.shop.api import get_product_filter_data create_variant_web_item() @@ -261,7 +261,7 @@ def test_product_list_with_variants(self): "Test if variants are hideen on hiding variants in settings." create_variant_web_item() - setup_webshop_settings({"enable_attribute_filters": 0, "hide_variants": 1}) + setup_shop_settings({"enable_attribute_filters": 0, "hide_variants": 1}) frappe.local.shopping_cart_settings = None attribute_filters = {"Test Size": ["Large"]} @@ -275,7 +275,7 @@ def test_product_list_with_variants(self): self.assertEqual(len(items), 0) # tear down - setup_webshop_settings({"enable_attribute_filters": 1, "hide_variants": 0}) + setup_shop_settings({"enable_attribute_filters": 1, "hide_variants": 0}) def test_custom_field_as_filter(self): "Test if custom field functions as filter correctly." @@ -300,7 +300,7 @@ def test_custom_field_as_filter(self): "Website Item", {"item_code": "Test 12I Laptop"}, "supplier", "_Test Supplier 1" ) - settings = frappe.get_doc("Webshop Settings") + settings = frappe.get_doc("Shop Settings") settings.append("filter_fields", {"fieldname": "supplier"}) settings.save() @@ -329,7 +329,7 @@ def test_custom_field_as_filter(self): def create_variant_web_item(): "Create Variant and Template Website Items." from erpnext.controllers.item_variant import create_variant - from webshop.webshop.doctype.website_item.website_item import make_website_item + from shop.shop.doctype.website_item.website_item import make_website_item from erpnext.stock.doctype.item.test_item import make_item make_item( diff --git a/webshop/webshop/redisearch_utils.py b/shop/shop/redisearch_utils.py similarity index 96% rename from webshop/webshop/redisearch_utils.py rename to shop/shop/redisearch_utils.py index 85e59624c3..534bba79cc 100644 --- a/webshop/webshop/redisearch_utils.py +++ b/shop/shop/redisearch_utils.py @@ -35,7 +35,7 @@ def get_indexable_web_fields(): def is_redisearch_enabled(): "Return True only if redisearch is loaded and enabled." - is_redisearch_enabled = frappe.db.get_single_value("Webshop Settings", "is_redisearch_enabled") + is_redisearch_enabled = frappe.db.get_single_value("Shop Settings", "is_redisearch_enabled") return is_search_module_loaded() and is_redisearch_enabled @@ -84,7 +84,7 @@ def create_website_items_index(): idx_def = IndexDefinition([make_key(WEBSITE_ITEM_KEY_PREFIX)]) # Index fields mentioned in webshop settings - idx_fields = frappe.db.get_single_value("Webshop Settings", "search_index_fields") + idx_fields = frappe.db.get_single_value("Shop Settings", "search_index_fields") idx_fields = idx_fields.split(",") if idx_fields else [] if "web_item_name" in idx_fields: @@ -241,7 +241,7 @@ def get_cache_key(name): def get_fields_indexed(): - fields_to_index = frappe.db.get_single_value("Webshop Settings", "search_index_fields") + fields_to_index = frappe.db.get_single_value("Shop Settings", "search_index_fields") fields_to_index = fields_to_index.split(",") if fields_to_index else [] mandatory_fields = ["name", "web_item_name", "route", "thumbnail", "ranking"] diff --git a/webshop/webshop/doctype/wishlist/__init__.py b/shop/shop/shopping_cart/__init__.py similarity index 100% rename from webshop/webshop/doctype/wishlist/__init__.py rename to shop/shop/shopping_cart/__init__.py diff --git a/webshop/webshop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py similarity index 97% rename from webshop/webshop/shopping_cart/cart.py rename to shop/shop/shopping_cart/cart.py index 9fd7555667..72ef14770f 100644 --- a/webshop/webshop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -10,10 +10,10 @@ from frappe.utils.nestedset import get_root_of from erpnext.accounts.utils import get_account_name -from webshop.webshop.doctype.webshop_settings.webshop_settings import ( +from shop.shop.doctype.shop_settings.shop_settings import ( get_shopping_cart_settings, ) -from webshop.webshop.utils.product import get_web_item_qty_in_stock +from shop.shop.utils.product import get_web_item_qty_in_stock from erpnext.selling.doctype.quotation.quotation import _make_sales_order @@ -22,7 +22,7 @@ class WebsitePriceListMissingError(frappe.ValidationError): def set_cart_count(quotation=None): - if cint(frappe.db.get_singles_value("Webshop Settings", "enabled")): + if cint(frappe.db.get_singles_value("Shop Settings", "enabled")): if not quotation: quotation = _get_cart_quotation() cart_count = cstr(cint(quotation.get("total_qty"))) @@ -50,7 +50,7 @@ def get_cart_quotation(doc=None): "shipping_addresses": get_shipping_addresses(party), "billing_addresses": get_billing_addresses(party), "shipping_rules": get_applicable_shipping_rules(party), - "cart_settings": frappe.get_cached_doc("Webshop Settings"), + "cart_settings": frappe.get_cached_doc("Shop Settings"), } @@ -89,7 +89,7 @@ def get_billing_addresses(party=None): @frappe.whitelist(allow_guest=True) def place_order(): quotation = _get_cart_quotation() - cart_settings = frappe.get_cached_doc("Webshop Settings") + cart_settings = frappe.get_cached_doc("Shop Settings") quotation.company = cart_settings.company quotation.flags.ignore_permissions = True @@ -387,7 +387,7 @@ def _get_cart_quotation(party=None): if quotation: qdoc = frappe.get_doc("Quotation", quotation[0].name) else: - company = frappe.db.get_single_value("Webshop Settings", "company") + company = frappe.db.get_single_value("Shop Settings", "company") qdoc = frappe.get_doc( { "doctype": "Quotation", @@ -449,7 +449,7 @@ def apply_cart_settings(party=None, quotation=None): if not quotation: quotation = _get_cart_quotation(party) - cart_settings = frappe.get_cached_doc("Webshop Settings") + cart_settings = frappe.get_cached_doc("Shop Settings") set_price_list_and_rate(quotation, cart_settings) @@ -547,7 +547,7 @@ def get_party(user=None): party_doctype = contact.links[0].link_doctype party = contact.links[0].link_name - cart_settings = frappe.get_cached_doc("Webshop Settings") + cart_settings = frappe.get_cached_doc("Shop Settings") debtors_account = "" diff --git a/webshop/webshop/shopping_cart/product_info.py b/shop/shop/shopping_cart/product_info.py similarity index 90% rename from webshop/webshop/shopping_cart/product_info.py rename to shop/shop/shopping_cart/product_info.py index 97e5871f01..76454457cc 100644 --- a/webshop/webshop/shopping_cart/product_info.py +++ b/shop/shop/shopping_cart/product_info.py @@ -3,14 +3,14 @@ import frappe -from webshop.webshop.doctype.webshop_settings.webshop_settings import ( +from shop.shop.doctype.shop_settings.shop_settings import ( get_shopping_cart_settings, show_quantity_in_website, ) -from webshop.webshop.shopping_cart.cart import _get_cart_quotation, _set_price_list +from shop.shop.shopping_cart.cart import _get_cart_quotation, _set_price_list from erpnext.utilities.product import (get_price) -from webshop.webshop.utils.product import (get_non_stock_item_status, get_web_item_qty_in_stock) -from webshop.webshop.shopping_cart.cart import get_party +from shop.shop.utils.product import (get_non_stock_item_status, get_web_item_qty_in_stock) +from shop.shop.shopping_cart.cart import get_party @frappe.whitelist(allow_guest=True) diff --git a/webshop/webshop/shopping_cart/test_shopping_cart.py b/shop/shop/shopping_cart/test_shopping_cart.py similarity index 96% rename from webshop/webshop/shopping_cart/test_shopping_cart.py rename to shop/shop/shopping_cart/test_shopping_cart.py index 40dacbc30f..7b3bb5094a 100644 --- a/webshop/webshop/shopping_cart/test_shopping_cart.py +++ b/shop/shop/shopping_cart/test_shopping_cart.py @@ -9,8 +9,8 @@ from frappe.utils import add_months, cint, nowdate from erpnext.accounts.doctype.tax_rule.tax_rule import ConflictingTaxRule -from webshop.webshop.doctype.website_item.website_item import make_website_item -from webshop.webshop.shopping_cart.cart import ( +from shop.shop.doctype.website_item.website_item import make_website_item +from shop.shop.shopping_cart.cart import ( _get_cart_quotation, get_cart_quotation, get_party, @@ -174,7 +174,7 @@ def test_tax_rule(self): self.remove_test_quotation(quotation) @change_settings( - "Webshop Settings", + "Shop Settings", { "company": "_Test Company", "enabled": 1, @@ -210,7 +210,7 @@ def test_add_item_variant_without_web_item_to_cart(self): # test if items are rendered without error frappe.render_template("templates/includes/cart/cart_items.html", cart) - @change_settings("Webshop Settings", {"save_quotations_as_draft": 1}) + @change_settings("Shop Settings", {"save_quotations_as_draft": 1}) def test_cart_without_checkout_and_draft_quotation(self): "Test impact of 'save_quotations_as_draft' checkbox." frappe.local.shopping_cart_settings = None @@ -222,7 +222,7 @@ def test_cart_without_checkout_and_draft_quotation(self): self.assertEqual(quote_doctstatus, 0) - frappe.db.set_single_value("Webshop Settings", "save_quotations_as_draft", 0) + frappe.db.set_single_value("Shop Settings", "save_quotations_as_draft", 0) frappe.local.shopping_cart_settings = None update_cart("_Test Item", 1) quote_name = request_for_quotation() # Request for Quote @@ -270,7 +270,7 @@ def remove_test_quotation(self, quotation): # helper functions def enable_shopping_cart(self): - settings = frappe.get_doc("Webshop Settings") + settings = frappe.get_doc("Shop Settings") settings.update( { @@ -307,7 +307,7 @@ def enable_shopping_cart(self): frappe.local.shopping_cart_settings = None def disable_shopping_cart(self): - settings = frappe.get_doc("Webshop Settings") + settings = frappe.get_doc("Shop Settings") settings.enabled = 0 settings.save() frappe.local.shopping_cart_settings = None diff --git a/webshop/webshop/shopping_cart/utils.py b/shop/shop/shopping_cart/utils.py similarity index 89% rename from webshop/webshop/shopping_cart/utils.py rename to shop/shop/shopping_cart/utils.py index cf3e5a1f4f..49218fcc21 100644 --- a/webshop/webshop/shopping_cart/utils.py +++ b/shop/shop/shopping_cart/utils.py @@ -2,7 +2,7 @@ # License: GNU General Public License v3. See license.txt import frappe -from webshop.webshop.doctype.webshop_settings.webshop_settings import is_cart_enabled +from shop.shop.doctype.shop_settings.shop_settings import is_cart_enabled def show_cart_count(): @@ -24,7 +24,7 @@ def set_cart_count(login_manager): return if show_cart_count(): - from webshop.webshop.shopping_cart.cart import set_cart_count + from shop.shop.shopping_cart.cart import set_cart_count # set_cart_count will try to fetch existing cart quotation # or create one if non existent (and create a customer too) diff --git a/webshop/webshop/doctype/wishlist_item/__init__.py b/shop/shop/utils/__init__.py similarity index 100% rename from webshop/webshop/doctype/wishlist_item/__init__.py rename to shop/shop/utils/__init__.py diff --git a/webshop/webshop/utils/portal.py b/shop/shop/utils/portal.py similarity index 90% rename from webshop/webshop/utils/portal.py rename to shop/shop/utils/portal.py index 72fdfb08b6..e5c0fa3b84 100644 --- a/webshop/webshop/utils/portal.py +++ b/shop/shop/utils/portal.py @@ -3,10 +3,10 @@ from erpnext.portal.utils import create_customer_or_supplier -from webshop.webshop.doctype.webshop_settings.webshop_settings import ( +from shop.shop.doctype.shop_settings.shop_settings import ( get_shopping_cart_settings, ) -from webshop.webshop.shopping_cart.cart import get_debtors_account +from shop.shop.shopping_cart.cart import get_debtors_account def update_debtors_account(): diff --git a/webshop/webshop/utils/product.py b/shop/shop/utils/product.py similarity index 100% rename from webshop/webshop/utils/product.py rename to shop/shop/utils/product.py diff --git a/webshop/webshop/utils/setup.py b/shop/shop/utils/setup.py similarity index 100% rename from webshop/webshop/utils/setup.py rename to shop/shop/utils/setup.py diff --git a/webshop/webshop/shopping_cart/__init__.py b/shop/shop/variant_selector/__init__.py similarity index 100% rename from webshop/webshop/shopping_cart/__init__.py rename to shop/shop/variant_selector/__init__.py diff --git a/webshop/webshop/variant_selector/item_variants_cache.py b/shop/shop/variant_selector/item_variants_cache.py similarity index 98% rename from webshop/webshop/variant_selector/item_variants_cache.py rename to shop/shop/variant_selector/item_variants_cache.py index 1339d16f58..06bb1457f6 100644 --- a/webshop/webshop/variant_selector/item_variants_cache.py +++ b/shop/shop/variant_selector/item_variants_cache.py @@ -124,7 +124,7 @@ def enqueue_build_cache(item_code): if frappe.cache().hget("item_cache_build_in_progress", item_code): return frappe.enqueue( - "webshop.webshop.variant_selector.item_variants_cache.build_cache", + "shop.shop.variant_selector.item_variants_cache.build_cache", item_code=item_code, queue="long", ) diff --git a/webshop/webshop/variant_selector/test_variant_selector.py b/shop/shop/variant_selector/test_variant_selector.py similarity index 89% rename from webshop/webshop/variant_selector/test_variant_selector.py rename to shop/shop/variant_selector/test_variant_selector.py index e48e1499fc..cc783e3650 100644 --- a/webshop/webshop/variant_selector/test_variant_selector.py +++ b/shop/shop/variant_selector/test_variant_selector.py @@ -2,11 +2,11 @@ from frappe.tests.utils import FrappeTestCase from erpnext.controllers.item_variant import create_variant -from webshop.webshop.doctype.webshop_settings.test_webshop_settings import ( - setup_webshop_settings, +from shop.shop.doctype.shop_settings.test_shop_settings import ( + setup_shop_settings, ) -from webshop.webshop.doctype.website_item.website_item import make_website_item -from webshop.webshop.variant_selector.utils import get_next_attribute_and_values +from shop.shop.doctype.website_item.website_item import make_website_item +from shop.shop.variant_selector.utils import get_next_attribute_and_values from erpnext.stock.doctype.item.test_item import make_item test_dependencies = ["Item"] @@ -49,7 +49,7 @@ def test_item_attributes(self): Attribute selection must not be linked to Website Items. """ - from webshop.webshop.variant_selector.utils import get_attributes_and_values + from shop.shop.variant_selector.utils import get_attributes_and_values attr_data = get_attributes_and_values("Test-Tshirt-Temp") @@ -97,10 +97,10 @@ def test_exact_match_with_price(self): """ Test price fetching and matching of variant without Website Item """ - from webshop.webshop.doctype.website_item.test_website_item import make_web_item_price + from shop.shop.doctype.website_item.test_website_item import make_web_item_price frappe.set_user("Administrator") - setup_webshop_settings( + setup_shop_settings( { "company": "_Test Company", "enabled": 1, diff --git a/webshop/webshop/variant_selector/utils.py b/shop/shop/variant_selector/utils.py similarity index 97% rename from webshop/webshop/variant_selector/utils.py rename to shop/shop/variant_selector/utils.py index 976a6e2074..9a2467ea8f 100644 --- a/webshop/webshop/variant_selector/utils.py +++ b/shop/shop/variant_selector/utils.py @@ -1,11 +1,11 @@ import frappe from frappe.utils import cint, flt -from webshop.webshop.doctype.webshop_settings.webshop_settings import ( +from shop.shop.doctype.shop_settings.shop_settings import ( get_shopping_cart_settings, ) -from webshop.webshop.shopping_cart.cart import _set_price_list -from webshop.webshop.variant_selector.item_variants_cache import ItemVariantsCacheManager +from shop.shop.shopping_cart.cart import _set_price_list +from shop.shop.variant_selector.item_variants_cache import ItemVariantsCacheManager from erpnext.utilities.product import get_price diff --git a/webshop/webshop/utils/__init__.py b/shop/shop/web_template/__init__.py similarity index 100% rename from webshop/webshop/utils/__init__.py rename to shop/shop/web_template/__init__.py diff --git a/webshop/webshop/variant_selector/__init__.py b/shop/shop/web_template/hero_slider/__init__.py similarity index 100% rename from webshop/webshop/variant_selector/__init__.py rename to shop/shop/web_template/hero_slider/__init__.py diff --git a/webshop/webshop/web_template/hero_slider/hero_slider.html b/shop/shop/web_template/hero_slider/hero_slider.html similarity index 100% rename from webshop/webshop/web_template/hero_slider/hero_slider.html rename to shop/shop/web_template/hero_slider/hero_slider.html diff --git a/webshop/webshop/web_template/hero_slider/hero_slider.json b/shop/shop/web_template/hero_slider/hero_slider.json similarity index 99% rename from webshop/webshop/web_template/hero_slider/hero_slider.json rename to shop/shop/web_template/hero_slider/hero_slider.json index 71c583e032..02c7caba54 100644 --- a/webshop/webshop/web_template/hero_slider/hero_slider.json +++ b/shop/shop/web_template/hero_slider/hero_slider.json @@ -276,7 +276,7 @@ "idx": 2, "modified": "2023-10-16 18:00:52.933687", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Hero Slider", "owner": "Administrator", "standard": 1, diff --git a/webshop/webshop/web_template/__init__.py b/shop/shop/web_template/item_card_group/__init__.py similarity index 100% rename from webshop/webshop/web_template/__init__.py rename to shop/shop/web_template/item_card_group/__init__.py diff --git a/webshop/webshop/web_template/item_card_group/item_card_group.html b/shop/shop/web_template/item_card_group/item_card_group.html similarity index 100% rename from webshop/webshop/web_template/item_card_group/item_card_group.html rename to shop/shop/web_template/item_card_group/item_card_group.html diff --git a/webshop/webshop/web_template/item_card_group/item_card_group.json b/shop/shop/web_template/item_card_group/item_card_group.json similarity index 99% rename from webshop/webshop/web_template/item_card_group/item_card_group.json rename to shop/shop/web_template/item_card_group/item_card_group.json index 9e60a261ef..db4964834f 100644 --- a/webshop/webshop/web_template/item_card_group/item_card_group.json +++ b/shop/shop/web_template/item_card_group/item_card_group.json @@ -261,7 +261,7 @@ "idx": 0, "modified": "2023-10-16 18:01:47.576190", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Item Card Group", "owner": "Administrator", "standard": 1, diff --git a/webshop/webshop/web_template/hero_slider/__init__.py b/shop/shop/web_template/product_card/__init__.py similarity index 100% rename from webshop/webshop/web_template/hero_slider/__init__.py rename to shop/shop/web_template/product_card/__init__.py diff --git a/webshop/webshop/web_template/product_card/product_card.html b/shop/shop/web_template/product_card/product_card.html similarity index 100% rename from webshop/webshop/web_template/product_card/product_card.html rename to shop/shop/web_template/product_card/product_card.html diff --git a/webshop/webshop/web_template/product_card/product_card.json b/shop/shop/web_template/product_card/product_card.json similarity index 96% rename from webshop/webshop/web_template/product_card/product_card.json rename to shop/shop/web_template/product_card/product_card.json index 635890d26e..8dbfc62e77 100644 --- a/webshop/webshop/web_template/product_card/product_card.json +++ b/shop/shop/web_template/product_card/product_card.json @@ -22,7 +22,7 @@ "idx": 0, "modified": "2024-06-17 15:15:09.902754", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Product Card", "owner": "Administrator", "standard": 1, diff --git a/webshop/webshop/web_template/item_card_group/__init__.py b/shop/shop/web_template/product_category_cards/__init__.py similarity index 100% rename from webshop/webshop/web_template/item_card_group/__init__.py rename to shop/shop/web_template/product_category_cards/__init__.py diff --git a/webshop/webshop/web_template/product_category_cards/product_category_cards.html b/shop/shop/web_template/product_category_cards/product_category_cards.html similarity index 100% rename from webshop/webshop/web_template/product_category_cards/product_category_cards.html rename to shop/shop/web_template/product_category_cards/product_category_cards.html diff --git a/webshop/webshop/web_template/product_category_cards/product_category_cards.json b/shop/shop/web_template/product_category_cards/product_category_cards.json similarity index 98% rename from webshop/webshop/web_template/product_category_cards/product_category_cards.json rename to shop/shop/web_template/product_category_cards/product_category_cards.json index 2c939fe0b1..a88d9c8097 100644 --- a/webshop/webshop/web_template/product_category_cards/product_category_cards.json +++ b/shop/shop/web_template/product_category_cards/product_category_cards.json @@ -76,7 +76,7 @@ "idx": 0, "modified": "2023-10-16 18:02:24.342186", "modified_by": "Administrator", - "module": "Webshop", + "module": "Shop", "name": "Product Category Cards", "owner": "Administrator", "standard": 1, diff --git a/webshop/webshop/web_template/product_card/__init__.py b/shop/templates/__init__.py similarity index 100% rename from webshop/webshop/web_template/product_card/__init__.py rename to shop/templates/__init__.py diff --git a/webshop/templates/generators/item/item.html b/shop/templates/generators/item/item.html similarity index 100% rename from webshop/templates/generators/item/item.html rename to shop/templates/generators/item/item.html diff --git a/webshop/templates/generators/item/item_add_to_cart.html b/shop/templates/generators/item/item_add_to_cart.html similarity index 98% rename from webshop/templates/generators/item/item_add_to_cart.html rename to shop/templates/generators/item/item_add_to_cart.html index c49dba5edb..006ad5be54 100644 --- a/webshop/templates/generators/item/item_add_to_cart.html +++ b/shop/templates/generators/item/item_add_to_cart.html @@ -129,7 +129,7 @@ const $btn = $(e.currentTarget); $btn.prop('disabled', true); const item_code = $btn.data('item-code'); - webshop.webshop.shopping_cart.update_cart({ + shop.shop.shopping_cart.update_cart({ item_code, qty: 1, callback(r) { @@ -161,7 +161,7 @@ }); frappe.call({ - method: 'webshop.webshop.doctype.website_offer.website_offer.get_offer_details', + method: 'shop.shop.doctype.website_offer.website_offer.get_offer_details', args: { offer_id: $btn.data('offer-id') }, diff --git a/webshop/templates/generators/item/item_configure.html b/shop/templates/generators/item/item_configure.html similarity index 100% rename from webshop/templates/generators/item/item_configure.html rename to shop/templates/generators/item/item_configure.html diff --git a/webshop/templates/generators/item/item_configure.js b/shop/templates/generators/item/item_configure.js similarity index 97% rename from webshop/templates/generators/item/item_configure.js rename to shop/templates/generators/item/item_configure.js index d6e774adf8..398c2d58d7 100644 --- a/webshop/templates/generators/item/item_configure.js +++ b/shop/templates/generators/item/item_configure.js @@ -249,7 +249,7 @@ class ItemConfigure { const additional_notes = Object.keys(this.range_values || {}).map(attribute => { return `${attribute}: ${this.range_values[attribute]}`; }).join('\n'); - webshop.webshop.shopping_cart.update_cart({ + shop.shop.shopping_cart.update_cart({ item_code, additional_notes, qty: 1 @@ -284,14 +284,14 @@ class ItemConfigure { } get_next_attribute_and_values(selected_attributes) { - return this.call('webshop.webshop.variant_selector.utils.get_next_attribute_and_values', { + return this.call('shop.shop.variant_selector.utils.get_next_attribute_and_values', { item_code: this.item_code, selected_attributes }); } get_attributes_and_values() { - return this.call('webshop.webshop.variant_selector.utils.get_attributes_and_values', { + return this.call('shop.shop.variant_selector.utils.get_attributes_and_values', { item_code: this.item_code }); } diff --git a/webshop/templates/generators/item/item_details.html b/shop/templates/generators/item/item_details.html similarity index 97% rename from webshop/templates/generators/item/item_details.html rename to shop/templates/generators/item/item_details.html index 3ef2d3394c..3c4595e6d5 100644 --- a/webshop/templates/generators/item/item_details.html +++ b/shop/templates/generators/item/item_details.html @@ -64,6 +64,6 @@ $('.page_content').on('click', '.like-action-item-fp', (e) => { // Bind action on wishlist button const $btn = $(e.currentTarget); - webshop.webshop.wishlist.wishlist_action($btn); + shop.shop.wishlist.wishlist_action($btn); }); diff --git a/webshop/templates/generators/item/item_image.html b/shop/templates/generators/item/item_image.html similarity index 100% rename from webshop/templates/generators/item/item_image.html rename to shop/templates/generators/item/item_image.html diff --git a/webshop/templates/generators/item/item_inquiry.html b/shop/templates/generators/item/item_inquiry.html similarity index 100% rename from webshop/templates/generators/item/item_inquiry.html rename to shop/templates/generators/item/item_inquiry.html diff --git a/webshop/templates/generators/item/item_inquiry.js b/shop/templates/generators/item/item_inquiry.js similarity index 94% rename from webshop/templates/generators/item/item_inquiry.js rename to shop/templates/generators/item/item_inquiry.js index 1a724c1f69..7f8d5b38c5 100644 --- a/webshop/templates/generators/item/item_inquiry.js +++ b/shop/templates/generators/item/item_inquiry.js @@ -52,7 +52,7 @@ frappe.ready(() => { d.hide(); - frappe.call('webshop.webshop.shopping_cart.cart.create_lead_for_item_inquiry', { + frappe.call('shop.shop.shopping_cart.cart.create_lead_for_item_inquiry', { lead: doc, subject: values.subject, message: values.message diff --git a/webshop/templates/generators/item/item_reviews.html b/shop/templates/generators/item/item_reviews.html similarity index 96% rename from webshop/templates/generators/item/item_reviews.html rename to shop/templates/generators/item/item_reviews.html index f1c7b67bdc..1c8c405e2c 100644 --- a/webshop/templates/generators/item/item_reviews.html +++ b/shop/templates/generators/item/item_reviews.html @@ -58,7 +58,7 @@
primary_action: function() { var 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: "{{ doc.name }}", title: data.title, diff --git a/webshop/templates/generators/item/item_specifications.html b/shop/templates/generators/item/item_specifications.html similarity index 100% rename from webshop/templates/generators/item/item_specifications.html rename to shop/templates/generators/item/item_specifications.html diff --git a/webshop/templates/generators/item_group.html b/shop/templates/generators/item_group.html similarity index 100% rename from webshop/templates/generators/item_group.html rename to shop/templates/generators/item_group.html diff --git a/webshop/templates/includes/cart/address_card.html b/shop/templates/includes/cart/address_card.html similarity index 100% rename from webshop/templates/includes/cart/address_card.html rename to shop/templates/includes/cart/address_card.html diff --git a/webshop/templates/includes/cart/address_picker_card.html b/shop/templates/includes/cart/address_picker_card.html similarity index 100% rename from webshop/templates/includes/cart/address_picker_card.html rename to shop/templates/includes/cart/address_picker_card.html diff --git a/webshop/templates/includes/cart/cart_address.html b/shop/templates/includes/cart/cart_address.html similarity index 96% rename from webshop/templates/includes/cart/cart_address.html rename to shop/templates/includes/cart/cart_address.html index c12f5796dc..ea127ed2df 100644 --- a/webshop/templates/includes/cart/cart_address.html +++ b/shop/templates/includes/cart/cart_address.html @@ -137,10 +137,10 @@ ], primary_action_label: '{{ _("Save") }}', primary_action: (values) => { - frappe.call('webshop.webshop.shopping_cart.cart.add_new_address', { doc: values }) + frappe.call('shop.shop.shopping_cart.cart.add_new_address', { doc: values }) .then(r => { frappe.call({ - method: "webshop.webshop.shopping_cart.cart.update_cart_address", + method: "shop.shop.shopping_cart.cart.update_cart_address", args: { address_type: r.message.address_type, address_name: r.message.name @@ -203,7 +203,7 @@ const address_name = $card.closest('[data-address-name]').attr('data-address-name'); frappe.call({ type: "POST", - method: "webshop.webshop.shopping_cart.cart.update_cart_address", + method: "shop.shop.shopping_cart.cart.update_cart_address", freeze: true, args: { address_type, diff --git a/webshop/templates/includes/cart/cart_address_picker.html b/shop/templates/includes/cart/cart_address_picker.html similarity index 100% rename from webshop/templates/includes/cart/cart_address_picker.html rename to shop/templates/includes/cart/cart_address_picker.html diff --git a/webshop/templates/includes/cart/cart_dropdown.html b/shop/templates/includes/cart/cart_dropdown.html similarity index 100% rename from webshop/templates/includes/cart/cart_dropdown.html rename to shop/templates/includes/cart/cart_dropdown.html diff --git a/webshop/templates/includes/cart/cart_items.html b/shop/templates/includes/cart/cart_items.html similarity index 100% rename from webshop/templates/includes/cart/cart_items.html rename to shop/templates/includes/cart/cart_items.html diff --git a/webshop/templates/includes/cart/cart_items_dropdown.html b/shop/templates/includes/cart/cart_items_dropdown.html similarity index 100% rename from webshop/templates/includes/cart/cart_items_dropdown.html rename to shop/templates/includes/cart/cart_items_dropdown.html diff --git a/webshop/templates/includes/cart/cart_items_total.html b/shop/templates/includes/cart/cart_items_total.html similarity index 100% rename from webshop/templates/includes/cart/cart_items_total.html rename to shop/templates/includes/cart/cart_items_total.html diff --git a/webshop/templates/includes/cart/cart_macros.html b/shop/templates/includes/cart/cart_macros.html similarity index 100% rename from webshop/templates/includes/cart/cart_macros.html rename to shop/templates/includes/cart/cart_macros.html diff --git a/webshop/templates/includes/cart/cart_payment_summary.html b/shop/templates/includes/cart/cart_payment_summary.html similarity index 100% rename from webshop/templates/includes/cart/cart_payment_summary.html rename to shop/templates/includes/cart/cart_payment_summary.html diff --git a/webshop/templates/includes/cart/coupon_code.html b/shop/templates/includes/cart/coupon_code.html similarity index 100% rename from webshop/templates/includes/cart/coupon_code.html rename to shop/templates/includes/cart/coupon_code.html diff --git a/webshop/templates/includes/cart/place_order.html b/shop/templates/includes/cart/place_order.html similarity index 100% rename from webshop/templates/includes/cart/place_order.html rename to shop/templates/includes/cart/place_order.html diff --git a/webshop/templates/includes/macros.html b/shop/templates/includes/macros.html similarity index 100% rename from webshop/templates/includes/macros.html rename to shop/templates/includes/macros.html diff --git a/webshop/templates/includes/navbar/navbar_items.html b/shop/templates/includes/navbar/navbar_items.html similarity index 89% rename from webshop/templates/includes/navbar/navbar_items.html rename to shop/templates/includes/navbar/navbar_items.html index 73e97bf913..54f7163c02 100644 --- a/webshop/templates/includes/navbar/navbar_items.html +++ b/shop/templates/includes/navbar/navbar_items.html @@ -9,7 +9,7 @@ - {% if frappe.db.get_single_value("Webshop Settings", "enable_wishlist") %} + {% if frappe.db.get_single_value("Shop Settings", "enable_wishlist") %} - {% if frappe.db.get_single_value("Shop Settings", "enable_wishlist") %} - - {% endif %} -{% endblock %} + +
  • + + + + + + +
  • +{% if frappe.db.get_single_value("Shop Settings", "enable_wishlist") %} +
  • + + + + + + +
  • +{% endif %} +{% endblock %} \ No newline at end of file From 61176450f1d3ef7304dc25042a1e67541b0d1016 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Thu, 19 Feb 2026 16:56:33 +0530 Subject: [PATCH 41/62] feat: add mobile bottom navigation bar with Home, Products, Cart, Wishlist tabs --- shop/public/js/shopping_cart.js | 58 +++++++++++++++++++++ shop/public/scss/shop_cart.scss | 92 +++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/shop/public/js/shopping_cart.js b/shop/public/js/shopping_cart.js index 6658a749ec..50c1407d39 100644 --- a/shop/public/js/shopping_cart.js +++ b/shop/public/js/shopping_cart.js @@ -58,6 +58,9 @@ frappe.ready(function () { shopping_cart.show_cart_navbar(); console.log("Standard Shopping Cart Initialized"); shopping_cart.bind_add_to_cart_action(); + + // Mobile Bottom Navigation Bar + shopping_cart.inject_mobile_bottom_nav(); }); $.extend(shopping_cart, { @@ -257,5 +260,60 @@ $.extend(shopping_cart, { freeze.remove(); }, 1); } + }, + + inject_mobile_bottom_nav() { + // Only inject once + if ($('#mobile-bottom-nav').length) return; + + let path = window.location.pathname; + let active = function (p) { + if (p === '/' && path === '/') return 'active'; + if (p !== '/' && path.startsWith(p)) return 'active'; + return ''; + }; + + let cart_count = frappe.get_cookie("cart_count") || 0; + let cart_badge = cart_count > 0 ? `${cart_count}` : ''; + + let html = ` + + `; + + $('body').append(html); } }); diff --git a/shop/public/scss/shop_cart.scss b/shop/public/scss/shop_cart.scss index 38ad31ee31..92567dcd40 100644 --- a/shop/public/scss/shop_cart.scss +++ b/shop/public/scss/shop_cart.scss @@ -1877,4 +1877,96 @@ body.product-page { .w-fit { width: fit-content !important; +} + +// ============================================================ +// Mobile Bottom Navigation Bar +// ============================================================ +#mobile-bottom-nav { + display: none; // Hidden on desktop +} + +@media (max-width: 768px) { + #mobile-bottom-nav { + display: flex !important; + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: 1050; + background: #ffffff; + border-top: 1px solid #e0e0e0; + box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.08); + padding: 6px 0; + padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px)); + } + + .mobile-nav-item { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-decoration: none !important; + color: #888 !important; + font-size: 10px; + font-weight: 500; + gap: 2px; + padding: 4px 0; + transition: color 0.2s ease; + + &.active { + color: var(--primary-color, #F47B20) !important; + + .mobile-nav-icon { + stroke: var(--primary-color, #F47B20); + } + } + + &:hover, + &:active { + color: var(--primary-color, #F47B20) !important; + } + } + + .mobile-nav-icon { + width: 22px; + height: 22px; + stroke: #888; + stroke-linecap: round; + stroke-linejoin: round; + transition: stroke 0.2s ease; + } + + .mobile-nav-icon-wrapper { + position: relative; + display: inline-flex; + } + + .mobile-nav-badge { + position: absolute; + top: -6px; + right: -8px; + background: var(--primary-color, #F47B20); + color: #fff; + font-size: 9px; + font-weight: 700; + width: 16px; + height: 16px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + line-height: 1; + } + + // Ensure page content doesn't hide behind bottom nav + body { + padding-bottom: 65px !important; + } + + // Hide the cart page's sticky bar bottom spacing conflict + .mobile-sticky-bar { + bottom: 58px !important; + } } \ No newline at end of file From 089927e928207fd5952bc6e09f2a05521a1485b6 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Thu, 19 Feb 2026 17:07:36 +0530 Subject: [PATCH 42/62] fix: use frappe.db.get_single_value for UPI settings and add debug logging --- shop/www/upi_payment.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/shop/www/upi_payment.py b/shop/www/upi_payment.py index fc3949683a..f6b67bf156 100644 --- a/shop/www/upi_payment.py +++ b/shop/www/upi_payment.py @@ -10,36 +10,30 @@ def get_context(context): return # Fetch the Sales Order document - try: - order = frappe.get_doc("Sales Order", order_id) - except frappe.DoesNotExistError: - # Fallback to Quotation if Sales Order doesn't exist yet (in case of draft/checkout flow issues) - try: - order = frappe.get_doc("Quotation", order_id) - except frappe.DoesNotExistError: - context.error = "Order not found" - return + order = None + for doctype in ["Sales Order", "Quotation"]: + if frappe.db.exists(doctype, order_id): + order = frappe.get_doc(doctype, order_id) + break - # Check permissions - crucial for security - # Allow if user is the owner or if it's a guest order with matching email/session - if order.owner != frappe.session.user and not (frappe.session.user == "Guest"): - # For Guests, we might need a looser check or rely on a signed token. - # For now, we'll assume valid redirection implies access for the session. - # In a strict production env, verify a token. - pass + if not order: + context.error = "Order not found" + return context.order = order context.amount = order.grand_total context.currency = order.currency - # Fetch UPI settings - shop_settings = frappe.get_doc("Shop Settings") - context.upi_id = shop_settings.upi_id - context.payee_name = shop_settings.payee_name + # Fetch UPI settings using get_single_value (more reliable for Singles) + context.upi_id = frappe.db.get_single_value("Shop Settings", "upi_id") + context.payee_name = frappe.db.get_single_value("Shop Settings", "payee_name") + + # Debug log to help troubleshoot + frappe.logger().info(f"UPI Payment Page: upi_id='{context.upi_id}', payee_name='{context.payee_name}'") if not context.upi_id: context.error = "UPI ID not configured in Shop Settings" except Exception as e: frappe.log_error(f"Error in UPI Payment Page: {str(e)}") - context.error = "An error occurred while loading the payment page." + context.error = f"An error occurred: {str(e)}" From 74360bb5487b79ef345fa1be706d62b20015bfa6 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Thu, 19 Feb 2026 17:35:45 +0530 Subject: [PATCH 43/62] fix: use ignore_permissions to dynamically load Sales Order on UPI payment page --- shop/www/upi_payment.html | 2 +- shop/www/upi_payment.py | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index 4b03044c6f..1250594a5b 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -16,7 +16,7 @@

    Scan & Pay via UPI

    {% else %}

    Order: {{ order.name }}

    -

    {{ order.get_formatted("grand_total") }}

    +

    {{ formatted_amount or order.get_formatted("grand_total") }}

    diff --git a/shop/www/upi_payment.py b/shop/www/upi_payment.py index f6b67bf156..7460515e38 100644 --- a/shop/www/upi_payment.py +++ b/shop/www/upi_payment.py @@ -9,27 +9,32 @@ def get_context(context): context.error = "Order ID is missing" return - # Fetch the Sales Order document + # Fetch the order with ignore_permissions so any session can view their own order order = None for doctype in ["Sales Order", "Quotation"]: if frappe.db.exists(doctype, order_id): order = frappe.get_doc(doctype, order_id) + order.flags.ignore_permissions = True break if not order: - context.error = "Order not found" + context.error = "Order not found: " + order_id return context.order = order context.amount = order.grand_total + context.formatted_amount = order.get_formatted("grand_total") context.currency = order.currency - # Fetch UPI settings using get_single_value (more reliable for Singles) + # Fetch UPI settings using get_single_value (most reliable for Singles doctype) context.upi_id = frappe.db.get_single_value("Shop Settings", "upi_id") context.payee_name = frappe.db.get_single_value("Shop Settings", "payee_name") - # Debug log to help troubleshoot - frappe.logger().info(f"UPI Payment Page: upi_id='{context.upi_id}', payee_name='{context.payee_name}'") + # Debug log + frappe.logger().info( + f"UPI Payment: order={order_id}, amount={context.amount}, " + f"upi_id='{context.upi_id}', payee='{context.payee_name}'" + ) if not context.upi_id: context.error = "UPI ID not configured in Shop Settings" From 289ac68c60c0ce8cc9f4e1e40a3af6aefe80ecee Mon Sep 17 00:00:00 2001 From: Balaji K Date: Thu, 19 Feb 2026 17:42:04 +0530 Subject: [PATCH 44/62] fix: always show order details on UPI page; separate order-not-found vs UPI-not-configured errors --- shop/www/upi_payment.html | 56 ++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index 1250594a5b..7c056e269a 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -6,19 +6,36 @@
    -

    Scan & Pay via UPI

    +

    Scan & Pay via UPI

    - {% if error %} + + {# --- Critical errors (no order ID or order not found) --- #} + {% if error and not order %} + + {# --- Order found — always show order details --- #} {% else %} +
    -

    Order: {{ order.name }}

    -

    {{ formatted_amount or order.get_formatted("grand_total") }}

    +

    Order: {{ order.name }}

    +

    {{ formatted_amount or order.get_formatted("grand_total") }} +

    +
    + + {# --- UPI not configured warning (but still show order) --- #} + {% if error %} + + {% else %} + {# --- QR Code section --- #}
    @@ -33,19 +50,21 @@

    {{ formatted_amount or order.get_formatted("grand_total
    -
    +
    UPI ID: {{ upi_id }} Payee: {{ payee_name }}
    - + + {{ _("Pay via UPI App") }} + + + {% endif %} + + + {{ _("I Have Paid") }} + {% endif %}
    @@ -56,7 +75,7 @@

    {{ formatted_amount or order.get_formatted("grand_total From 921502d35b29677d075ca173e033c9b3d7e88d73 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Thu, 19 Feb 2026 17:59:59 +0530 Subject: [PATCH 45/62] fix: mobile cart totals and shipping charges for guests; added state selection for guests --- shop/public/js/shopping_cart.js | 12 ++++-- shop/shop/shopping_cart/cart.py | 43 +++++++++++++------ .../templates/includes/cart/cart_address.html | 1 + shop/templates/pages/cart.html | 7 +++ shop/templates/pages/cart.js | 43 +++++++++++++++++-- 5 files changed, 86 insertions(+), 20 deletions(-) diff --git a/shop/public/js/shopping_cart.js b/shop/public/js/shopping_cart.js index 50c1407d39..108337d7b3 100644 --- a/shop/public/js/shopping_cart.js +++ b/shop/public/js/shopping_cart.js @@ -168,10 +168,7 @@ $.extend(shopping_cart, { shopping_cart.set_cart_count(); // Update mobile sticky bar total - var $grand = $(".payment-summary .net-total").last(); - if ($grand.length) { - $(".mobile-sticky-bar .total-amount").text($grand.text()); - } + shopping_cart.update_mobile_sticky_bar(); if (cart_dropdown != true) { $(".cart-icon").hide(); @@ -181,6 +178,13 @@ $.extend(shopping_cart, { }); }, + update_mobile_sticky_bar: function () { + var $grand = $(".payment-summary .net-total").last(); + if ($grand.length) { + $(".mobile-sticky-bar .total-amount").text($grand.text()); + } + }, + show_cart_navbar: function () { shopping_cart.get_settings().then((settings) => { $(".shopping-cart").toggleClass('hidden', settings.enabled ? false : true); diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 552875a266..758e985dcf 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -356,6 +356,14 @@ def update_guest_country(country): return get_cart_quotation() +@frappe.whitelist(allow_guest=True) +def update_guest_state(state): + frappe.session.guest_state = state + # Apply cart settings again to refresh rules + apply_cart_settings() + return get_cart_quotation() + + def guess_territory(): territory = None geoip_country = frappe.session.get("session_country") @@ -491,16 +499,24 @@ def apply_cart_settings(party=None, quotation=None): cart_settings = get_shopping_cart_settings() + frappe.logger().debug(f"Applying cart settings for Quotation: {quotation.name}, Party: {party.name}") + set_price_list_and_rate(quotation, cart_settings) + frappe.logger().debug(f"After set_price_list_and_rate: Grand Total: {quotation.grand_total}, Net Total: {quotation.net_total}") quotation.run_method("calculate_taxes_and_totals") set_taxes(quotation, cart_settings) + frappe.logger().debug(f"After set_taxes: Taxes Count: {len(quotation.get('taxes'))}") _apply_shipping_rule(party, quotation, cart_settings) + frappe.logger().debug(f"After _apply_shipping_rule: Shipping Rule: {quotation.shipping_rule}, Grand Total: {quotation.grand_total}") if cart_settings.enable_manual_shipping_charge and not quotation.shipping_rule: _apply_manual_shipping_charge(quotation, cart_settings) + frappe.logger().debug(f"After manual shipping: Grand Total: {quotation.grand_total}") + + quotation.run_method("calculate_taxes_and_totals") def _apply_manual_shipping_charge(quotation, cart_settings): @@ -832,12 +848,19 @@ def get_shipping_rules(quotation=None, cart_settings=None): shipping_rules = [] country = None + state = None + if quotation.shipping_address_name: - country = frappe.db.get_value( - "Address", quotation.shipping_address_name, "country" + addr = frappe.db.get_value( + "Address", quotation.shipping_address_name, ["country", "state"], as_dict=True ) - elif frappe.session.get("guest_country"): - country = frappe.session.get("guest_country") + country = addr.country + state = addr.state + else: + if frappe.session.get("guest_country"): + country = frappe.session.get("guest_country") + if frappe.session.get("guest_state"): + state = frappe.session.get("guest_state") if country: sr_country = frappe.qb.DocType("Shipping Rule Country") @@ -853,15 +876,9 @@ def get_shipping_rules(quotation=None, cart_settings=None): result = query.run(as_list=True) shipping_rules = [x[0] for x in result] - if shipping_rules: - # Further filter by state - state = None - if quotation.shipping_address_name: - state = frappe.db.get_value("Address", quotation.shipping_address_name, "state") - - if state: - filtered_rules = [] - for rule in shipping_rules: + if shipping_rules and state: + filtered_rules = [] + for rule in shipping_rules: rule_states = frappe.get_all("Shipping Rule State", filters={"parent": rule}, fields=["state"]) if not rule_states: # If no states specified, it's a global rule for that country diff --git a/shop/templates/includes/cart/cart_address.html b/shop/templates/includes/cart/cart_address.html index cfeaf81f67..88dfb2dc4b 100644 --- a/shop/templates/includes/cart/cart_address.html +++ b/shop/templates/includes/cart/cart_address.html @@ -220,6 +220,7 @@
    {{ _("Billing Address") }}
    if (!r.exc) { $(".cart-tax-items").html(r.message.total); $(".payment-summary").html(r.message.payment_summary); + shopping_cart.update_mobile_sticky_bar(); shopping_cart.parent.find( `.address-container[data-address-type="${address_type}"]` ).html(r.message.address); diff --git a/shop/templates/pages/cart.html b/shop/templates/pages/cart.html index c7ffe90233..ab3121aabb 100644 --- a/shop/templates/pages/cart.html +++ b/shop/templates/pages/cart.html @@ -153,6 +153,13 @@
    {{ _("Alternatively, Checkout as Guest") }}
    {% endfor %}

    +
    + + +
    diff --git a/shop/templates/pages/cart.js b/shop/templates/pages/cart.js index c3e23d439a..d8ef69146b 100644 --- a/shop/templates/pages/cart.js +++ b/shop/templates/pages/cart.js @@ -20,6 +20,7 @@ $.extend(shopping_cart, { shopping_cart.bind_coupon_code(); shopping_cart.bind_remove_coupon_code(); shopping_cart.bind_guest_country_change(); + shopping_cart.bind_guest_state_change(); shopping_cart.bind_shipping_rule_change(); }, @@ -152,6 +153,8 @@ $.extend(shopping_cart, { fullname: $(".guest-fullname").val(), phone: $(".guest-phone").val(), address: $(".guest-address").val(), + state: $(".guest-state").val(), + country: $(".guest-country").val(), }; if (!guest_details.email || !guest_details.fullname || !guest_details.address) { @@ -260,6 +263,20 @@ $.extend(shopping_cart, { $(".guest-country").on("change", function () { var country = $(this).val(); if (country) { + // Populate states + frappe.call({ + method: "frappe.geo.utils.get_states", + args: { country: country }, + callback: function (r) { + var $state = $(".guest-state"); + $state.empty().append(''); + if (r.message) { + r.message.forEach(function (state) { + $state.append(''); + }); + } + } + }); shopping_cart.update_guest_country(country); } }); @@ -272,9 +289,29 @@ $.extend(shopping_cart, { args: { country: country }, callback: function (r) { if (r.message) { - // We need a way to re-render the taxes and totals - // If shopping_cart.render is missing, let's at least reload the parts we can - location.reload(); // Simplest fix for now to ensure all context is correct + location.reload(); + } + } + }); + }, + + bind_guest_state_change: function () { + $(".guest-state").on("change", function () { + var state = $(this).val(); + if (state) { + shopping_cart.update_guest_state(state); + } + }); + }, + + update_guest_state: function (state) { + return frappe.call({ + type: "POST", + method: "shop.shop.shopping_cart.cart.update_guest_state", + args: { state: state }, + callback: function (r) { + if (r.message) { + location.reload(); } } }); From 7b174b1dbe2f1a7f5193a3401a20ff6a4893c3f0 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Thu, 19 Feb 2026 18:03:30 +0530 Subject: [PATCH 46/62] fix: resolve 500 error caused by indentation and logging --- shop/shop/shopping_cart/cart.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 758e985dcf..d6588cda75 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -499,22 +499,16 @@ def apply_cart_settings(party=None, quotation=None): cart_settings = get_shopping_cart_settings() - frappe.logger().debug(f"Applying cart settings for Quotation: {quotation.name}, Party: {party.name}") - set_price_list_and_rate(quotation, cart_settings) - frappe.logger().debug(f"After set_price_list_and_rate: Grand Total: {quotation.grand_total}, Net Total: {quotation.net_total}") quotation.run_method("calculate_taxes_and_totals") set_taxes(quotation, cart_settings) - frappe.logger().debug(f"After set_taxes: Taxes Count: {len(quotation.get('taxes'))}") _apply_shipping_rule(party, quotation, cart_settings) - frappe.logger().debug(f"After _apply_shipping_rule: Shipping Rule: {quotation.shipping_rule}, Grand Total: {quotation.grand_total}") if cart_settings.enable_manual_shipping_charge and not quotation.shipping_rule: _apply_manual_shipping_charge(quotation, cart_settings) - frappe.logger().debug(f"After manual shipping: Grand Total: {quotation.grand_total}") quotation.run_method("calculate_taxes_and_totals") @@ -879,15 +873,15 @@ def get_shipping_rules(quotation=None, cart_settings=None): if shipping_rules and state: filtered_rules = [] for rule in shipping_rules: - rule_states = frappe.get_all("Shipping Rule State", filters={"parent": rule}, fields=["state"]) - if not rule_states: - # If no states specified, it's a global rule for that country - filtered_rules.append(rule) - elif any(s.state == state for s in rule_states): - # If current address state is in the list - filtered_rules.append(rule) - - shipping_rules = filtered_rules + rule_states = frappe.get_all("Shipping Rule State", filters={"parent": rule}, fields=["state"]) + if not rule_states: + # If no states specified, it's a global rule for that country + filtered_rules.append(rule) + elif any(s.state == state for s in rule_states): + # If current address state is in the list + filtered_rules.append(rule) + + shipping_rules = filtered_rules return shipping_rules From 6590b335677daa64e8937c0f8ae234936f1a968f Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 10:43:56 +0530 Subject: [PATCH 47/62] fix: auto-set shipping address for logged-in users to ensure shipping rules are applied --- shop/shop/shopping_cart/cart.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index d6588cda75..b4bd316182 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -45,6 +45,9 @@ def get_cart_quotation(doc=None): if not doc.customer_address and addresses: update_cart_address("billing", addresses[0].name) + if not doc.shipping_address_name and get_shipping_addresses(party): + update_cart_address("shipping", get_shipping_addresses(party)[0]["name"]) + return { "doc": decorate_quotation_doc(doc), "shipping_addresses": get_shipping_addresses(party), From 2078f54e0166c641030eeb4faf2b577681b1f082 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 10:53:15 +0530 Subject: [PATCH 48/62] fix: reload quotation doc after auto-setting addresses to ensure UI reflects latest state --- shop/shop/shopping_cart/cart.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index b4bd316182..a4dcbed18c 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -44,9 +44,11 @@ def get_cart_quotation(doc=None): if not doc.customer_address and addresses: update_cart_address("billing", addresses[0].name) + doc = _get_cart_quotation(party) if not doc.shipping_address_name and get_shipping_addresses(party): update_cart_address("shipping", get_shipping_addresses(party)[0]["name"]) + doc = _get_cart_quotation(party) return { "doc": decorate_quotation_doc(doc), From ea9ec0e46b55ba2237d37e50fae45ea2e49dbd8e Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 11:00:01 +0530 Subject: [PATCH 49/62] fix: robustness improvement for repeat orders - default shipping address to billing address if missing --- shop/shop/shopping_cart/cart.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index a4dcbed18c..647cd68b99 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -46,9 +46,13 @@ def get_cart_quotation(doc=None): update_cart_address("billing", addresses[0].name) doc = _get_cart_quotation(party) - if not doc.shipping_address_name and get_shipping_addresses(party): - update_cart_address("shipping", get_shipping_addresses(party)[0]["name"]) - doc = _get_cart_quotation(party) + if not doc.shipping_address_name: + if doc.customer_address: + update_cart_address("shipping", doc.customer_address) + doc = _get_cart_quotation(party) + elif get_shipping_addresses(party): + update_cart_address("shipping", get_shipping_addresses(party)[0]["name"]) + doc = _get_cart_quotation(party) return { "doc": decorate_quotation_doc(doc), From 3c5fbf41f96720ba5f87ab8394b9454643aca02c Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 11:05:08 +0530 Subject: [PATCH 50/62] fix: explicit copy of shipping rule and taxes from quotation to sales order to prevent data loss --- shop/shop/shopping_cart/cart.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 647cd68b99..22c802e506 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -130,6 +130,29 @@ def place_order(guest_details=None): quotation.name, ignore_permissions=True ) ) + + # Force copy shipping details to ensure they persist + if quotation.shipping_address_name: + sales_order.shipping_address_name = quotation.shipping_address_name + if quotation.shipping_rule: + sales_order.shipping_rule = quotation.shipping_rule + + # Ensure taxes are carried over exactly as is + if quotation.get("taxes"): + sales_order.set("taxes", []) + for tax in quotation.get("taxes"): + sales_order.append("taxes", { + "charge_type": tax.charge_type, + "account_head": tax.account_head, + "description": tax.description, + "included_in_print_rate": tax.included_in_print_rate, + "cost_center": tax.cost_center, + "rate": tax.rate, + "tax_amount": tax.tax_amount, + "total": tax.total, + "add_deduct": tax.add_deduct, + }) + sales_order.payment_schedule = [] if frappe.session.user == "Guest" and guest_details: From 46b3ff9844f10ecdcdd9ddb6a38ea09137848c20 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 11:09:29 +0530 Subject: [PATCH 51/62] fix: remove manual tax copy loop from place_order to prevent crash, retain shipping rule copy --- shop/shop/shopping_cart/cart.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 22c802e506..421c8e6cc1 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -136,22 +136,6 @@ def place_order(guest_details=None): sales_order.shipping_address_name = quotation.shipping_address_name if quotation.shipping_rule: sales_order.shipping_rule = quotation.shipping_rule - - # Ensure taxes are carried over exactly as is - if quotation.get("taxes"): - sales_order.set("taxes", []) - for tax in quotation.get("taxes"): - sales_order.append("taxes", { - "charge_type": tax.charge_type, - "account_head": tax.account_head, - "description": tax.description, - "included_in_print_rate": tax.included_in_print_rate, - "cost_center": tax.cost_center, - "rate": tax.rate, - "tax_amount": tax.tax_amount, - "total": tax.total, - "add_deduct": tax.add_deduct, - }) sales_order.payment_schedule = [] From e737344ec5bad65a3587f38bda840b230ab6edeb Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 11:16:04 +0530 Subject: [PATCH 52/62] fix: safely copy shipping address text and taxes to sales order to ensure correct totals --- shop/shop/shopping_cart/cart.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 421c8e6cc1..68b1855b14 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -134,8 +134,30 @@ def place_order(guest_details=None): # Force copy shipping details to ensure they persist if quotation.shipping_address_name: sales_order.shipping_address_name = quotation.shipping_address_name + sales_order.shipping_address = quotation.shipping_address + + if quotation.customer_address: + sales_order.customer_address = quotation.customer_address + sales_order.address_display = quotation.address_display + if quotation.shipping_rule: sales_order.shipping_rule = quotation.shipping_rule + + # Safely copy taxes to ensure totals match exactly + if quotation.get("taxes"): + sales_order.set("taxes", []) + for tax in quotation.get("taxes"): + sales_order.append("taxes", { + "charge_type": tax.charge_type, + "account_head": tax.account_head, + "description": tax.description, + "included_in_print_rate": tax.included_in_print_rate, + "cost_center": tax.cost_center, + "rate": tax.rate, + "tax_amount": tax.tax_amount, + "total": tax.total, + "add_deduct": tax.add_deduct, + }) sales_order.payment_schedule = [] From 9944acc244c707d1cf0542a260b75faccb14efc3 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 11:34:28 +0530 Subject: [PATCH 53/62] fix: safe address handling in get_cart_quotation to prevent 417 errors on invalid address --- shop/shop/shopping_cart/cart.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 68b1855b14..34cf6c9b95 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -47,12 +47,15 @@ def get_cart_quotation(doc=None): doc = _get_cart_quotation(party) if not doc.shipping_address_name: - if doc.customer_address: - update_cart_address("shipping", doc.customer_address) - doc = _get_cart_quotation(party) - elif get_shipping_addresses(party): - update_cart_address("shipping", get_shipping_addresses(party)[0]["name"]) - doc = _get_cart_quotation(party) + try: + if doc.customer_address and frappe.db.exists("Address", doc.customer_address): + update_cart_address("shipping", doc.customer_address) + doc = _get_cart_quotation(party) + elif get_shipping_addresses(party): + update_cart_address("shipping", get_shipping_addresses(party)[0]["name"]) + doc = _get_cart_quotation(party) + except Exception as e: + frappe.log_error(f"Error auto-setting shipping address: {str(e)}") return { "doc": decorate_quotation_doc(doc), From 534c1de00f47ea867416c035db6500a48e3abb2b Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 11:47:26 +0530 Subject: [PATCH 54/62] fix: remove tax copy loop again, but keep explicit address text copy to ensure correct calculation without crashing --- shop/shop/shopping_cart/cart.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 34cf6c9b95..a2d534de95 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -145,22 +145,6 @@ def place_order(guest_details=None): if quotation.shipping_rule: sales_order.shipping_rule = quotation.shipping_rule - - # Safely copy taxes to ensure totals match exactly - if quotation.get("taxes"): - sales_order.set("taxes", []) - for tax in quotation.get("taxes"): - sales_order.append("taxes", { - "charge_type": tax.charge_type, - "account_head": tax.account_head, - "description": tax.description, - "included_in_print_rate": tax.included_in_print_rate, - "cost_center": tax.cost_center, - "rate": tax.rate, - "tax_amount": tax.tax_amount, - "total": tax.total, - "add_deduct": tax.add_deduct, - }) sales_order.payment_schedule = [] From c58948282569de196923a53e5d5df0bf1a844a9d Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 11:58:22 +0530 Subject: [PATCH 55/62] fix: add cache busting to UPI redirect and debug logs to ensure fresh order data --- shop/shop/shopping_cart/cart.py | 1 + shop/templates/pages/cart.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index a2d534de95..4fba8f07cf 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -175,6 +175,7 @@ def place_order(guest_details=None): sales_order.flags.ignore_permissions = True sales_order.insert() + frappe.logger().info(f"Place Order: Created Sales Order {sales_order.name} from Quotation {quotation.name}") sales_order.submit() if hasattr(frappe.local, "cookie_manager"): diff --git a/shop/templates/pages/cart.js b/shop/templates/pages/cart.js index d8ef69146b..b7670aef26 100644 --- a/shop/templates/pages/cart.js +++ b/shop/templates/pages/cart.js @@ -185,7 +185,7 @@ $.extend(shopping_cart, { .toggle(true); } else { $(btn).hide(); - window.location.href = '/upi_payment?order=' + encodeURIComponent(r.message); + window.location.href = '/upi_payment?order=' + encodeURIComponent(r.message) + '&t=' + Date.now(); } } }); From 19c6f4f1307b9b800a5f18630a62017dd8f7e655 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 12:12:27 +0530 Subject: [PATCH 56/62] feat: remove pay via upi app button as requested --- shop/www/upi_payment.html | 9 --------- 1 file changed, 9 deletions(-) diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index 7c056e269a..65bf2222d0 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -55,10 +55,6 @@

    {{ formatted_amount or order.get_formatted("gra Payee: {{ payee_name }}

    - - {{ _("Pay via UPI App") }} - {% endif %} @@ -97,11 +93,6 @@

    {{ formatted_amount or order.get_formatted("gra correctLevel: QRCode.CorrectLevel.H }); - // Set UPI deep link for mobile - var deepLinkBtn = document.getElementById("btn-upi-deep-link"); - if (deepLinkBtn) { - deepLinkBtn.href = upiUrl; - } }); {% endif %} From 48862cbd6ee6f133969fa56eebec99dc4031ff2d Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 12:44:31 +0530 Subject: [PATCH 57/62] fix: add no_cache=1 for dynamic order number + make QR code static (UPI ID + payee only) --- shop/www/upi_payment.html | 14 +++++--------- shop/www/upi_payment.py | 12 +++++++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index 65bf2222d0..5c4dc18068 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -35,7 +35,7 @@

    {{ formatted_amount or order.get_formatted("gra

    {% else %} - {# --- QR Code section --- #} + {# --- Static QR Code section (UPI ID + Payee only, no order-specific data) --- #}
    @@ -55,7 +55,6 @@

    {{ formatted_amount or order.get_formatted("gra Payee: {{ payee_name }}

    - {% endif %} @@ -75,14 +74,12 @@

    {{ formatted_amount or order.get_formatted("gra document.addEventListener('DOMContentLoaded', function () { var upiId = "{{ upi_id }}"; var payeeName = "{{ payee_name }}"; - var amount = "{{ amount }}"; - var transactionNote = "Order {{ order.name }}"; - var currency = "{{ currency }}"; - var upiUrl = `upi://pay?pa=${encodeURIComponent(upiId)}&pn=${encodeURIComponent(payeeName)}&am=${amount}&cu=${currency}&tn=${encodeURIComponent(transactionNote)}&tr=${encodeURIComponent(transactionNote)}`; + // Static QR Code: Only UPI ID and Payee Name (no amount or order reference) + var upiUrl = "upi://pay?pa=" + encodeURIComponent(upiId) + "&pn=" + encodeURIComponent(payeeName); - console.log("UPI URL:", upiUrl); - console.log("Order:", "{{ order.name }}", "Amount:", amount); + console.log("UPI Static URL:", upiUrl); + console.log("Order:", "{{ order.name }}", "Amount:", "{{ amount }}"); new QRCode(document.getElementById("qrcode"), { text: upiUrl, @@ -92,7 +89,6 @@

    {{ formatted_amount or order.get_formatted("gra colorLight: "#ffffff", correctLevel: QRCode.CorrectLevel.H }); - }); {% endif %} diff --git a/shop/www/upi_payment.py b/shop/www/upi_payment.py index 7460515e38..f8a3a30462 100644 --- a/shop/www/upi_payment.py +++ b/shop/www/upi_payment.py @@ -1,6 +1,12 @@ import frappe +# CRITICAL: Disable Frappe page caching so the order number is always fresh +no_cache = 1 + def get_context(context): + # Disable caching at context level too + context.no_cache = 1 + try: # Get order ID from query parameters order_id = frappe.form_dict.get("order") @@ -26,14 +32,14 @@ def get_context(context): context.formatted_amount = order.get_formatted("grand_total") context.currency = order.currency - # Fetch UPI settings using get_single_value (most reliable for Singles doctype) + # Fetch UPI settings context.upi_id = frappe.db.get_single_value("Shop Settings", "upi_id") context.payee_name = frappe.db.get_single_value("Shop Settings", "payee_name") # Debug log frappe.logger().info( - f"UPI Payment: order={order_id}, amount={context.amount}, " - f"upi_id='{context.upi_id}', payee='{context.payee_name}'" + f"UPI Payment Page: order_id={order_id}, order.name={order.name}, " + f"grand_total={order.grand_total}, upi_id='{context.upi_id}'" ) if not context.upi_id: From 7b6fd9b9047fd15ee97e34e955d6df1d0db7cdab Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 12:52:45 +0530 Subject: [PATCH 58/62] fix: rewrite UPI page to use AJAX for dynamic order data - bypasses all Frappe page caching --- shop/shop/shopping_cart/cart.py | 30 ++++++ shop/www/upi_payment.html | 162 ++++++++++++++++++++------------ shop/www/upi_payment.py | 50 ++-------- 3 files changed, 137 insertions(+), 105 deletions(-) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 4fba8f07cf..2f1ce24645 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -329,6 +329,36 @@ def get_terms_and_conditions(terms_name): return frappe.db.get_value("Terms and Conditions", terms_name, "terms") +@frappe.whitelist(allow_guest=True) +def get_upi_payment_details(order_id): + """Return order details and UPI settings for the payment page. + Called via AJAX to bypass Frappe page caching.""" + if not order_id: + return {"error": "Order ID is missing"} + + order = None + for doctype in ["Sales Order", "Quotation"]: + if frappe.db.exists(doctype, order_id): + order = frappe.get_doc(doctype, order_id) + order.flags.ignore_permissions = True + break + + if not order: + return {"error": f"Order not found: {order_id}"} + + upi_id = frappe.db.get_single_value("Shop Settings", "upi_id") + payee_name = frappe.db.get_single_value("Shop Settings", "payee_name") + + return { + "order_name": order.name, + "grand_total": order.grand_total, + "formatted_amount": order.get_formatted("grand_total"), + "currency": order.currency, + "upi_id": upi_id or "", + "payee_name": payee_name or "", + } + + @frappe.whitelist(allow_guest=True) def update_cart_address(address_type, address_name): quotation = _get_cart_quotation() diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index 5c4dc18068..e5dceea858 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -10,58 +10,56 @@

    Scan & Pay via UPI

    @@ -70,26 +68,68 @@

    {{ formatted_amount or order.get_formatted("gra {% endblock %} \ No newline at end of file diff --git a/shop/www/upi_payment.py b/shop/www/upi_payment.py index f8a3a30462..72aad904b7 100644 --- a/shop/www/upi_payment.py +++ b/shop/www/upi_payment.py @@ -1,50 +1,12 @@ import frappe -# CRITICAL: Disable Frappe page caching so the order number is always fresh +# Prevent Frappe page caching no_cache = 1 def get_context(context): - # Disable caching at context level too context.no_cache = 1 - - try: - # Get order ID from query parameters - order_id = frappe.form_dict.get("order") - - if not order_id: - context.error = "Order ID is missing" - return - - # Fetch the order with ignore_permissions so any session can view their own order - order = None - for doctype in ["Sales Order", "Quotation"]: - if frappe.db.exists(doctype, order_id): - order = frappe.get_doc(doctype, order_id) - order.flags.ignore_permissions = True - break - - if not order: - context.error = "Order not found: " + order_id - return - - context.order = order - context.amount = order.grand_total - context.formatted_amount = order.get_formatted("grand_total") - context.currency = order.currency - - # Fetch UPI settings - context.upi_id = frappe.db.get_single_value("Shop Settings", "upi_id") - context.payee_name = frappe.db.get_single_value("Shop Settings", "payee_name") - - # Debug log - frappe.logger().info( - f"UPI Payment Page: order_id={order_id}, order.name={order.name}, " - f"grand_total={order.grand_total}, upi_id='{context.upi_id}'" - ) - - if not context.upi_id: - context.error = "UPI ID not configured in Shop Settings" - - except Exception as e: - frappe.log_error(f"Error in UPI Payment Page: {str(e)}") - context.error = f"An error occurred: {str(e)}" + # We only pass static UPI settings server-side. + # Order details are fetched dynamically via JavaScript AJAX call + # to completely bypass any Frappe/browser page caching. + context.upi_id = frappe.db.get_single_value("Shop Settings", "upi_id") or "" + context.payee_name = frappe.db.get_single_value("Shop Settings", "payee_name") or "" From b9df7af654309507081a6ca133ead7ca3ea8ef9c Mon Sep 17 00:00:00 2001 From: Balaji K Date: Fri, 20 Feb 2026 13:03:03 +0530 Subject: [PATCH 59/62] fix: shipping rule state priority + style I Have Paid button green --- shop/shop/shopping_cart/cart.py | 19 ++++++++++++------- shop/www/upi_payment.html | 5 +++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index 2f1ce24645..d1510f3806 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -927,17 +927,22 @@ def get_shipping_rules(quotation=None, cart_settings=None): shipping_rules = [x[0] for x in result] if shipping_rules and state: - filtered_rules = [] + state_specific_rules = [] + global_rules = [] # Rules with no states defined (fallback) for rule in shipping_rules: rule_states = frappe.get_all("Shipping Rule State", filters={"parent": rule}, fields=["state"]) if not rule_states: - # If no states specified, it's a global rule for that country - filtered_rules.append(rule) + # No states specified = global fallback for this country + global_rules.append(rule) elif any(s.state == state for s in rule_states): - # If current address state is in the list - filtered_rules.append(rule) - - shipping_rules = filtered_rules + # Matches the customer's specific state + state_specific_rules.append(rule) + + # Priority: state-specific rules first, then global fallback + if state_specific_rules: + shipping_rules = state_specific_rules + else: + shipping_rules = global_rules return shipping_rules diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index e5dceea858..d331f3d9a4 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -55,8 +55,9 @@

    {% endif %} - - {{ _("I Have Paid") }} + + ✅ {{ _("I Have Paid") }}

    From 1722ead11ea83948ec89ff7581692b471c68737f Mon Sep 17 00:00:00 2001 From: Balaji K Date: Mon, 23 Feb 2026 19:08:35 +0530 Subject: [PATCH 60/62] feat: UPI payment confirmation - deep link button, transaction form, custom fields on Sales Order --- shop/patches.txt | 3 +- shop/patches/add_upi_fields_to_sales_order.py | 46 +++++++ shop/setup/install.py | 37 ++++++ shop/shop/shopping_cart/cart.py | 31 +++++ shop/www/upi_payment.html | 121 +++++++++++++++--- 5 files changed, 220 insertions(+), 18 deletions(-) create mode 100644 shop/patches/add_upi_fields_to_sales_order.py diff --git a/shop/patches.txt b/shop/patches.txt index 8451ee40f9..72d480fb42 100644 --- a/shop/patches.txt +++ b/shop/patches.txt @@ -5,4 +5,5 @@ 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 \ No newline at end of file +shop.patches.add_shipping_rule_state_field +shop.patches.add_upi_fields_to_sales_order \ No newline at end of file diff --git a/shop/patches/add_upi_fields_to_sales_order.py b/shop/patches/add_upi_fields_to_sales_order.py new file mode 100644 index 0000000000..e4cf04434b --- /dev/null +++ b/shop/patches/add_upi_fields_to_sales_order.py @@ -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) diff --git a/shop/setup/install.py b/shop/setup/install.py index fcf0a3a3b4..f6ac687fcd 100644 --- a/shop/setup/install.py +++ b/shop/setup/install.py @@ -191,6 +191,43 @@ def add_custom_fields(): "options": "Shipping Rule State", "insert_after": "shipping_rule_states_section", }, + ], + "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, + }, ] } diff --git a/shop/shop/shopping_cart/cart.py b/shop/shop/shopping_cart/cart.py index d1510f3806..14f4d19bff 100644 --- a/shop/shop/shopping_cart/cart.py +++ b/shop/shop/shopping_cart/cart.py @@ -359,6 +359,37 @@ def get_upi_payment_details(order_id): } +@frappe.whitelist(allow_guest=True) +def confirm_upi_payment(order_id, transaction_id): + """Save UPI transaction details to the Sales Order.""" + if not order_id or not transaction_id: + return {"error": "Order ID and Transaction ID are required"} + + if not frappe.db.exists("Sales Order", order_id): + return {"error": f"Sales Order not found: {order_id}"} + + try: + frappe.db.set_value("Sales Order", order_id, { + "upi_transaction_id": transaction_id, + "upi_payment_date": frappe.utils.now(), + "upi_payment_status": "Paid", + }, update_modified=False) + frappe.db.commit() + + frappe.logger().info( + f"UPI Payment confirmed: order={order_id}, txn={transaction_id}" + ) + + return { + "success": True, + "order_name": order_id, + "message": "Payment confirmed successfully" + } + except Exception as e: + frappe.log_error(f"Error confirming UPI payment: {str(e)}") + return {"error": f"Failed to confirm payment: {str(e)}"} + + @frappe.whitelist(allow_guest=True) def update_cart_address(address_type, address_name): quotation = _get_cart_quotation() diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index d331f3d9a4..d619fbc729 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -10,16 +10,16 @@

    Scan & Pay via UPI

    - {# Loading state - shown while AJAX fetches order data #} + {# Loading state #}

    Loading order details...

    - {# Error state - hidden by default #} + {# Error state #} - {# Order details - hidden by default, populated by JS #} + {# Order details - populated by JS #}
    @@ -69,8 +100,9 @@

    {% endblock %} \ No newline at end of file From 219593228ef546236650031a82753295bb490336 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Tue, 24 Feb 2026 10:29:58 +0530 Subject: [PATCH 61/62] feat: auto-generate UPI reference ID, embed in deep link, auto-redirect after confirmation --- shop/www/upi_payment.html | 260 +++++++++++++++++++------------------- 1 file changed, 131 insertions(+), 129 deletions(-) diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index d619fbc729..877fc75279 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -51,43 +51,31 @@

    UPI ID: {{ upi_id }} Payee: {{ payee_name }} + Ref:
    {# Pay via UPI App button (mobile only) #} + style="background-color: #6366f1; border-color: #6366f1; color: #fff; font-weight: 600; padding: 14px; font-size: 1.1rem;"> 📱 {{ _("Pay via UPI App") }} {% endif %} -
    - - {# Transaction Confirmation Form #} -
    -

    After payment, enter your UPI reference number below:

    -
    - -
    - -
    + {# Confirm Payment Button - shown after deep link click or QR scan #} + - {# Success state - hidden by default #} + {# Success state #} @@ -100,124 +88,138 @@
    ✅ Payment Confirmed!
    {% endblock %} \ No newline at end of file From 03f1fb003d98c5fd2e9af230ed5b5ead583744a7 Mon Sep 17 00:00:00 2001 From: Balaji K Date: Thu, 26 Feb 2026 13:04:46 +0530 Subject: [PATCH 62/62] fix: use Sales Order name as UPI reference instead of random ID, simplify deep link URL --- shop/www/upi_payment.html | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/shop/www/upi_payment.html b/shop/www/upi_payment.html index 877fc75279..61867115b1 100644 --- a/shop/www/upi_payment.html +++ b/shop/www/upi_payment.html @@ -92,12 +92,7 @@
    ✅ Payment Recorded!
    var generatedRef = null; // Generate a unique reference ID based on order name - function generateRef(orderName) { - var shortId = Math.random().toString(36).substring(2, 6).toUpperCase(); - // Extract the number part from order name (e.g., SAL-ORD-2026-00071 -> 71) - var orderNum = orderName.replace(/\D/g, '').slice(-4); - return "REF-" + orderNum + "-" + shortId; - } + document.addEventListener('DOMContentLoaded', function () { var urlParams = new URLSearchParams(window.location.search); @@ -129,8 +124,8 @@
    ✅ Payment Recorded!
    if (r.message) { var data = r.message; - // Generate unique reference - generatedRef = generateRef(data.order_name); + // Use order name as the reference (clean and traceable) + generatedRef = data.order_name; // Populate order details document.getElementById("upi-order-name").textContent = data.order_name; @@ -141,15 +136,14 @@
    ✅ Payment Recorded!
    var refDisplay = document.getElementById("upi-ref-display"); if (refDisplay) refDisplay.textContent = generatedRef; - // Set UPI deep link with amount and reference + // Set UPI deep link — simple URL with just payee, amount, and order note var deepLinkBtn = document.getElementById("btn-upi-deep-link"); if (deepLinkBtn && data.upi_id) { var upiUrl = "upi://pay?pa=" + encodeURIComponent(data.upi_id) + "&pn=" + encodeURIComponent(data.payee_name) + "&am=" + data.grand_total + "&cu=" + data.currency - + "&tn=" + encodeURIComponent(generatedRef) - + "&tr=" + encodeURIComponent(generatedRef); + + "&tn=" + encodeURIComponent("Order " + data.order_name); deepLinkBtn.href = upiUrl; } }