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.
Files changed (180) hide show
  1. shopyo_ecommerce-0.1.0/PKG-INFO +152 -0
  2. shopyo_ecommerce-0.1.0/README.md +122 -0
  3. shopyo_ecommerce-0.1.0/pyproject.toml +62 -0
  4. shopyo_ecommerce-0.1.0/setup.cfg +4 -0
  5. shopyo_ecommerce-0.1.0/shopyo_ecommerce/__init__.py +143 -0
  6. shopyo_ecommerce-0.1.0/shopyo_ecommerce/_utils.py +40 -0
  7. shopyo_ecommerce-0.1.0/shopyo_ecommerce/box_info.json +9 -0
  8. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/__init__.py +0 -0
  9. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/forms.py +22 -0
  10. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/global.py +8 -0
  11. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/info.json +12 -0
  12. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/models.py +93 -0
  13. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/add.html +55 -0
  14. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/blocks/sidebar.html +42 -0
  15. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/choose_sub.html +35 -0
  16. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/dashboard.html +82 -0
  17. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/edit.html +99 -0
  18. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/edit_img_sub.html +82 -0
  19. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/manage_sub.html +79 -0
  20. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/message.html +18 -0
  21. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/templates/category/upload.html +115 -0
  22. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/tests/test_category.py +316 -0
  23. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/upload.py +151 -0
  24. shopyo_ecommerce-0.1.0/shopyo_ecommerce/category/view.py +634 -0
  25. shopyo_ecommerce-0.1.0/shopyo_ecommerce/cli.py +83 -0
  26. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/__init__.py +0 -0
  27. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/forms.py +0 -0
  28. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/global.py +1 -0
  29. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/info.json +16 -0
  30. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/models.py +32 -0
  31. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/admin_dashboard.html +47 -0
  32. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/blocks/sidebar.html +21 -0
  33. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/dashboard.html +20 -0
  34. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/order_item_view.html +87 -0
  35. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/templates/customer/orders.html +115 -0
  36. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/tests/test_customer_functional.py +1 -0
  37. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/tests/test_customer_models.py +1 -0
  38. shopyo_ecommerce-0.1.0/shopyo_ecommerce/customer/view.py +179 -0
  39. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/forms.py +0 -0
  40. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/global.py +18 -0
  41. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/info.json +17 -0
  42. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/models.py +0 -0
  43. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/templates/demo/blocks/sidebar.html +0 -0
  44. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/templates/demo/dashboard.html +22 -0
  45. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/templates/demo/import_demo.html +42 -0
  46. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/tests/test_demo_functional.py +1 -0
  47. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/tests/test_demo_models.py +1 -0
  48. shopyo_ecommerce-0.1.0/shopyo_ecommerce/demo/view.py +103 -0
  49. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/forms.py +8 -0
  50. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/global.py +18 -0
  51. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/info.json +8 -0
  52. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/models.py +97 -0
  53. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/blocks/sidebar.html +5 -0
  54. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/count.html +49 -0
  55. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/dashboard.html +42 -0
  56. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/location_stock.html +31 -0
  57. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/locations.html +36 -0
  58. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/new.html +23 -0
  59. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/reports.html +44 -0
  60. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/templates/inventory/transfers.html +68 -0
  61. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/tests/test_inventory_functional.py +108 -0
  62. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/tests/test_inventory_models.py +1 -0
  63. shopyo_ecommerce-0.1.0/shopyo_ecommerce/inventory/view.py +251 -0
  64. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/__init__.py +0 -0
  65. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/forms.py +0 -0
  66. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/info.json +16 -0
  67. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/models.py +102 -0
  68. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/blocks/sidebar.html +8 -0
  69. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/index.html +1036 -0
  70. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/quick_keys.html +57 -0
  71. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/reports.html +68 -0
  72. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/return.html +33 -0
  73. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/shifts.html +50 -0
  74. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/transaction_view.html +31 -0
  75. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/templates/pos/transactions.html +41 -0
  76. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/tests/test_pos_functional.py +149 -0
  77. shopyo_ecommerce-0.1.0/shopyo_ecommerce/pos/view.py +316 -0
  78. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/__init__.py +0 -0
  79. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/global.py +10 -0
  80. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/info.json +12 -0
  81. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/models.py +156 -0
  82. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/add.html +163 -0
  83. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/adjustments.html +44 -0
  84. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/blocks/sidebar.html +43 -0
  85. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/edit.html +253 -0
  86. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/labels.html +23 -0
  87. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/list.html +69 -0
  88. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/lookup.html +128 -0
  89. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/templates/product/nav.html +31 -0
  90. shopyo_ecommerce-0.1.0/shopyo_ecommerce/product/view.py +464 -0
  91. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/forms.py +16 -0
  92. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/global.py +18 -0
  93. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/info.json +8 -0
  94. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/models.py +42 -0
  95. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/templates/purchase/add.html +26 -0
  96. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/templates/purchase/blocks/sidebar.html +2 -0
  97. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/templates/purchase/dashboard.html +31 -0
  98. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/templates/purchase/edit.html +125 -0
  99. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/tests/test_purchase_functional.py +97 -0
  100. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/tests/test_purchase_models.py +1 -0
  101. shopyo_ecommerce-0.1.0/shopyo_ecommerce/purchase/view.py +174 -0
  102. shopyo_ecommerce-0.1.0/shopyo_ecommerce/resource/__init__.py +0 -0
  103. shopyo_ecommerce-0.1.0/shopyo_ecommerce/resource/info.json +15 -0
  104. shopyo_ecommerce-0.1.0/shopyo_ecommerce/resource/models.py +30 -0
  105. shopyo_ecommerce-0.1.0/shopyo_ecommerce/resource/view.py +24 -0
  106. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/__init__.py +0 -0
  107. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/cart.py +120 -0
  108. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/forms.py +226 -0
  109. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/global.py +37 -0
  110. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/helpers.py +50 -0
  111. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/info.json +16 -0
  112. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/models.py +137 -0
  113. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/base.html +20 -0
  114. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/blocks/accordion.html +35 -0
  115. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/blocks/common_styles.html +39 -0
  116. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/blocks/sidebar.html +0 -0
  117. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/category.html +101 -0
  118. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/checkout.html +330 -0
  119. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/emails/order_info.html +47 -0
  120. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/emails/order_info.txt +51 -0
  121. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/order_complete.html +23 -0
  122. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/product.html +319 -0
  123. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/sections/resources.html +30 -0
  124. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/shop.html +132 -0
  125. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/shop_login.html +19 -0
  126. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/subcategory.html +153 -0
  127. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/view_cart.html +244 -0
  128. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/templates/shop/wishlist.html +80 -0
  129. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/tests/test_shop.py +20 -0
  130. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shop/view.py +491 -0
  131. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/__init__.py +0 -0
  132. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/data/country.json +245 -0
  133. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/data/currency.json +158 -0
  134. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/forms.py +64 -0
  135. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/info.json +17 -0
  136. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/models.py +65 -0
  137. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/blocks/sidebar.html +39 -0
  138. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/coupon.html +92 -0
  139. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/dashboard.html +43 -0
  140. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/delivery.html +86 -0
  141. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/email_status_change.html +19 -0
  142. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/order.html +44 -0
  143. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/order_view.html +107 -0
  144. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/templates/shopman/payment.html +86 -0
  145. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/upload.py +18 -0
  146. shopyo_ecommerce-0.1.0/shopyo_ecommerce/shopman/view.py +326 -0
  147. shopyo_ecommerce-0.1.0/shopyo_ecommerce/static/css/styles.css +41 -0
  148. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/index.html +266 -0
  149. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/info.json +4 -0
  150. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/carousel.html +38 -0
  151. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/drawer_head.html +68 -0
  152. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/footer.html +20 -0
  153. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/image_row.html +41 -0
  154. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/nav.html +186 -0
  155. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/ecommerceus/sections/resources.html +29 -0
  156. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/index.html +266 -0
  157. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/carousel.html +38 -0
  158. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/drawer_head.html +68 -0
  159. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/footer.html +20 -0
  160. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/image_row.html +41 -0
  161. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/nav.html +186 -0
  162. shopyo_ecommerce-0.1.0/shopyo_ecommerce/templates/shopyo_ecommerce/ecommerceus/sections/resources.html +29 -0
  163. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/forms.py +12 -0
  164. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/global.py +18 -0
  165. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/info.json +8 -0
  166. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/models.py +22 -0
  167. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/add.html +43 -0
  168. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/blocks/sidebar.html +2 -0
  169. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/dashboard.html +50 -0
  170. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/edit.html +43 -0
  171. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/templates/vendor/index.html +9 -0
  172. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/tests/test_vendor_functional.py +43 -0
  173. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/tests/test_vendor_models.py +1 -0
  174. shopyo_ecommerce-0.1.0/shopyo_ecommerce/vendor/view.py +88 -0
  175. shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/PKG-INFO +152 -0
  176. shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/SOURCES.txt +178 -0
  177. shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/dependency_links.txt +1 -0
  178. shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/requires.txt +4 -0
  179. shopyo_ecommerce-0.1.0/shopyo_ecommerce.egg-info/top_level.txt +1 -0
  180. 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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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))
@@ -0,0 +1,9 @@
1
+ {
2
+ "display_string": "Ecommerce",
3
+ "box_name":"ecommerce",
4
+ "author": {
5
+ "name":"",
6
+ "website":"",
7
+ "mail":""
8
+ }
9
+ }
@@ -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,8 @@
1
+ from shopyo_ecommerce.category.models import Category
2
+
3
+
4
+ def get_categories():
5
+ return Category.query.all()
6
+
7
+
8
+ available_everywhere = {"get_categories": get_categories, "Category": Category}
@@ -0,0 +1,12 @@
1
+ {
2
+ "display_string": "Inventory",
3
+ "module_name": "category",
4
+ "type": "show",
5
+ "icons": {
6
+ "fa": "fa fa-edit",
7
+ "boxicons": "bx bx-pen"
8
+ },
9
+ "url_prefix": "/category",
10
+ "dashboard": "/dashboard",
11
+ "fa-icon": "fas fa-cubes"
12
+ }
@@ -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
+ )