1. Refactoring form objects and database objects to use inheritance and abstract base class for consistency and reduced redundancy.\n2. Contact us page button links updated to resolve error of missing link causing page refresh instead of expected functionality.

This commit is contained in:
2024-09-10 12:09:50 +01:00
parent c9dda91dc9
commit 6b730bf8e7
709 changed files with 5158 additions and 1512 deletions

View File

@@ -19,8 +19,11 @@ Base data model for views
# from routes import bp_home
import lib.argument_validation as av
from forms.forms import Form_Is_Included_VAT, Form_Delivery_Region, Form_Currency
from datastores.datastore_base import DataStore_Base
from datastores.datastore_user import DataStore_User
from business_objects.store.store_base import Store_Base
from business_objects.store.product_category import Product_Category
from business_objects.store.access_level import Filters_Access_Level
from business_objects.user import User, User_Filters
# external
from abc import ABC, abstractmethod
@@ -33,10 +36,13 @@ from typing import ClassVar
class Model_View_Base(BaseModel, ABC):
# Global constants
# ATTR_FOR: ClassVar[str] = 'for'
ATTR_ID_ACCESS_LEVEL: ClassVar[str] = Store_Base.ATTR_ID_ACCESS_LEVEL
ATTR_TEXT_COLLAPSED: ClassVar[str] = 'textCollapsed'
ATTR_TEXT_EXPANDED: ClassVar[str] = 'textExpanded'
ATTR_VALUE_CURRENT: ClassVar[str] = 'current-value'
ATTR_VALUE_PREVIOUS: ClassVar[str] = 'previous-value'
FLAG_ACCESS_LEVEL: ClassVar[str] = 'access_level'
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = Product_Category.FLAG_ACCESS_LEVEL_REQUIRED
FLAG_ACTIVE: ClassVar[str] = Store_Base.FLAG_ACTIVE
FLAG_ADD: ClassVar[str] = 'add'
FLAG_CANCEL: ClassVar[str] = 'button-cancel'
@@ -58,10 +64,14 @@ class Model_View_Base(BaseModel, ABC):
FLAG_DISPLAY_ORDER: ClassVar[str] = Store_Base.FLAG_DISPLAY_ORDER
FLAG_ERROR: ClassVar[str] = 'error'
FLAG_EXPANDED: ClassVar[str] = 'expanded'
FLAG_FAILURE: ClassVar[str] = 'failure'
FLAG_FILTER: ClassVar[str] = 'filter'
FLAG_FORM_FILTERS: ClassVar[str] = 'form-filters'
FLAG_HAMBURGER: ClassVar[str] = 'hamburger'
FLAG_IMAGE_LOGO: ClassVar[str] = 'image-logo'
FLAG_INITIALISED: ClassVar[str] = 'initialised'
FLAG_KEY_PRIMARY: ClassVar[str] = Store_Base.FLAG_KEY_PRIMARY
FLAG_MESSAGE: ClassVar[str] = 'Message'
FLAG_MODAL: ClassVar[str] = 'modal'
FLAG_NAME: ClassVar[str] = Store_Base.FLAG_NAME
FLAG_NAV_ADMIN_HOME: ClassVar[str] = 'navAdminHome'
@@ -86,11 +96,14 @@ class Model_View_Base(BaseModel, ABC):
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
FLAG_ROW: ClassVar[str] = 'row'
FLAG_ROW_NEW: ClassVar[str] = 'row-new'
FLAG_ROWS: ClassVar[str] = Store_Base.FLAG_ROWS
FLAG_SAVE: ClassVar[str] = 'save'
FLAG_SCROLLABLE: ClassVar[str] = 'scrollable'
FLAG_SLIDER: ClassVar[str] = 'slider'
FLAG_STATUS: ClassVar[str] = 'status'
FLAG_SUBMIT: ClassVar[str] = 'submit'
FLAG_SUBMITTED: ClassVar[str] = 'submitted'
FLAG_SUCCESS: ClassVar[str] = 'success'
# flagIsDatePicker: ClassVar[str] = 'is-date-picker'
HASH_APPLY_FILTERS_STORE_PRODUCT_PERMUTATION: ClassVar[str] = '/store/permutation_filter'
HASH_CALLBACK_LOGIN: ClassVar[str] = '/callback-login'
@@ -118,6 +131,7 @@ class Model_View_Base(BaseModel, ABC):
HASH_PAGE_USER_ADMIN: ClassVar[str] = '/user/admin'
HASH_PAGE_USER_LOGIN: ClassVar[str] = '/login'
HASH_PAGE_USER_LOGOUT: ClassVar[str] = '/logout'
HASH_SCRIPTS_SECTION_STORE: ClassVar[str] = '/scripts_store'
ID_BUTTON_ADD: ClassVar[str] = 'buttonAdd'
ID_BUTTON_APPLY_FILTERS: ClassVar[str] = 'buttonApplyFilters'
ID_BUTTON_CANCEL: ClassVar[str] = 'buttonCancel'
@@ -127,6 +141,7 @@ class Model_View_Base(BaseModel, ABC):
ID_FORM_CONTACT: ClassVar[str] = 'formContact'
ID_FORM_CURRENCY: ClassVar[str] = 'formCurrency'
ID_FORM_DELIVERY_REGION: ClassVar[str] = 'formDeliveryRegion'
ID_FORM_FILTERS: ClassVar[str] = 'formFilters'
ID_FORM_IS_INCLUDED_VAT: ClassVar[str] = 'formIsIncludedVAT'
ID_LABEL_ERROR: ClassVar[str] = 'labelError'
ID_MODAL_SERVICES: ClassVar[str] = 'modalServices'
@@ -158,6 +173,7 @@ class Model_View_Base(BaseModel, ABC):
ID_TEXTAREA_CONFIRM: ClassVar[str] = 'textareaConfirm'
KEY_CALLBACK: ClassVar[str] = 'callback'
# KEY_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
KEY_DATA: ClassVar[str] = 'data'
KEY_FORM: ClassVar[str] = 'form'
KEY_FORM_FILTERS: ClassVar[str] = KEY_FORM + 'Filters'
KEY_USER: ClassVar[str] = User.KEY_USER
@@ -184,6 +200,7 @@ class Model_View_Base(BaseModel, ABC):
session: None = None
is_page_store: bool = None
is_user_logged_in: bool = None
access_levels: list = None
model_config = ConfigDict(arbitrary_types_allowed=True)
@@ -272,4 +289,21 @@ class Model_View_Base(BaseModel, ABC):
return False
"""
# def get_csrf_token(self):
def get_many_access_level(self, filters):
_m = 'Model_View_Store.get_many_access_level'
av.val_instance(filters, 'filters', _m, Filters_Access_Level)
access_levels, errors = DataStore_Base.get_many_access_level(filters)
return access_levels
@staticmethod
def convert_list_objects_to_list_options(list_objects):
return Store_Base.convert_list_objects_to_list_options(list_objects)
@staticmethod
def join_with_linebreaks(strs):
str_multiline = ''
for str in strs:
if str_multiline != '':
str_multiline += '\n'
str_multiline += str
return str_multiline

View File

@@ -18,7 +18,9 @@ Parent data model for store views
# internal
# from context import models
from models.model_view_base import Model_View_Base
from business_objects.store.store_base import Store_Base
from business_objects.store.product import Product, Filters_Product, Product_Permutation # Product_Image_Filters,
# from business_objects.store.product_category import Filters_Product_Category
from business_objects.store.image import Resolution_Level_Enum
import lib.argument_validation as av
from datastores.datastore_store_base import DataStore_Store_Base
@@ -33,6 +35,7 @@ from flask import send_file, jsonify
from flask_sqlalchemy import SQLAlchemy
import locale
from typing import ClassVar
from abc import abstractmethod
# VARIABLE INSTANTIATION
@@ -56,6 +59,7 @@ class Model_View_Store(Model_View_Base):
FLAG_DATE_PURCHASED: ClassVar[str] = 'date-purchased'
FLAG_DATE_RECEIVED: ClassVar[str] = 'date-received'
FLAG_DATE_UNSEALED: ClassVar[str] = 'date-unsealed'
FLAG_IS_NOT_EMPTY: ClassVar[str] = Store_Base.FLAG_IS_NOT_EMPTY
FLAG_IS_OUT_OF_STOCK: ClassVar[str] = 'is-out-of-stock'
FLAG_LOCATION_STORAGE: ClassVar[str] = 'storage-location'
FLAG_PRODUCT: ClassVar[str] = 'product'
@@ -64,6 +68,7 @@ class Model_View_Store(Model_View_Base):
FLAG_QUANTITY_MIN: ClassVar[str] = Product_Permutation.FLAG_QUANTITY_MIN # 'quantity-min'
FLAG_QUANTITY_STOCK: ClassVar[str] = Product_Permutation.FLAG_QUANTITY_STOCK # 'quantity-stock'
FLAG_PLANT_STORAGE: ClassVar[str] = 'plant-storage'
FLAG_PRODUCT_CATEGORY: ClassVar[str] = 'category'
FLAG_REGION_STORAGE: ClassVar[str] = 'region-storage'
FLAG_VARIATIONS: ClassVar[str] = 'variations'
HASH_PAGE_STORE_BASKET : ClassVar[str] = '/store/basket'
@@ -71,7 +76,9 @@ class Model_View_Store(Model_View_Base):
HASH_STORE_BASKET_DELETE : ClassVar[str] = '/store/basket_delete'
HASH_STORE_BASKET_EDIT : ClassVar[str] = '/store/basket_edit'
HASH_STORE_BASKET_LOAD : ClassVar[str] = '/store/basket_load'
HASH_GET_STORE_PRODUCT: ClassVar[str] = '/store/product_get'
HASH_GET_STORE_PRODUCT_CATEGORY: ClassVar[str] = '/store/category_get'
HASH_SAVE_STORE_PRODUCT: ClassVar[str] = '/store/product_save'
HASH_GET_STORE_PRODUCT_PERMUTATION: ClassVar[str] = '/store/permutation_get'
HASH_SAVE_STORE_PRODUCT_CATEGORY: ClassVar[str] = '/store/category_save'
HASH_SAVE_STORE_PRODUCT_PERMUTATION: ClassVar[str] = '/store/permutation_save'
@@ -103,7 +110,6 @@ class Model_View_Store(Model_View_Base):
KEY_NAME_VARIATION : ClassVar[str] = Product_Variation.KEY_NAME_VARIATION
KEY_NAME_VARIATION_TYPE : ClassVar[str] = Product_Variation.KEY_NAME_VARIATION_TYPE
KEY_PRICE : ClassVar[str] = 'price'
KEY_PRODUCT_CATEGORY: ClassVar[str] = 'category'
KEY_QUANTITY : ClassVar[str] = 'quantity'
KEY_VALUE_DEFAULT : ClassVar[str] = 'default'
TYPE_FORM_BASKET_ADD : ClassVar[str] = 'Form_Basket_Add'
@@ -133,6 +139,9 @@ class Model_View_Store(Model_View_Base):
# cls.FLAG_BUTTON_BASKET_ADD = cls.FLAG_BUTTON_SUBMIT + '.buttonAdd2Basket'
return super().__new__(cls, db, info_user, app) # Model_View_Store, cls
"""
@property
def title(self):
raise NotImplementedError('title must be implemented in child class')
def __init__(self, hash_page_current, **kwargs): # , id_currency, id_region_delivery, is_included_VAT):
# Constructor

