shopyo-ecommerce 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- shopyo_ecommerce-0.1.0/PKG-INFO +152 -0
- shopyo_ecommerce-0.1.0/README.md +122 -0
- shopyo_ecommerce-0.1.0/pyproject.toml +62 -0
- shopyo_ecommerce-0.1.0/setup.cfg +4 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/__init__.py +143 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/_utils.py +40 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/box_info.json +9 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/__init__.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/forms.py +22 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/global.py +8 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/info.json +12 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/models.py +93 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/add.html +55 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/blocks/sidebar.html +42 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/choose_sub.html +35 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/dashboard.html +82 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/edit.html +99 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/edit_img_sub.html +82 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/manage_sub.html +79 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/message.html +18 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/upload.html +115 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/tests/test_category.py +316 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/upload.py +151 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/view.py +634 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/cli.py +83 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/__init__.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/forms.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/global.py +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/info.json +16 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/models.py +32 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/admin_dashboard.html +47 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/blocks/sidebar.html +21 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/dashboard.html +20 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/order_item_view.html +87 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/orders.html +115 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/tests/test_customer_functional.py +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/tests/test_customer_models.py +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/view.py +179 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/forms.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/global.py +18 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/info.json +17 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/models.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/templates/demo/blocks/sidebar.html +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/templates/demo/dashboard.html +22 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/templates/demo/import_demo.html +42 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/tests/test_demo_functional.py +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/tests/test_demo_models.py +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/view.py +103 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/forms.py +8 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/global.py +18 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/info.json +8 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/models.py +97 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/blocks/sidebar.html +5 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/count.html +49 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/dashboard.html +42 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/location_stock.html +31 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/locations.html +36 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/new.html +23 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/reports.html +44 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/transfers.html +68 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/tests/test_inventory_functional.py +108 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/tests/test_inventory_models.py +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/view.py +251 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/__init__.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/forms.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/info.json +16 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/models.py +102 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/blocks/sidebar.html +8 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/index.html +1036 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/quick_keys.html +57 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/reports.html +68 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/return.html +33 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/shifts.html +50 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/transaction_view.html +31 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/transactions.html +41 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/tests/test_pos_functional.py +149 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/view.py +316 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/__init__.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/global.py +10 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/info.json +12 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/models.py +156 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/add.html +163 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/adjustments.html +44 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/blocks/sidebar.html +43 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/edit.html +253 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/labels.html +23 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/list.html +69 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/lookup.html +128 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/nav.html +31 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/view.py +464 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/forms.py +16 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/global.py +18 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/info.json +8 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/models.py +42 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/templates/purchase/add.html +26 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/templates/purchase/blocks/sidebar.html +2 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/templates/purchase/dashboard.html +31 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/templates/purchase/edit.html +125 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/tests/test_purchase_functional.py +97 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/tests/test_purchase_models.py +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/view.py +174 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/resource/__init__.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/resource/info.json +15 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/resource/models.py +30 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/resource/view.py +24 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/__init__.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/cart.py +120 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/forms.py +226 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/global.py +37 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/helpers.py +50 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/info.json +16 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/models.py +137 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/base.html +20 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/blocks/accordion.html +35 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/blocks/common_styles.html +39 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/blocks/sidebar.html +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/category.html +101 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/checkout.html +330 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/emails/order_info.html +47 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/emails/order_info.txt +51 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/order_complete.html +23 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/product.html +319 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/sections/resources.html +30 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/shop.html +132 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/shop_login.html +19 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/subcategory.html +153 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/view_cart.html +244 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/wishlist.html +80 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/tests/test_shop.py +20 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/view.py +491 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/__init__.py +0 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/data/country.json +245 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/data/currency.json +158 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/forms.py +64 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/info.json +17 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/models.py +65 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/blocks/sidebar.html +39 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/coupon.html +92 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/dashboard.html +43 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/delivery.html +86 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/email_status_change.html +19 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/order.html +44 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/order_view.html +107 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/payment.html +86 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/upload.py +18 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/view.py +326 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/static/css/styles.css +41 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/index.html +266 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/info.json +4 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/carousel.html +38 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/drawer_head.html +68 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/footer.html +20 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/image_row.html +41 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/nav.html +186 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/resources.html +29 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/index.html +266 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/carousel.html +38 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/drawer_head.html +68 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/footer.html +20 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/image_row.html +41 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/nav.html +186 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/resources.html +29 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/forms.py +12 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/global.py +18 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/info.json +8 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/models.py +22 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/add.html +43 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/blocks/sidebar.html +2 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/dashboard.html +50 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/edit.html +43 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/index.html +9 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/tests/test_vendor_functional.py +43 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/tests/test_vendor_models.py +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/view.py +88 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/PKG-INFO +152 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/SOURCES.txt +178 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/dependency_links.txt +1 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/requires.txt +4 -0
- shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/top_level.txt +1 -0
- shopyo_ecommerce-0.1.0/tests/test_models.py +149 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: shopyo_ecommerce
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Full-featured ecommerce module for Shopyo Flask apps — products, cart, checkout, orders, POS, inventory, and API
|
|
5
|
+
Author-email: ShopCube <dev@shopcube.app>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/shopcube/shopcube
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/shopcube/shopcube/issues
|
|
9
|
+
Keywords: shopyo,ecommerce,flask,flask-ecommerce,shopping-cart,online-store,point-of-sale,pos,inventory,order-management,python-ecommerce,flask-shop
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Information Technology
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
21
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
Requires-Dist: shopyo
|
|
27
|
+
Requires-Dist: shopyo-appadmin
|
|
28
|
+
Requires-Dist: shopyo-auth
|
|
29
|
+
Requires-Dist: shopyo-dashboard
|
|
30
|
+
|
|
31
|
+
# 🛒 Shopyo Ecommerce — Plug & Play Python Ecommerce for Shopyo
|
|
32
|
+
|
|
33
|
+
**shopyo-ecommerce** is a full-featured, plug-and-play ecommerce module for the [Shopyo](https://shopyo.readthedocs.io/) Flask framework. Add products, categories, variants, cart, checkout, and order management to your Shopyo app in minutes — no boilerplate, no fuss.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## ✨ Features
|
|
38
|
+
|
|
39
|
+
- **Product & Category Management** — CRUD for products and categories with image uploads
|
|
40
|
+
- **Inventory Tracking** — stock counts, low-stock alerts, and variant support
|
|
41
|
+
- **Shopping Cart** — session-based cart with quantity controls
|
|
42
|
+
- **Checkout Flow** — address collection, order summary, and payment integration hooks
|
|
43
|
+
- **Order Dashboard** — admin order management with status tracking
|
|
44
|
+
- **POS Interface** — point-of-sale view for in-person transactions
|
|
45
|
+
- **RESTful API** — JSON endpoints for headless or mobile frontends
|
|
46
|
+
- **Shopyo Native** — respects Shopyo's theming, auth, dashboard, and settings
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 🚀 Quick Start
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install shopyo-ecommerce
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then initialise it in your Shopyo app factory:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from shopyo_ecommerce import ShopyoEcommerce
|
|
60
|
+
|
|
61
|
+
def create_app():
|
|
62
|
+
app = Flask(__name__)
|
|
63
|
+
# ... load extensions ...
|
|
64
|
+
ShopyoEcommerce(app)
|
|
65
|
+
return app
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
That's it. The ecommerce sub-modules (shop, pos, orders, etc.) will appear automatically in the dashboard and be ready at their default routes.
|
|
69
|
+
|
|
70
|
+
## 🎨 Theme Commands
|
|
71
|
+
|
|
72
|
+
Copy the ecommerceus front theme into your project so you can customise it:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
flask shopyo-ecommerce copy front ecommerceus
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
To overwrite an already-copied theme (backup first if needed):
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
flask shopyo-ecommerce update front ecommerceus
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The theme lands at `static/themes/front/ecommerceus/` and becomes available in the Shopyo theme picker.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 📦 What's Inside
|
|
89
|
+
|
|
90
|
+
| Sub-module | Route Prefix | Description |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `shop` | `/shop` | Product listing, detail, cart, checkout |
|
|
93
|
+
| `pos` | `/pos` | Point-of-sale interface |
|
|
94
|
+
| `category` | `/category` | Category management |
|
|
95
|
+
| `product` | `/product` | Product management |
|
|
96
|
+
| `order` | `/order` | Order management |
|
|
97
|
+
| `delivery` | `/delivery` | Delivery configuration |
|
|
98
|
+
| `payment` | `/payment` | Payment gateway hooks |
|
|
99
|
+
| `resource` | `/resource` | Image & asset serving |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 🔧 Configuration
|
|
104
|
+
|
|
105
|
+
All settings are configured via Flask app config keys. Set them in your `config.py` or before calling `ShopyoEcommerce(app)`.
|
|
106
|
+
|
|
107
|
+
| Config Key | Default | Description |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `SHOPYO_ECOMMERCE_URL` | `/shopyo-ecommerce` | URL prefix for all ecommerce routes |
|
|
110
|
+
| `SHOPYO_ECOMMERCE_CURRENCY` | `USD` | Default currency code (e.g. `USD`, `EUR`, `MUR`) |
|
|
111
|
+
| `SHOPYO_ECOMMERCE_SECTION_NAME` | `Shop` | Name shown in dashboard & settings for the ecommerce section |
|
|
112
|
+
| `SHOPYO_ECOMMERCE_ITEMS_PER_PAGE` | `12` | Number of products per page in shop listings |
|
|
113
|
+
| `SHOPYO_ECOMMERCE_ENABLE_WISHLIST` | `True` | Enable/disable the wishlist feature |
|
|
114
|
+
| `SHOPYO_ECOMMERCE_ENABLE_REVIEWS` | `False` | Enable/disable product reviews |
|
|
115
|
+
| `SHOPYO_ECOMMERCE_CATEGORYPHOTOS_UPLOADSET` | `categoryphotos` | Flask-Uploads set name for category images |
|
|
116
|
+
| `SHOPYO_ECOMMERCE_SUBCATEGORYPHOTOS_UPLOADSET` | `subcategoryphotos` | Flask-Uploads set name for subcategory images |
|
|
117
|
+
| `SHOPYO_ECOMMERCE_PRODUCTEXCEL_UPLOADSET` | `productexcel` | Flask-Uploads set name for product Excel imports |
|
|
118
|
+
| `SHOPYO_ECOMMERCE_PRODUCTPHOTOS_UPLOADSET` | `productphotos` | Flask-Uploads set name for product images |
|
|
119
|
+
| `SHOPYO_ECOMMERCE_UPLOADED_CATEGORYPHOTOS_DEST` | `static/uploads/categoryphotos` | Upload destination for category images (relative paths resolved against `BASE_DIR`) |
|
|
120
|
+
| `SHOPYO_ECOMMERCE_UPLOADED_SUBCATEGORYPHOTOS_DEST` | `static/uploads/subcategoryphotos` | Upload destination for subcategory images |
|
|
121
|
+
| `SHOPYO_ECOMMERCE_UPLOADED_PRODUCTEXCEL_DEST` | `static/uploads/productexcel` | Upload destination for product Excel files |
|
|
122
|
+
| `SHOPYO_ECOMMERCE_UPLOADED_PRODUCTPHOTOS_DEST` | `static/uploads/productphotos` | Upload destination for product images |
|
|
123
|
+
|
|
124
|
+
**Example:**
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
class Config:
|
|
128
|
+
SHOPYO_ECOMMERCE_URL = "/shop"
|
|
129
|
+
SHOPYO_ECOMMERCE_CURRENCY = "EUR"
|
|
130
|
+
SHOPYO_ECOMMERCE_ITEMS_PER_PAGE = 24
|
|
131
|
+
SHOPYO_ECOMMERCE_UPLOADED_PRODUCTPHOTOS_DEST = "/data/uploads/products"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 🧪 Tested With
|
|
137
|
+
|
|
138
|
+
- Python 3.10+
|
|
139
|
+
- Shopyo 4.18+
|
|
140
|
+
- Flask 2+
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 🤝 Contributing
|
|
145
|
+
|
|
146
|
+
Found a bug? Want a feature? Open an issue at [github.com/shopcube/shopcube](https://github.com/shopcube/shopcube).
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 📄 License
|
|
151
|
+
|
|
152
|
+
BSD-3-Clause. See `LICENSE`.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# 🛒 Shopyo Ecommerce — Plug & Play Python Ecommerce for Shopyo
|
|
2
|
+
|
|
3
|
+
**shopyo-ecommerce** is a full-featured, plug-and-play ecommerce module for the [Shopyo](https://shopyo.readthedocs.io/) Flask framework. Add products, categories, variants, cart, checkout, and order management to your Shopyo app in minutes — no boilerplate, no fuss.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ✨ Features
|
|
8
|
+
|
|
9
|
+
- **Product & Category Management** — CRUD for products and categories with image uploads
|
|
10
|
+
- **Inventory Tracking** — stock counts, low-stock alerts, and variant support
|
|
11
|
+
- **Shopping Cart** — session-based cart with quantity controls
|
|
12
|
+
- **Checkout Flow** — address collection, order summary, and payment integration hooks
|
|
13
|
+
- **Order Dashboard** — admin order management with status tracking
|
|
14
|
+
- **POS Interface** — point-of-sale view for in-person transactions
|
|
15
|
+
- **RESTful API** — JSON endpoints for headless or mobile frontends
|
|
16
|
+
- **Shopyo Native** — respects Shopyo's theming, auth, dashboard, and settings
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 🚀 Quick Start
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install shopyo-ecommerce
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Then initialise it in your Shopyo app factory:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from shopyo_ecommerce import ShopyoEcommerce
|
|
30
|
+
|
|
31
|
+
def create_app():
|
|
32
|
+
app = Flask(__name__)
|
|
33
|
+
# ... load extensions ...
|
|
34
|
+
ShopyoEcommerce(app)
|
|
35
|
+
return app
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That's it. The ecommerce sub-modules (shop, pos, orders, etc.) will appear automatically in the dashboard and be ready at their default routes.
|
|
39
|
+
|
|
40
|
+
## 🎨 Theme Commands
|
|
41
|
+
|
|
42
|
+
Copy the ecommerceus front theme into your project so you can customise it:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
flask shopyo-ecommerce copy front ecommerceus
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
To overwrite an already-copied theme (backup first if needed):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
flask shopyo-ecommerce update front ecommerceus
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The theme lands at `static/themes/front/ecommerceus/` and becomes available in the Shopyo theme picker.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 📦 What's Inside
|
|
59
|
+
|
|
60
|
+
| Sub-module | Route Prefix | Description |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `shop` | `/shop` | Product listing, detail, cart, checkout |
|
|
63
|
+
| `pos` | `/pos` | Point-of-sale interface |
|
|
64
|
+
| `category` | `/category` | Category management |
|
|
65
|
+
| `product` | `/product` | Product management |
|
|
66
|
+
| `order` | `/order` | Order management |
|
|
67
|
+
| `delivery` | `/delivery` | Delivery configuration |
|
|
68
|
+
| `payment` | `/payment` | Payment gateway hooks |
|
|
69
|
+
| `resource` | `/resource` | Image & asset serving |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 🔧 Configuration
|
|
74
|
+
|
|
75
|
+
All settings are configured via Flask app config keys. Set them in your `config.py` or before calling `ShopyoEcommerce(app)`.
|
|
76
|
+
|
|
77
|
+
| Config Key | Default | Description |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `SHOPYO_ECOMMERCE_URL` | `/shopyo-ecommerce` | URL prefix for all ecommerce routes |
|
|
80
|
+
| `SHOPYO_ECOMMERCE_CURRENCY` | `USD` | Default currency code (e.g. `USD`, `EUR`, `MUR`) |
|
|
81
|
+
| `SHOPYO_ECOMMERCE_SECTION_NAME` | `Shop` | Name shown in dashboard & settings for the ecommerce section |
|
|
82
|
+
| `SHOPYO_ECOMMERCE_ITEMS_PER_PAGE` | `12` | Number of products per page in shop listings |
|
|
83
|
+
| `SHOPYO_ECOMMERCE_ENABLE_WISHLIST` | `True` | Enable/disable the wishlist feature |
|
|
84
|
+
| `SHOPYO_ECOMMERCE_ENABLE_REVIEWS` | `False` | Enable/disable product reviews |
|
|
85
|
+
| `SHOPYO_ECOMMERCE_CATEGORYPHOTOS_UPLOADSET` | `categoryphotos` | Flask-Uploads set name for category images |
|
|
86
|
+
| `SHOPYO_ECOMMERCE_SUBCATEGORYPHOTOS_UPLOADSET` | `subcategoryphotos` | Flask-Uploads set name for subcategory images |
|
|
87
|
+
| `SHOPYO_ECOMMERCE_PRODUCTEXCEL_UPLOADSET` | `productexcel` | Flask-Uploads set name for product Excel imports |
|
|
88
|
+
| `SHOPYO_ECOMMERCE_PRODUCTPHOTOS_UPLOADSET` | `productphotos` | Flask-Uploads set name for product images |
|
|
89
|
+
| `SHOPYO_ECOMMERCE_UPLOADED_CATEGORYPHOTOS_DEST` | `static/uploads/categoryphotos` | Upload destination for category images (relative paths resolved against `BASE_DIR`) |
|
|
90
|
+
| `SHOPYO_ECOMMERCE_UPLOADED_SUBCATEGORYPHOTOS_DEST` | `static/uploads/subcategoryphotos` | Upload destination for subcategory images |
|
|
91
|
+
| `SHOPYO_ECOMMERCE_UPLOADED_PRODUCTEXCEL_DEST` | `static/uploads/productexcel` | Upload destination for product Excel files |
|
|
92
|
+
| `SHOPYO_ECOMMERCE_UPLOADED_PRODUCTPHOTOS_DEST` | `static/uploads/productphotos` | Upload destination for product images |
|
|
93
|
+
|
|
94
|
+
**Example:**
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
class Config:
|
|
98
|
+
SHOPYO_ECOMMERCE_URL = "/shop"
|
|
99
|
+
SHOPYO_ECOMMERCE_CURRENCY = "EUR"
|
|
100
|
+
SHOPYO_ECOMMERCE_ITEMS_PER_PAGE = 24
|
|
101
|
+
SHOPYO_ECOMMERCE_UPLOADED_PRODUCTPHOTOS_DEST = "/data/uploads/products"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 🧪 Tested With
|
|
107
|
+
|
|
108
|
+
- Python 3.10+
|
|
109
|
+
- Shopyo 4.18+
|
|
110
|
+
- Flask 2+
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 🤝 Contributing
|
|
115
|
+
|
|
116
|
+
Found a bug? Want a feature? Open an issue at [github.com/shopcube/shopcube](https://github.com/shopcube/shopcube).
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 📄 License
|
|
121
|
+
|
|
122
|
+
BSD-3-Clause. See `LICENSE`.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "shopyo_ecommerce"
|
|
3
|
+
authors = [{ name = "ShopCube", email = "dev@shopcube.app" }]
|
|
4
|
+
description = "Full-featured ecommerce module for Shopyo Flask apps — products, cart, checkout, orders, POS, inventory, and API"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
license = "BSD-3-Clause"
|
|
8
|
+
keywords = [
|
|
9
|
+
"shopyo",
|
|
10
|
+
"ecommerce",
|
|
11
|
+
"flask",
|
|
12
|
+
"flask-ecommerce",
|
|
13
|
+
"shopping-cart",
|
|
14
|
+
"online-store",
|
|
15
|
+
"point-of-sale",
|
|
16
|
+
"pos",
|
|
17
|
+
"inventory",
|
|
18
|
+
"order-management",
|
|
19
|
+
"python-ecommerce",
|
|
20
|
+
"flask-shop",
|
|
21
|
+
]
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Development Status :: 4 - Beta",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"Intended Audience :: Information Technology",
|
|
26
|
+
"Natural Language :: English",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
34
|
+
"Topic :: Office/Business :: Financial",
|
|
35
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
36
|
+
"Typing :: Typed",
|
|
37
|
+
]
|
|
38
|
+
dependencies = [
|
|
39
|
+
"shopyo",
|
|
40
|
+
"shopyo-appadmin",
|
|
41
|
+
"shopyo-auth",
|
|
42
|
+
"shopyo-dashboard",
|
|
43
|
+
]
|
|
44
|
+
version = "0.1.0"
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
"Homepage" = "https://github.com/shopcube/shopcube"
|
|
48
|
+
"Bug Tracker" = "https://github.com/shopcube/shopcube/issues"
|
|
49
|
+
|
|
50
|
+
[build-system]
|
|
51
|
+
requires = ["setuptools>=61.0"]
|
|
52
|
+
build-backend = "setuptools.build_meta"
|
|
53
|
+
|
|
54
|
+
[tool.setuptools]
|
|
55
|
+
include-package-data = true
|
|
56
|
+
|
|
57
|
+
[tool.setuptools.packages.find]
|
|
58
|
+
where = ["."]
|
|
59
|
+
include = ["shopyo_ecommerce*"]
|
|
60
|
+
|
|
61
|
+
[tool.setuptools.package-data]
|
|
62
|
+
shopyo_ecommerce = ["static/**", "templates/**", "*/templates/**", "data/**", "**/*.json"]
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import jinja2
|
|
6
|
+
from flask import Blueprint
|
|
7
|
+
from flask import Flask
|
|
8
|
+
from flask import current_app
|
|
9
|
+
from flask_uploads import DOCUMENTS
|
|
10
|
+
from flask_uploads import IMAGES
|
|
11
|
+
from flask_uploads import configure_uploads
|
|
12
|
+
from flask_uploads import UploadSet
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__version__ = "0.1.0"
|
|
16
|
+
|
|
17
|
+
info = {}
|
|
18
|
+
with open(os.path.dirname(os.path.abspath(__file__)) + os.sep + "box_info.json") as f:
|
|
19
|
+
info = json.load(f)
|
|
20
|
+
|
|
21
|
+
default_config = {
|
|
22
|
+
"SHOPYO_ECOMMERCE_URL": "/shopyo-ecommerce",
|
|
23
|
+
"SHOPYO_ECOMMERCE_CURRENCY": "USD",
|
|
24
|
+
"SHOPYO_ECOMMERCE_SECTION_NAME": "Shop",
|
|
25
|
+
"SHOPYO_ECOMMERCE_ITEMS_PER_PAGE": 12,
|
|
26
|
+
"SHOPYO_ECOMMERCE_ENABLE_WISHLIST": True,
|
|
27
|
+
"SHOPYO_ECOMMERCE_ENABLE_REVIEWS": False,
|
|
28
|
+
"SHOPYO_ECOMMERCE_CATEGORYPHOTOS_UPLOADSET": "categoryphotos",
|
|
29
|
+
"SHOPYO_ECOMMERCE_SUBCATEGORYPHOTOS_UPLOADSET": "subcategoryphotos",
|
|
30
|
+
"SHOPYO_ECOMMERCE_PRODUCTEXCEL_UPLOADSET": "productexcel",
|
|
31
|
+
"SHOPYO_ECOMMERCE_PRODUCTPHOTOS_UPLOADSET": "productphotos",
|
|
32
|
+
"SHOPYO_ECOMMERCE_UPLOADED_CATEGORYPHOTOS_DEST": "static/uploads/categoryphotos",
|
|
33
|
+
"SHOPYO_ECOMMERCE_UPLOADED_SUBCATEGORYPHOTOS_DEST": "static/uploads/subcategoryphotos",
|
|
34
|
+
"SHOPYO_ECOMMERCE_UPLOADED_PRODUCTEXCEL_DEST": "static/uploads/productexcel",
|
|
35
|
+
"SHOPYO_ECOMMERCE_UPLOADED_PRODUCTPHOTOS_DEST": "static/uploads/productphotos",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
categoryphotos = UploadSet("categoryphotos", IMAGES)
|
|
39
|
+
subcategoryphotos = UploadSet("subcategoryphotos", IMAGES)
|
|
40
|
+
productexcel = UploadSet("productexcel", DOCUMENTS)
|
|
41
|
+
productphotos = UploadSet("productphotos", IMAGES)
|
|
42
|
+
|
|
43
|
+
_pkg_dir = os.path.dirname(os.path.abspath(__file__))
|
|
44
|
+
|
|
45
|
+
blueprint_names = [
|
|
46
|
+
"category",
|
|
47
|
+
"customer",
|
|
48
|
+
"demo",
|
|
49
|
+
"inventory",
|
|
50
|
+
"pos",
|
|
51
|
+
"product",
|
|
52
|
+
"purchase",
|
|
53
|
+
"resource",
|
|
54
|
+
"shop",
|
|
55
|
+
"shopman",
|
|
56
|
+
"vendor",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ShopyoEcommerce:
|
|
61
|
+
def __init__(self, app: Any = None) -> None:
|
|
62
|
+
if app is not None:
|
|
63
|
+
self.init_app(app)
|
|
64
|
+
|
|
65
|
+
def init_app(self, app: Flask) -> None:
|
|
66
|
+
if not hasattr(app, "extensions"):
|
|
67
|
+
app.extensions = {}
|
|
68
|
+
|
|
69
|
+
for key, value in default_config.items():
|
|
70
|
+
app.config.setdefault(key, value)
|
|
71
|
+
|
|
72
|
+
url_prefix = app.config.get("SHOPYO_ECOMMERCE_URL", "/shopyo-ecommerce")
|
|
73
|
+
parent = Blueprint(
|
|
74
|
+
"shopyo_ecommerce",
|
|
75
|
+
__name__,
|
|
76
|
+
url_prefix=url_prefix,
|
|
77
|
+
template_folder="templates",
|
|
78
|
+
static_folder="static",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
for name in blueprint_names:
|
|
82
|
+
mod = __import__(
|
|
83
|
+
f"shopyo_ecommerce.{name}.view", fromlist=["module_blueprint"]
|
|
84
|
+
)
|
|
85
|
+
parent.register_blueprint(mod.module_blueprint)
|
|
86
|
+
|
|
87
|
+
global_modules = [
|
|
88
|
+
"shopyo_ecommerce.category.global",
|
|
89
|
+
"shopyo_ecommerce.shop.global",
|
|
90
|
+
"shopyo_ecommerce.product.global",
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
for g_path in global_modules:
|
|
94
|
+
try:
|
|
95
|
+
mod = __import__(g_path, fromlist=["available_everywhere"])
|
|
96
|
+
app.jinja_env.globals.update(mod.available_everywhere)
|
|
97
|
+
except (ImportError, AttributeError):
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
app.register_blueprint(parent)
|
|
101
|
+
|
|
102
|
+
pkg_templates = os.path.join(_pkg_dir, "templates")
|
|
103
|
+
if os.path.isdir(pkg_templates):
|
|
104
|
+
current = app.jinja_loader
|
|
105
|
+
if not isinstance(current, jinja2.ChoiceLoader):
|
|
106
|
+
current = jinja2.ChoiceLoader([current])
|
|
107
|
+
app.jinja_loader = current
|
|
108
|
+
current.loaders.insert(0, jinja2.FileSystemLoader(pkg_templates))
|
|
109
|
+
|
|
110
|
+
app.extensions["shopyo_ecommerce"] = self
|
|
111
|
+
|
|
112
|
+
from shopyo_ecommerce import cli as shopyo_ecommerce_cli
|
|
113
|
+
|
|
114
|
+
app.cli.add_command(shopyo_ecommerce_cli.cli)
|
|
115
|
+
|
|
116
|
+
upload_set_names = {
|
|
117
|
+
"categoryphotos": categoryphotos,
|
|
118
|
+
"subcategoryphotos": subcategoryphotos,
|
|
119
|
+
"productexcel": productexcel,
|
|
120
|
+
"productphotos": productphotos,
|
|
121
|
+
}
|
|
122
|
+
base = app.config.get("BASE_DIR", os.getcwd())
|
|
123
|
+
for name, uset in upload_set_names.items():
|
|
124
|
+
config_key = f"SHOPYO_ECOMMERCE_UPLOADED_{name.upper()}_DEST"
|
|
125
|
+
dest = app.config[config_key]
|
|
126
|
+
if not os.path.isabs(dest):
|
|
127
|
+
dest = os.path.join(base, dest)
|
|
128
|
+
app.config[f"UPLOADED_{name.upper()}_DEST"] = dest
|
|
129
|
+
configure_uploads(app, uset)
|
|
130
|
+
|
|
131
|
+
def get_info(self):
|
|
132
|
+
info_copy = dict(info)
|
|
133
|
+
modules_info = {}
|
|
134
|
+
base_url = current_app.config.get("SHOPYO_ECOMMERCE_URL", "/shopyo-ecommerce")
|
|
135
|
+
for name in blueprint_names:
|
|
136
|
+
info_path = os.path.join(_pkg_dir, name, "info.json")
|
|
137
|
+
if os.path.exists(info_path):
|
|
138
|
+
with open(info_path) as f:
|
|
139
|
+
mod_info = json.load(f)
|
|
140
|
+
mod_info["url_prefix"] = base_url + mod_info.get("url_prefix", f"/{name}")
|
|
141
|
+
modules_info[name] = mod_info
|
|
142
|
+
info_copy["modules"] = modules_info
|
|
143
|
+
return info_copy
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from shopyo.api.validators import is_empty_str
|
|
4
|
+
from shopyo.api.file import unique_filename
|
|
5
|
+
from werkzeug.utils import secure_filename
|
|
6
|
+
from wtforms.validators import ValidationError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def is_safe_path_component(component):
|
|
10
|
+
if not component:
|
|
11
|
+
return False
|
|
12
|
+
return bool(re.match(r"^[a-zA-Z0-9_.\-]+$", component))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def unique_sec_filename(filename):
|
|
16
|
+
return unique_filename(secure_filename(filename))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def require_if_default_address(form, field):
|
|
20
|
+
if form.diffAddress.data == False:
|
|
21
|
+
if is_empty_str(field.data):
|
|
22
|
+
raise ValidationError("{} cannot be empty!".format(field.label))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def require_if_diff_address(form, field):
|
|
26
|
+
if form.diffAddress.data == True:
|
|
27
|
+
if is_empty_str(field.data):
|
|
28
|
+
raise ValidationError("{} cannot be empty!".format(field.label))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def require_if_apply_coupon(form, field):
|
|
32
|
+
if form.applyCoupon.data == True:
|
|
33
|
+
if is_empty_str(field.data):
|
|
34
|
+
raise ValidationError("{} cannot be empty!".format(field.label))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def require_if_create_account(form, field):
|
|
38
|
+
if form.createAccount.data == True:
|
|
39
|
+
if is_empty_str(field.data):
|
|
40
|
+
raise ValidationError("{} cannot be empty!".format(field.label))
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from flask_wtf import FlaskForm
|
|
2
|
+
from flask_wtf.file import FileAllowed
|
|
3
|
+
from flask_wtf.file import FileField
|
|
4
|
+
from flask_wtf.file import FileRequired
|
|
5
|
+
from wtforms import SubmitField
|
|
6
|
+
|
|
7
|
+
from shopyo_ecommerce import productexcel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class UploadProductForm(FlaskForm):
|
|
11
|
+
product_file = FileField(
|
|
12
|
+
"Product upload",
|
|
13
|
+
validators=[
|
|
14
|
+
FileAllowed(productexcel, "File must be in xls, xlsx, xlsm, xlsb, odf"),
|
|
15
|
+
FileRequired("File was empty!"),
|
|
16
|
+
],
|
|
17
|
+
render_kw={
|
|
18
|
+
"class": "form-control",
|
|
19
|
+
"autocomplete": "off",
|
|
20
|
+
"id": "upload-product-input",
|
|
21
|
+
},
|
|
22
|
+
)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
remember: backrefs should be unique
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from flask import url_for
|
|
6
|
+
|
|
7
|
+
from shopyo.api.models import PkModel
|
|
8
|
+
from sqlalchemy import exists
|
|
9
|
+
from sqlalchemy.orm import validates
|
|
10
|
+
|
|
11
|
+
from init import db
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Category(PkModel):
|
|
15
|
+
__tablename__ = "shopyo_ecommerce_categories"
|
|
16
|
+
name = db.Column(db.String(100), unique=True, nullable=False)
|
|
17
|
+
subcategories = db.relationship("SubCategory", backref="category", lazy=True)
|
|
18
|
+
resources = db.relationship(
|
|
19
|
+
"Resource",
|
|
20
|
+
backref="resource_category",
|
|
21
|
+
lazy=True,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def __repr__(self):
|
|
25
|
+
return f"Category: {self.name}"
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def category_exists(cls, name):
|
|
29
|
+
return db.session.query(exists().where(cls.name == name.lower())).scalar()
|
|
30
|
+
|
|
31
|
+
@validates("name")
|
|
32
|
+
def convert_lower(self, key, value):
|
|
33
|
+
return value.lower()
|
|
34
|
+
|
|
35
|
+
def get_num_subcategories(self):
|
|
36
|
+
return len(self.subcategories)
|
|
37
|
+
|
|
38
|
+
def get_one_image_url(self):
|
|
39
|
+
if len(self.resources) == 0:
|
|
40
|
+
return url_for("static", filename="default/default_subcategory.jpg")
|
|
41
|
+
else:
|
|
42
|
+
resource = self.resources[0]
|
|
43
|
+
return url_for("static", filename=f"uploads/products/{resource.filename}")
|
|
44
|
+
|
|
45
|
+
def get_page_url(self):
|
|
46
|
+
return url_for("shopyo_ecommerce.shop.category", category_name=self.name)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class SubCategory(PkModel):
|
|
50
|
+
__tablename__ = "shopyo_ecommerce_subcategories"
|
|
51
|
+
name = db.Column(db.String(100), nullable=False)
|
|
52
|
+
category_id = db.Column(db.Integer, db.ForeignKey("shopyo_ecommerce_categories.id"))
|
|
53
|
+
products = db.relationship("Product", backref="subcategory", lazy=True)
|
|
54
|
+
resources = db.relationship("Resource", backref="resource_subcategory", lazy=True)
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def category_exists(cls, name):
|
|
58
|
+
return db.session.query(exists().where(cls.name == name.lower())).scalar()
|
|
59
|
+
|
|
60
|
+
@validates("name")
|
|
61
|
+
def convert_lower(self, key, value):
|
|
62
|
+
return value.lower()
|
|
63
|
+
|
|
64
|
+
def get_num_products(self):
|
|
65
|
+
return len(self.products)
|
|
66
|
+
|
|
67
|
+
def get_one_image_url(self):
|
|
68
|
+
|
|
69
|
+
if len(self.products) > 0:
|
|
70
|
+
product = self.products[0]
|
|
71
|
+
if len(product.resources) == 0:
|
|
72
|
+
if len(self.resources) == 0:
|
|
73
|
+
return url_for("static", filename="default/default_subcategory.jpg")
|
|
74
|
+
else:
|
|
75
|
+
resource = self.resources[0]
|
|
76
|
+
return url_for(
|
|
77
|
+
"static",
|
|
78
|
+
filename=f"uploads/subcategory/{resource.filename}",
|
|
79
|
+
)
|
|
80
|
+
else:
|
|
81
|
+
resource = product.resources[0]
|
|
82
|
+
return url_for(
|
|
83
|
+
"static", filename=f"uploads/products/{resource.filename}"
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
if len(self.resources) == 0:
|
|
87
|
+
return url_for("static", filename="default/default_subcategory.jpg")
|
|
88
|
+
else:
|
|
89
|
+
resource = self.resources[0]
|
|
90
|
+
return url_for(
|
|
91
|
+
"static",
|
|
92
|
+
filename=f"uploads/subcategory/{resource.filename}",
|
|
93
|
+
)
|