ob-dj-store 0.0.11.7__tar.gz → 0.0.11.9__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.
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/PKG-INFO +1 -1
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/config/settings.py +3 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/stores/filters.py +25 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/stores/rest/serializers/serializers.py +53 -13
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/stores/urls.py +3 -3
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/stores/views.py +100 -37
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/admin.py +8 -9
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/admin_inlines.py +4 -4
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/models.py +1 -1
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/managers.py +1 -3
- ob-dj-store-0.0.11.9/ob_dj_store/core/stores/migrations/0062_auto_20230226_2005.py +43 -0
- ob-dj-store-0.0.11.9/ob_dj_store/core/stores/migrations/0063_alter_store_payment_methods.py +23 -0
- ob-dj-store-0.0.11.9/ob_dj_store/core/stores/migrations/0064_auto_20230228_1814.py +24 -0
- ob-dj-store-0.0.11.9/ob_dj_store/core/stores/migrations/0064_auto_20230228_1932.py +34 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_favorite.py +4 -1
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_order.py +2 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_payment.py +31 -11
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_product.py +3 -5
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_store.py +15 -6
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_wallet.py +41 -8
- ob-dj-store-0.0.11.9/ob_dj_store/core/stores/receivers.py +109 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/utils.py +14 -6
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/utils/helpers.py +7 -1
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/utils/utils.py +3 -2
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store.egg-info/PKG-INFO +1 -1
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store.egg-info/SOURCES.txt +4 -0
- ob-dj-store-0.0.11.7/ob_dj_store/core/stores/receivers.py +0 -55
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/.github/dependabot.yml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/.github/workflows/docs.yml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/.github/workflows/pre-release.yml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/.github/workflows/release.yml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/.github/workflows/test-build.yml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/.gitignore +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/.isort.cfg +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/.pre-commit-config.yaml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/Dockerfile +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/MANIFEST.in +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/Makefile +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/Pipfile +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/Pipfile.lock +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/README.md +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/config/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/config/urls.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/config/wsgi.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docker-compose.env +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docker-compose.yml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docs/Makefile +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docs/make.bat +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docs/source/admin.rst +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docs/source/conf.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docs/source/index.rst +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docs/source/installation.rst +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docs/source/models.rst +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/docs/source/rest_endpoints.rst +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/fixtures/initial_users.yaml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/fixtures/stores.yaml +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/manage.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/stores/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/tap/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/tap/serializers.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/tap/urls.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/apis/tap/views.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/apps.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/admin.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/apps.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/managers.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/migrations/0001_initial.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/migrations/0002_auto_20220815_1610.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/migrations/0003_auto_20220818_1938.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/migrations/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/gateway/tap/utils.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0001_initial.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0002_auto_20220422_0205.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0003_openinghours.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0004_auto_20220422_2326.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0005_auto_20220425_2119.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0005_auto_20220427_1729.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0006_auto_20220428_0100.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0007_cart_cartitem_order_orderitem.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0008_order_status.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0009_auto_20220508_2142.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0010_auto_20220509_1633.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0011_favorite.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0012_auto_20220514_0633.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0013_auto_20220518_1539.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0014_auto_20220519_0018.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0015_inventory_inventoryoperations.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0016_productvariant_preparation_time.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0017_auto_20220524_0912.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0018_auto_20220524_1613.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0019_product_is_featured.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0020_orderhistory.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0021_auto_20220531_1849.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0022_order_pickup_time.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0023_feedback_feedbackattribute_feedbackconfig.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0024_auto_20220609_1552.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0025_productvariant_is_primary.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0026_auto_20220630_1913.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0027_auto_20220713_1759.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0028_phonecontact.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0029_auto_20220726_1750.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0030_category_parent.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0031_auto_20220811_1733.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0032_auto_20220812_1951.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0033_auto_20220815_0133.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0034_auto_20220815_1528.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0035_auto_20220818_1938.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0036_productattribute_is_mandatory.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0037_auto_20220825_1736.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0038_cartitem_extra_infos.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0039_auto_20220831_1521.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0040_auto_20220902_1806.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0041_auto_20220912_1506.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0042_wallet_wallettransaction.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0043_auto_20220919_1854.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0044_remove_productvariant_has_inventory.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0045_shippingmethod_type.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0046_auto_20221014_1720.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0047_auto_20221018_1433.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0048_auto_20221026_1933.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0049_auto_20221029_1524.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0050_favoriteextra.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0051_order_car_id.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0052_auto_20221129_1732.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0053_inventory_plu.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0054_auto_20221230_1501.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0055_store_image.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0056_auto_20230213_2224.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0057_auto_20230214_1724.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0058_attributechoice_is_default.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0059_auto_20230217_2006.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0060_alter_orderitem_product_variant.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/0061_auto_20230223_1435.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/migrations/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_address.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_cart.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_feedback.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/models/_inventory.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/core/stores/settings_validation.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/utils/__init__.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store/utils/model.py +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store.egg-info/dependency_links.txt +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store.egg-info/requires.txt +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/ob_dj_store.egg-info/top_level.txt +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/pytest.ini +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/setup.cfg +0 -0
- {ob-dj-store-0.0.11.7 → ob-dj-store-0.0.11.9}/setup.py +0 -0
@@ -5,10 +5,12 @@ from django.utils.timezone import now
|
|
5
5
|
from django_filters import rest_framework as filters
|
6
6
|
from rest_framework.exceptions import ValidationError
|
7
7
|
|
8
|
+
from config import settings as store_settings
|
8
9
|
from ob_dj_store.core.stores.models import (
|
9
10
|
Category,
|
10
11
|
Favorite,
|
11
12
|
Order,
|
13
|
+
PaymentMethod,
|
12
14
|
Product,
|
13
15
|
ProductVariant,
|
14
16
|
Store,
|
@@ -128,6 +130,7 @@ class CategoryFilter(filters.FilterSet):
|
|
128
130
|
is_active=True,
|
129
131
|
).distinct(),
|
130
132
|
),
|
133
|
+
"subcategories__products__images",
|
131
134
|
)
|
132
135
|
.distinct()
|
133
136
|
)
|
@@ -174,3 +177,25 @@ class FavoriteFilter(filters.FilterSet):
|
|
174
177
|
content_type=content_type,
|
175
178
|
object_id__in=products_ids,
|
176
179
|
)
|
180
|
+
|
181
|
+
|
182
|
+
class PaymentMethodFilter(filters.FilterSet):
|
183
|
+
store = filters.CharFilter(method="by_store")
|
184
|
+
is_digital = filters.BooleanFilter(method="by_digital")
|
185
|
+
|
186
|
+
class Meta:
|
187
|
+
models = PaymentMethod
|
188
|
+
|
189
|
+
def by_store(self, queryset, name, value):
|
190
|
+
return queryset.filter(stores=value)
|
191
|
+
|
192
|
+
def by_digital(self, queryset, name, value):
|
193
|
+
if value:
|
194
|
+
return queryset.filter(
|
195
|
+
payment_provider__in=[
|
196
|
+
store_settings.TAP_CREDIT_CARD,
|
197
|
+
store_settings.TAP_KNET,
|
198
|
+
store_settings.TAP_ALL,
|
199
|
+
]
|
200
|
+
)
|
201
|
+
return queryset
|
@@ -39,6 +39,7 @@ from ob_dj_store.core.stores.models import (
|
|
39
39
|
ShippingMethod,
|
40
40
|
Store,
|
41
41
|
Tax,
|
42
|
+
Wallet,
|
42
43
|
)
|
43
44
|
from ob_dj_store.core.stores.models._inventory import Inventory
|
44
45
|
from ob_dj_store.core.stores.utils import distance
|
@@ -288,7 +289,7 @@ class OrderSerializer(serializers.ModelSerializer):
|
|
288
289
|
if payment_method:
|
289
290
|
if payment_method.payment_provider == store_settings.WALLET:
|
290
291
|
try:
|
291
|
-
wallet = user.wallets.get(
|
292
|
+
wallet = user.wallets.get(currency=attrs["store"].currency)
|
292
293
|
except ObjectDoesNotExist:
|
293
294
|
raise serializers.ValidationError(
|
294
295
|
{
|
@@ -603,7 +604,9 @@ class ProductSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
603
604
|
return data
|
604
605
|
|
605
606
|
|
606
|
-
class ProductListSerializer(
|
607
|
+
class ProductListSerializer(serializers.ModelSerializer):
|
608
|
+
product_images = ProductMediaSerializer(many=True, source="images")
|
609
|
+
|
607
610
|
class Meta:
|
608
611
|
model = Product
|
609
612
|
fields = (
|
@@ -795,9 +798,7 @@ class StoreSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
795
798
|
|
796
799
|
def get_is_closed(self, obj):
|
797
800
|
current_time = now()
|
798
|
-
current_op_hour = obj.
|
799
|
-
weekday=current_time.weekday() + 1
|
800
|
-
).first()
|
801
|
+
current_op_hour = obj.current_opening_hours
|
801
802
|
if current_op_hour:
|
802
803
|
return (
|
803
804
|
not current_op_hour.from_hour
|
@@ -869,9 +870,7 @@ class StoreSerializer(FavoriteMixin, serializers.ModelSerializer):
|
|
869
870
|
return PhoneContactSerializer(phone_contacts, many=True).data
|
870
871
|
|
871
872
|
def get_current_day_opening_hours(self, obj):
|
872
|
-
current_opening_hours = obj.
|
873
|
-
weekday=now().weekday() + 1
|
874
|
-
).first()
|
873
|
+
current_opening_hours = obj.current_opening_hours
|
875
874
|
op_hour = {}
|
876
875
|
if current_opening_hours:
|
877
876
|
op_hour["from_hour"] = current_opening_hours.from_hour.strftime("%I:%M%p")
|
@@ -978,7 +977,11 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
978
977
|
"extras",
|
979
978
|
"object_id",
|
980
979
|
"object_type",
|
980
|
+
"name",
|
981
981
|
)
|
982
|
+
extra_kwargs = {
|
983
|
+
"name": {"required": True},
|
984
|
+
}
|
982
985
|
|
983
986
|
def _lookup_validation(self, data):
|
984
987
|
content_type = ContentType.objects.get_for_model(type(data["content_object"]))
|
@@ -1005,6 +1008,7 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
1005
1008
|
|
1006
1009
|
def validate(self, attrs):
|
1007
1010
|
validated_data = super().validate(attrs)
|
1011
|
+
name = validated_data["name"]
|
1008
1012
|
object_type = validated_data["object_type"]
|
1009
1013
|
if object_type not in store_settings.FAVORITE_TYPES and hasattr(
|
1010
1014
|
sys.modules[__name__], object_type
|
@@ -1039,14 +1043,50 @@ class FavoriteSerializer(serializers.ModelSerializer):
|
|
1039
1043
|
validated_data = {
|
1040
1044
|
"content_object": object_instance,
|
1041
1045
|
"extras": extras,
|
1046
|
+
"name": name,
|
1042
1047
|
}
|
1043
1048
|
self._lookup_validation(validated_data)
|
1044
1049
|
return validated_data
|
1045
1050
|
|
1046
1051
|
def create(self, validated_data):
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
+
try:
|
1053
|
+
favorite = Favorite.add_favorite(
|
1054
|
+
content_object=validated_data["content_object"],
|
1055
|
+
user=self.context["request"].user,
|
1056
|
+
name=validated_data["name"],
|
1057
|
+
extras=validated_data["extras"],
|
1058
|
+
)
|
1059
|
+
except ValidationError as e:
|
1060
|
+
raise serializers.ValidationError(detail=e.message_dict)
|
1052
1061
|
return favorite
|
1062
|
+
|
1063
|
+
|
1064
|
+
class WalletSerializer(serializers.ModelSerializer):
|
1065
|
+
class Meta:
|
1066
|
+
model = Wallet
|
1067
|
+
fields = ["id", "user", "balance", "name", "image", "image_thumbnail_medium"]
|
1068
|
+
extra_kwargs = {
|
1069
|
+
"user": {"read_only": True},
|
1070
|
+
"image_thumbnail_medium": {"read_only": True},
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
|
1074
|
+
class WalletTopUpSerializer(serializers.Serializer):
|
1075
|
+
amount = serializers.DecimalField(
|
1076
|
+
max_digits=10, decimal_places=2, min_value=1, required=True
|
1077
|
+
)
|
1078
|
+
payment_method = serializers.PrimaryKeyRelatedField(
|
1079
|
+
queryset=PaymentMethod.objects.filter(
|
1080
|
+
payment_provider__in=[
|
1081
|
+
store_settings.TAP_CREDIT_CARD,
|
1082
|
+
store_settings.TAP_KNET,
|
1083
|
+
store_settings.TAP_ALL,
|
1084
|
+
]
|
1085
|
+
),
|
1086
|
+
required=True,
|
1087
|
+
)
|
1088
|
+
|
1089
|
+
def top_up_wallet(self, wallet):
|
1090
|
+
amount = self.validated_data["amount"]
|
1091
|
+
payment_method = self.validated_data["payment_method"]
|
1092
|
+
return wallet.top_up_wallet(amount=amount, payment_method=payment_method)
|
@@ -16,6 +16,7 @@ from ob_dj_store.apis.stores.views import (
|
|
16
16
|
TaxViewSet,
|
17
17
|
TransactionsViewSet,
|
18
18
|
VariantView,
|
19
|
+
WalletViewSet,
|
19
20
|
)
|
20
21
|
|
21
22
|
app_name = "stores"
|
@@ -28,9 +29,6 @@ stores_router.register(r"order", OrderView, basename="order")
|
|
28
29
|
stores_router.register(r"product", ProductView, basename="product")
|
29
30
|
stores_router.register(r"variant", VariantView, basename="variant")
|
30
31
|
stores_router.register(r"inventory", InventoryView, basename="inventory")
|
31
|
-
stores_router.register(
|
32
|
-
r"payment-method", PaymentMethodViewSet, basename="payment-method"
|
33
|
-
)
|
34
32
|
stores_router.register(
|
35
33
|
r"shipping-method", ShippingMethodViewSet, basename="shipping-method"
|
36
34
|
)
|
@@ -40,6 +38,8 @@ router.register(r"transaction", TransactionsViewSet, basename="transaction")
|
|
40
38
|
router.register(r"cart", CartView, basename="cart")
|
41
39
|
router.register(r"cart-item", CartItemView, basename="cart-item")
|
42
40
|
router.register(r"favorite", FavoriteViewSet, basename="favorite")
|
41
|
+
router.register(r"wallet", WalletViewSet, basename="wallet")
|
42
|
+
router.register(r"payment-method", PaymentMethodViewSet, basename="payment-method")
|
43
43
|
urlpatterns = [
|
44
44
|
path(r"", include(router.urls)),
|
45
45
|
path(r"", include(stores_router.urls)),
|
@@ -26,6 +26,7 @@ from ob_dj_store.apis.stores.filters import (
|
|
26
26
|
FavoriteFilter,
|
27
27
|
InventoryFilter,
|
28
28
|
OrderFilter,
|
29
|
+
PaymentMethodFilter,
|
29
30
|
ProductFilter,
|
30
31
|
StoreFilter,
|
31
32
|
VariantFilter,
|
@@ -47,6 +48,8 @@ from ob_dj_store.apis.stores.rest.serializers.serializers import (
|
|
47
48
|
ShippingMethodSerializer,
|
48
49
|
StoreSerializer,
|
49
50
|
TaxSerializer,
|
51
|
+
WalletSerializer,
|
52
|
+
WalletTopUpSerializer,
|
50
53
|
)
|
51
54
|
from ob_dj_store.core.stores.models import (
|
52
55
|
Cart,
|
@@ -62,6 +65,7 @@ from ob_dj_store.core.stores.models import (
|
|
62
65
|
ShippingMethod,
|
63
66
|
Store,
|
64
67
|
Tax,
|
68
|
+
Wallet,
|
65
69
|
)
|
66
70
|
from ob_dj_store.core.stores.models._inventory import Inventory
|
67
71
|
|
@@ -93,7 +97,7 @@ class StoreView(
|
|
93
97
|
|
94
98
|
def get_queryset(self):
|
95
99
|
queryset = super().get_queryset()
|
96
|
-
queryset.
|
100
|
+
queryset = queryset.prefetch_related("opening_hours")
|
97
101
|
if self.action == "favorites":
|
98
102
|
favorite_store_ids = Favorite.objects.favorites_for_model(
|
99
103
|
Store, self.request.user
|
@@ -188,29 +192,6 @@ class StoreView(
|
|
188
192
|
serializer = self.get_serializer(page, many=True)
|
189
193
|
return self.get_paginated_response(serializer.data)
|
190
194
|
|
191
|
-
@swagger_auto_schema(
|
192
|
-
operation_summary="Add or Remove Store from Favorites",
|
193
|
-
operation_description="""
|
194
|
-
Add or Remove Store from Favorites
|
195
|
-
""",
|
196
|
-
tags=[
|
197
|
-
"Store",
|
198
|
-
],
|
199
|
-
)
|
200
|
-
@action(
|
201
|
-
detail=True,
|
202
|
-
methods=["GET"],
|
203
|
-
url_path="favorite",
|
204
|
-
)
|
205
|
-
def favorite(self, request, *args, **kwargs):
|
206
|
-
instance = self.get_object()
|
207
|
-
try:
|
208
|
-
Favorite.objects.favorite_for_user(instance, request.user).delete()
|
209
|
-
except Favorite.DoesNotExist:
|
210
|
-
Favorite.add_favorite(instance, request.user)
|
211
|
-
serializer = StoreSerializer(instance=instance, context={"request": request})
|
212
|
-
return Response(serializer.data)
|
213
|
-
|
214
195
|
@swagger_auto_schema(
|
215
196
|
operation_summary="Retrieve count of store's products",
|
216
197
|
operation_description="""
|
@@ -231,10 +212,13 @@ class StoreView(
|
|
231
212
|
product_variants__inventories__store=store
|
232
213
|
).values_list("id", flat=True)
|
233
214
|
content_type = ContentType.objects.get_for_model(Product)
|
234
|
-
favorites_count =
|
235
|
-
|
236
|
-
|
237
|
-
|
215
|
+
favorites_count = (
|
216
|
+
Favorite.objects.filter(
|
217
|
+
content_type=content_type, object_id__in=products_ids, user=request.user
|
218
|
+
).count()
|
219
|
+
if request.user.id
|
220
|
+
else 0
|
221
|
+
)
|
238
222
|
menu = Product.objects.filter(
|
239
223
|
product_variants__inventories__store=store,
|
240
224
|
category__isnull=False,
|
@@ -295,7 +279,6 @@ class CartView(
|
|
295
279
|
permissions.IsAuthenticated,
|
296
280
|
]
|
297
281
|
queryset = Cart.objects.all()
|
298
|
-
lookup_value_regex = "[0-9]+"
|
299
282
|
|
300
283
|
def get_object(self):
|
301
284
|
return self.request.user.cart
|
@@ -672,6 +655,9 @@ class CategoryViewSet(
|
|
672
655
|
filterset_class = CategoryFilter
|
673
656
|
lookup_value_regex = "[0-9]+"
|
674
657
|
|
658
|
+
def get_queryset(self):
|
659
|
+
return super().get_queryset().prefetch_related("products__images")
|
660
|
+
|
675
661
|
def get_object(self):
|
676
662
|
store_id = self.request.query_params.get("store", None)
|
677
663
|
instance_pk = self.kwargs["pk"]
|
@@ -697,6 +683,7 @@ class CategoryViewSet(
|
|
697
683
|
"products",
|
698
684
|
queryset=product_queryset.distinct(),
|
699
685
|
),
|
686
|
+
"subcategories__products__images",
|
700
687
|
).get(pk=instance_pk)
|
701
688
|
except Category.DoesNotExist:
|
702
689
|
raise Http404("No Category matches the given query.")
|
@@ -798,14 +785,9 @@ class PaymentMethodViewSet(
|
|
798
785
|
permission_classes = [
|
799
786
|
permissions.IsAuthenticated,
|
800
787
|
]
|
801
|
-
queryset = PaymentMethod.objects.
|
802
|
-
|
803
|
-
|
804
|
-
try:
|
805
|
-
store = Store.objects.get(pk=self.kwargs["store_pk"])
|
806
|
-
except ObjectDoesNotExist:
|
807
|
-
raise ValidationError(_(f"Store does not Exist"))
|
808
|
-
return store.payment_methods.filter(is_active=True)
|
788
|
+
queryset = PaymentMethod.objects.filter(is_active=True)
|
789
|
+
filterset_class = PaymentMethodFilter
|
790
|
+
lookup_value_regex = "[0-9]+"
|
809
791
|
|
810
792
|
@swagger_auto_schema(
|
811
793
|
operation_summary="List Payment Methods",
|
@@ -947,3 +929,84 @@ class FavoriteViewSet(
|
|
947
929
|
)
|
948
930
|
def destroy(self, request, *args, **kwargs):
|
949
931
|
return super().destroy(request, *args, **kwargs)
|
932
|
+
|
933
|
+
|
934
|
+
class WalletViewSet(
|
935
|
+
mixins.ListModelMixin,
|
936
|
+
mixins.RetrieveModelMixin,
|
937
|
+
mixins.UpdateModelMixin,
|
938
|
+
viewsets.GenericViewSet,
|
939
|
+
):
|
940
|
+
queryset = Wallet.objects.all()
|
941
|
+
serializer_class = WalletSerializer
|
942
|
+
permission_classes = [
|
943
|
+
permissions.IsAuthenticated,
|
944
|
+
]
|
945
|
+
|
946
|
+
def get_queryset(self):
|
947
|
+
return Wallet.objects.filter(user=self.request.user)
|
948
|
+
|
949
|
+
@swagger_auto_schema(
|
950
|
+
operation_summary="Get User Wallet",
|
951
|
+
operation_description="""
|
952
|
+
Get User Wallet
|
953
|
+
""",
|
954
|
+
tags=[
|
955
|
+
"Wallet",
|
956
|
+
],
|
957
|
+
)
|
958
|
+
def retrieve(
|
959
|
+
self, request: Request, *args: typing.Any, **kwargs: typing.Any
|
960
|
+
) -> Response:
|
961
|
+
return super().retrieve(request=request, *args, **kwargs)
|
962
|
+
|
963
|
+
@swagger_auto_schema(
|
964
|
+
operation_summary="Update user wallet",
|
965
|
+
operation_description="""
|
966
|
+
Update a wallet
|
967
|
+
""",
|
968
|
+
tags=[
|
969
|
+
"Wallet",
|
970
|
+
],
|
971
|
+
)
|
972
|
+
def partial_update(self, request: Request, *args: typing.Any, **kwargs: typing.Any):
|
973
|
+
return super().partial_update(request, *args, **kwargs)
|
974
|
+
|
975
|
+
@swagger_auto_schema(
|
976
|
+
operation_summary="List User Wallets",
|
977
|
+
operation_description="""
|
978
|
+
List User Wallets
|
979
|
+
""",
|
980
|
+
tags=[
|
981
|
+
"Wallet",
|
982
|
+
],
|
983
|
+
)
|
984
|
+
def list(
|
985
|
+
self, request: Request, *args: typing.Any, **kwargs: typing.Any
|
986
|
+
) -> Response:
|
987
|
+
return super().list(request=request, *args, **kwargs)
|
988
|
+
|
989
|
+
@swagger_auto_schema(
|
990
|
+
operation_summary="top up a wallet",
|
991
|
+
operation_description="""
|
992
|
+
top up a user wallet with tap payment
|
993
|
+
""",
|
994
|
+
tags=[
|
995
|
+
"Wallet",
|
996
|
+
],
|
997
|
+
)
|
998
|
+
@action(
|
999
|
+
methods=["POST"],
|
1000
|
+
detail=True,
|
1001
|
+
url_path="top-up",
|
1002
|
+
url_name="top-up",
|
1003
|
+
serializer_class=WalletTopUpSerializer,
|
1004
|
+
)
|
1005
|
+
def top_up_wallet(
|
1006
|
+
self, request: Request, *args: typing.Any, **kwargs: typing.Any
|
1007
|
+
) -> Response:
|
1008
|
+
serializer = self.get_serializer(data=request.data)
|
1009
|
+
serializer.is_valid(raise_exception=True)
|
1010
|
+
instance = self.get_object()
|
1011
|
+
payment_url = serializer.top_up_wallet(instance)
|
1012
|
+
return Response({"payment_url": payment_url}, status=status.HTTP_200_OK)
|
@@ -99,18 +99,11 @@ class CategoryAdmin(admin.ModelAdmin):
|
|
99
99
|
list_display = ["name", "is_active", "parent", "image"]
|
100
100
|
search_fields = [
|
101
101
|
"name",
|
102
|
-
"parent__name",
|
103
102
|
]
|
104
103
|
list_filter = [
|
105
104
|
"is_active",
|
106
105
|
]
|
107
106
|
|
108
|
-
def save_model(self, request, obj, form, change) -> None:
|
109
|
-
from ob_dj_store.core.stores.receivers import create_media_thumbnails
|
110
|
-
|
111
|
-
create_media_thumbnails(None, obj, None)
|
112
|
-
return super().save_model(request, obj, form, change)
|
113
|
-
|
114
107
|
|
115
108
|
class ProductVariantAdmin(admin.ModelAdmin):
|
116
109
|
inlines = [
|
@@ -123,6 +116,9 @@ class ProductVariantAdmin(admin.ModelAdmin):
|
|
123
116
|
]
|
124
117
|
search_fields = ["name", "product__name", "sku"]
|
125
118
|
|
119
|
+
def get_queryset(self, request):
|
120
|
+
return super().get_queryset(request).prefetch_related("inventories")
|
121
|
+
|
126
122
|
|
127
123
|
class ProductAdmin(admin.ModelAdmin):
|
128
124
|
list_display = ["id", "name", "category", "type", "is_active"]
|
@@ -227,7 +223,7 @@ class PaymentAdmin(admin.ModelAdmin):
|
|
227
223
|
"method__payment_provider",
|
228
224
|
"status",
|
229
225
|
]
|
230
|
-
search_fields = ["
|
226
|
+
search_fields = ["orders__store__name", "user__email"]
|
231
227
|
|
232
228
|
|
233
229
|
class InventoryAdmin(admin.ModelAdmin):
|
@@ -250,6 +246,9 @@ class InventoryAdmin(admin.ModelAdmin):
|
|
250
246
|
"is_uncountable",
|
251
247
|
]
|
252
248
|
|
249
|
+
def get_queryset(self, request):
|
250
|
+
return super().get_queryset(request).prefetch_related("store")
|
251
|
+
|
253
252
|
|
254
253
|
class TaxAdmin(admin.ModelAdmin):
|
255
254
|
list_display = [
|
@@ -278,7 +277,7 @@ class WalletTransactionAdmin(admin.ModelAdmin):
|
|
278
277
|
"type",
|
279
278
|
]
|
280
279
|
search_fields = [
|
281
|
-
"
|
280
|
+
"wallet__user__email",
|
282
281
|
]
|
283
282
|
|
284
283
|
|
@@ -22,10 +22,10 @@ class InventoryInlineAdmin(admin.TabularInline):
|
|
22
22
|
extra = 1
|
23
23
|
|
24
24
|
def get_queryset(self, request):
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
"variant",
|
25
|
+
return (
|
26
|
+
super()
|
27
|
+
.get_queryset(request)
|
28
|
+
.select_related("variant", "store", "variant__product")
|
29
29
|
)
|
30
30
|
|
31
31
|
|
@@ -6,7 +6,6 @@ from django.db import models
|
|
6
6
|
from django.utils.translation import gettext_lazy as _
|
7
7
|
|
8
8
|
from config import settings
|
9
|
-
from ob_dj_store.core.stores.utils import get_country_by_currency
|
10
9
|
|
11
10
|
|
12
11
|
class ActiveMixin:
|
@@ -77,8 +76,7 @@ class PaymentManager(models.Manager):
|
|
77
76
|
return instance
|
78
77
|
elif gateway == settings.WALLET:
|
79
78
|
try:
|
80
|
-
|
81
|
-
wallet = kwargs["user"].wallets.get(country=country)
|
79
|
+
wallet = kwargs["user"].wallets.get(currency=currency)
|
82
80
|
except ObjectDoesNotExist:
|
83
81
|
raise ValidationError({"wallet": _("Wallet Not Found")})
|
84
82
|
WalletTransaction.objects.create(
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Generated by Django 3.2.8 on 2023-02-26 17:05
|
2
|
+
|
3
|
+
from django.conf import settings
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
import ob_dj_store.core.stores.utils
|
7
|
+
|
8
|
+
|
9
|
+
class Migration(migrations.Migration):
|
10
|
+
|
11
|
+
dependencies = [
|
12
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
13
|
+
("stores", "0061_auto_20230223_1435"),
|
14
|
+
]
|
15
|
+
|
16
|
+
operations = [
|
17
|
+
migrations.AddField(
|
18
|
+
model_name="store",
|
19
|
+
name="currency",
|
20
|
+
field=models.CharField(
|
21
|
+
default="KWD",
|
22
|
+
max_length=3,
|
23
|
+
validators=[ob_dj_store.core.stores.utils.validate_currency],
|
24
|
+
),
|
25
|
+
),
|
26
|
+
migrations.AddField(
|
27
|
+
model_name="wallet",
|
28
|
+
name="currency",
|
29
|
+
field=models.CharField(
|
30
|
+
default="KWD",
|
31
|
+
max_length=3,
|
32
|
+
validators=[ob_dj_store.core.stores.utils.validate_currency],
|
33
|
+
),
|
34
|
+
),
|
35
|
+
migrations.AlterUniqueTogether(
|
36
|
+
name="wallet",
|
37
|
+
unique_together={("user", "currency")},
|
38
|
+
),
|
39
|
+
migrations.RemoveField(
|
40
|
+
model_name="wallet",
|
41
|
+
name="country",
|
42
|
+
),
|
43
|
+
]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Generated by Django 3.2.8 on 2023-02-27 11:15
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
("stores", "0062_auto_20230226_2005"),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.AlterField(
|
14
|
+
model_name="store",
|
15
|
+
name="payment_methods",
|
16
|
+
field=models.ManyToManyField(
|
17
|
+
blank=True,
|
18
|
+
help_text="Payment methods within the store",
|
19
|
+
related_name="stores",
|
20
|
+
to="stores.PaymentMethod",
|
21
|
+
),
|
22
|
+
),
|
23
|
+
]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Generated by Django 3.2.8 on 2023-02-28 15:14
|
2
|
+
|
3
|
+
from django.conf import settings
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
|
9
|
+
dependencies = [
|
10
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
11
|
+
("stores", "0063_alter_store_payment_methods"),
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
migrations.AddField(
|
16
|
+
model_name="favorite",
|
17
|
+
name="name",
|
18
|
+
field=models.CharField(blank=True, max_length=200, null=True),
|
19
|
+
),
|
20
|
+
migrations.AlterUniqueTogether(
|
21
|
+
name="favorite",
|
22
|
+
unique_together={("name", "user")},
|
23
|
+
),
|
24
|
+
]
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Generated by Django 3.2.8 on 2023-02-28 16:32
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
import ob_dj_store.utils.helpers
|
6
|
+
|
7
|
+
|
8
|
+
class Migration(migrations.Migration):
|
9
|
+
|
10
|
+
dependencies = [
|
11
|
+
("stores", "0063_alter_store_payment_methods"),
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
migrations.AddField(
|
16
|
+
model_name="wallet",
|
17
|
+
name="image",
|
18
|
+
field=models.ImageField(
|
19
|
+
blank=True,
|
20
|
+
null=True,
|
21
|
+
upload_to=ob_dj_store.utils.helpers.wallet_media_upload_to,
|
22
|
+
),
|
23
|
+
),
|
24
|
+
migrations.AddField(
|
25
|
+
model_name="wallet",
|
26
|
+
name="image_thumbnail_medium",
|
27
|
+
field=models.ImageField(blank=True, null=True, upload_to="wallets/"),
|
28
|
+
),
|
29
|
+
migrations.AddField(
|
30
|
+
model_name="wallet",
|
31
|
+
name="name",
|
32
|
+
field=models.CharField(blank=True, max_length=200, null=True),
|
33
|
+
),
|
34
|
+
]
|
@@ -16,6 +16,7 @@ class Favorite(DjangoModelCleanMixin, models.Model):
|
|
16
16
|
user = models.ForeignKey(
|
17
17
|
get_user_model(), related_name="favorites", on_delete=models.CASCADE
|
18
18
|
)
|
19
|
+
name = models.CharField(max_length=200, null=True, blank=True)
|
19
20
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
|
20
21
|
content_object = GenericForeignKey("content_type", "object_id")
|
21
22
|
object_id = models.PositiveIntegerField()
|
@@ -26,18 +27,20 @@ class Favorite(DjangoModelCleanMixin, models.Model):
|
|
26
27
|
class Meta:
|
27
28
|
verbose_name = _("favorite")
|
28
29
|
verbose_name_plural = _("favorites")
|
30
|
+
unique_together = (("name", "user"),)
|
29
31
|
|
30
32
|
def __str__(self):
|
31
33
|
return f"{self.user} favorites {self.content_object}"
|
32
34
|
|
33
35
|
@classmethod
|
34
|
-
def add_favorite(cls, content_object, user, extras=[]):
|
36
|
+
def add_favorite(cls, content_object, user, name, extras=[]):
|
35
37
|
content_type = ContentType.objects.get_for_model(type(content_object))
|
36
38
|
favorite = Favorite(
|
37
39
|
user=user,
|
38
40
|
content_type=content_type,
|
39
41
|
object_id=content_object.pk,
|
40
42
|
content_object=content_object,
|
43
|
+
name=name,
|
41
44
|
)
|
42
45
|
favorite.save()
|
43
46
|
for extra in extras:
|