View File

@@ -21,26 +21,26 @@ from models.model_view_store import Model_View_Store
from business_objects.store.product import Product
from forms.forms import Form_Basket_Add, Form_Basket_Edit # Form_Product
# external
from typing import ClassVar
# VARIABLE INSTANTIATION
# CLASSES
class Model_View_Store_Home(Model_View_Store):
# Global constants
MAX_PRODUCTS_PER_CATEGORY: ClassVar[int] = -1
# Attributes
product_categories: list # (str)
forms_product: dict
forms_basket: dict
# Global constants
# category_products: dict { category_enum_id: List[Product] }
# Attributes
@property
def title(self):
return 'Store Home'
max_products_per_category = -1
def __init__(self, id_currency, id_region_delivery, is_included_VAT, hash_page_current=Model_View_Store.HASH_PAGE_STORE_):
def __init__(self, id_currency, id_region_delivery, is_included_VAT, hash_page_current=Model_View_Store.HASH_PAGE_STORE_HOME):
# Constructor
super().__init__(id_currency, id_region_delivery, is_included_VAT)
# self.categories = Model_View_Store_Home.get_many_product(self.db, get_all_category = True, get_all_product = True)

View File

@@ -37,7 +37,7 @@ class Model_View_Store_Product(Model_View_Store):
def title(self):
return 'Store Product'
def __init__(self, id_permutation, id_currency, id_region_delivery, is_included_VAT, hash_page_current=Model_View_Store.HASH_PAGE_STORE_PRODUCT):
def __init__(self, id_permutation, id_currency, id_region_delivery, is_included_VAT, hash_page_current=Model_View_Store.HASH_PAGE_STORE_PRODUCTS):
# Constructor
_m = 'Model_View_Store_Product.__init__'
print(f'{_m}\nstarting...')
@@ -57,8 +57,10 @@ class Model_View_Store_Product(Model_View_Store):
print('connection to db successful')
# self.categories = categories
# self.category_index = category_index
if (category_list.get_count_categories() > 0):
"""
if (category_list.get_category_count() > 0):
self.product = category_list.get_permutation_first()
else:
self.product = None
print('selected permutation selected')
"""

View File

@@ -14,9 +14,10 @@ Data model for store permutations view
from models.model_view_store import Model_View_Store
# from datastores.datastore_store_base import DataStore_Store_Base
from datastores.datastore_store_product_category import DataStore_Store_Product_Category
from business_objects.store.product_category import Container_Product_Category, Filters_Product_Category
from business_objects.store.access_level import Filters_Access_Level
from business_objects.store.product_category import Product_Category_Container # , Filters_Product_Category
from forms.forms import Form_Filters_Permutation
from forms.store.product_category import Form_Filters_Product_Category
from forms.store.product_category import Filters_Product_Category
# from routes import bp_home
from business_objects.store.product import Product, Filters_Product, Product_Permutation
from business_objects.store.product_variation import Product_Variation_List
@@ -27,26 +28,25 @@ from pydantic import BaseModel
from typing import ClassVar
class Model_View_Store_Product_Category(Model_View_Store):
FLAG_IS_NOT_EMPTY: ClassVar[str] = 'is-not-empty'
ID_FORM_FILTERS_PRODUCT_CATEGORY: ClassVar[str] = 'Form_Filters_Product_Category'
KEY_CATEGORIES: ClassVar[str] = 'categories'
# KEY_CATEGORIES: ClassVar[str] = 'categories'
category_list: Container_Product_Category = None # (str)
filters_category: Filters_Product_Category
form_filters: Form_Filters_Product_Category = None
category_list: Product_Category_Container = None # (str)
# filters_category: Filters_Product_Category
form_filters: Filters_Product_Category = None
@property
def title(self):
return 'Product Category'
def __init__(self, filters_category, hash_page_current=Model_View_Store.HASH_PAGE_STORE_PRODUCT_CATEGORIES):
def __init__(self, form_filters, hash_page_current=Model_View_Store.HASH_PAGE_STORE_PRODUCT_CATEGORIES):
_m = 'Model_View_Store_Product_Category.__init__'
print(f'{_m}\nstarting...')
super().__init__(hash_page_current=hash_page_current, filters_category=filters_category)
super().__init__(hash_page_current=hash_page_current, form_filters=form_filters) # filters_category=filters_category)
# BaseModel.__init__(self, app=app, filters_product=filters_product, **kwargs)
self.access_levels = self.get_many_access_level(Filters_Access_Level())
datastore_store = DataStore_Store_Product_Category()
self.form_filters = Form_Filters_Product_Category.from_filters_product_category(filters_category)
filters_product = Filters_Product.from_filters_product_category(filters_category)
# self.form_filters = Filters_Product_Category.from_filters(filters_category)
filters_product = Filters_Product.from_filters_product_category(self.form_filters)
self.category_list, errors = datastore_store.get_many_product(filters_product)
@classmethod

View File

@@ -13,7 +13,7 @@ Data model for store permutations view
# internal
from models.model_view_store import Model_View_Store
from datastores.datastore_store_product_permutation import DataStore_Store_Product_Permutation
from business_objects.store.product_category import Container_Product_Category
from business_objects.store.product_category import Product_Category_Container
from forms.forms import Form_Filters_Permutation
# from routes import bp_home
from business_objects.store.product import Product, Filters_Product, Product_Permutation
@@ -30,10 +30,10 @@ class Model_View_Store_Product_Permutation(Model_View_Store):
ID_FILTER_IS_OUT_OF_STOCK: ClassVar[str] = 'is_out_of_stock'
ID_FILTER_QUANTITY_MIN: ClassVar[str] = 'quantity_min'
ID_FILTER_QUANTITY_MAX: ClassVar[str] = 'quantity_max'
ID_Form_Filters_Permutation: ClassVar[str] = 'Form_Filters_Permutation'
# ID_Form_Filters_Permutation: ClassVar[str] = 'Form_Filters_Permutation'
KEY_PERMUTATIONS: ClassVar[str] = 'permutations'
category_list: Container_Product_Category = None # (str)
category_list: Product_Category_Container = None # (str)
filters_product: Filters_Product
form_filters: Form_Filters_Permutation = None
permutation_blank: Product_Permutation = None
@@ -67,7 +67,7 @@ class Model_View_Store_Product_Permutation(Model_View_Store):
print(f'category_list_filters: {category_list_filters.categories}')
self.form_filters.id_category.choices = [('0', 'All')] + [(str(category.id_category), category.name) for category in category_list_filters.categories]
print(f'category options: {self.form_filters.id_category.choices}')
product_list = category_list_filters.to_list_products()
product_list = category_list_filters.to_product_option_list()
print(f'product_list: {product_list}')
self.form_filters.id_product.choices = [('0', 'All')] + [(str(product['value']), product['text']) for product in product_list]
self.permutation_blank = Product_Permutation()

View File

@@ -13,7 +13,7 @@ Data model for store stock items view
# internal
from models.model_view_store import Model_View_Store
from datastores.datastore_store_stock_item import DataStore_Store_Stock_Item
from business_objects.store.product_category import Container_Product_Category
from business_objects.store.product_category import Product_Category_Container
from forms.forms import Form_Filters_Stock_Item
# from routes import bp_home
from business_objects.store.product import Product, Filters_Product, Product_Permutation
@@ -33,7 +33,7 @@ class Model_View_Store_Stock_Items(Model_View_Store):
ID_Form_Filters_Permutation: ClassVar[str] = 'Form_Filters_Permutation'
KEY_PERMUTATIONS: ClassVar[str] = 'permutations'
category_list: Container_Product_Category = None # (str)
category_list: Product_Category_Container = None # (str)
filters_stock_item: Stock_Item_Filters
form_filters: Form_Filters_Stock_Item = None
permutation_blank: Product_Permutation = None
@@ -70,7 +70,7 @@ class Model_View_Store_Stock_Items(Model_View_Store):
print(f'category_list_filters: {category_list_filters.categories}')
self.form_filters.id_category.choices = [('0', 'All')] + [(str(category.id_category), category.name) for category in category_list_filters.categories]
print(f'category options: {self.form_filters.id_category.choices}')
product_list = category_list_filters.to_list_products()
product_list = category_list_filters.to_product_option_list()
print(f'product_list: {product_list}')
self.form_filters.id_product.choices = [('0', 'All')] + [(str(product['value']), product['text']) for product in product_list]
self.permutation_blank = Product_Permutation()