1. View, filter, and save Product Permutation. \n 2. Synchronised with Product Category page and all common functionality moved into base and base table css, js, and python files.

This commit is contained in:
2024-09-24 23:25:52 +01:00
parent d37f632c92
commit cf78e4b3bc
239 changed files with 6371 additions and 4336 deletions

59
business_objects/base.py Normal file
View File

@@ -0,0 +1,59 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Business Objects
Feature: Base Business Object
Description:
Abstract business object
"""
# internal
from extensions import db
import lib.argument_validation as av
# external
from typing import ClassVar
class Base():
ATTR_ID_ACCESS_LEVEL: ClassVar[str] = 'id_access_level'
ATTR_ID_CURRENCY: ClassVar[str] = 'id_currency'
ATTR_ID_DELIVERY_REGION: ClassVar[str] = 'id_delivery_region'
ATTR_ID_USER: ClassVar[str] = 'id_user'
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = 'access_level_required'
FLAG_ACTIVE: ClassVar[str] = 'active'
FLAG_CAN_ADMIN: ClassVar[str] = 'can_admin'
FLAG_CAN_EDIT: ClassVar[str] = 'can_edit'
FLAG_CAN_VIEW: ClassVar[str] = 'can_view'
FLAG_CODE: ClassVar[str] = 'code'
FLAG_DESCRIPTION: ClassVar[str] = 'description'
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display_order'
FLAG_GUID: ClassVar[str] = 'guid'
FLAG_IS_NOT_EMPTY: ClassVar[str] = 'is_not_empty'
# FLAG_KEY_PRIMARY: ClassVar[str] = 'key_primary'
FLAG_NAME: ClassVar[str] = 'name'
FLAG_NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'NAME_ATTR_OPTION_TEXT'
FLAG_NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'NAME_ATTR_OPTION_VALUE'
FLAG_NAME_SINGULAR: ClassVar[str] = 'name_singular'
FLAG_NAME_PLURAL: ClassVar[str] = 'name_plural'
FLAG_PRIORITY: ClassVar[str] = 'priority'
FLAG_ROWS: ClassVar[str] = 'rows'
FLAG_SYMBOL: ClassVar[str] = 'symbol'
FLAG_URL: ClassVar[str] = 'url'
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'name-attribute-option-text'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'name-attribute-option-value'
@classmethod
def output_bool(cls, value):
return av.input_bool(value, f'{cls.__name__} bool attribute', f'{cls.__name__}.output_bool')
@staticmethod
def convert_list_objects_to_list_options(objects):
return [object.to_json_option() for object in objects]
@classmethod
def get_shared_json_attributes(cls, object):
return {
cls.FLAG_NAME_ATTR_OPTION_TEXT: object.NAME_ATTR_OPTION_TEXT,
cls.FLAG_NAME_ATTR_OPTION_VALUE: object.NAME_ATTR_OPTION_VALUE
}

View File

@@ -61,8 +61,10 @@ class SQLAlchemy_ABC(db.Model, metaclass=SQLAlchemy_ABCMeta):
@classmethod
def from_json(cls, json):
pass
"""
def to_json_option(self):
pass
"""
def to_temporary_record(self):
pass
def to_object_with_missing_attributes(self, excluded_attributes):

View File

@@ -20,6 +20,8 @@ from typing import ClassVar
class Access_Level(db.Model, Store_Base):
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_ACCESS_LEVEL
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
__tablename__ = 'Shop_Access_Level_Temp'
id_access_level = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(50))
@@ -33,8 +35,9 @@ class Access_Level(db.Model, Store_Base):
def __init__(self):
super().__init__()
Store_Base.__init__(self)
def from_DB_access_level(query_row):
access_level = Access_Level()
@classmethod
def from_DB_access_level(cls, query_row):
access_level = cls()
access_level.id_access_level = query_row[0]
access_level.code = query_row[1]
access_level.name = query_row[2]
@@ -54,13 +57,14 @@ class Access_Level(db.Model, Store_Base):
'''
def to_json(self):
return {
**self.get_shared_json_attributes(self),
self.ATTR_ID_ACCESS_LEVEL: self.id_access_level[0] if isinstance(self.id_access_level, tuple) else self.id_access_level,
self.FLAG_CODE: self.code[0] if isinstance(self.code, tuple) else self.code,
self.FLAG_NAME: self.name[0] if isinstance(self.name, tuple) else self.name,
self.FLAG_DESCRIPTION: self.description[0] if isinstance(self.description, tuple) else self.description,
self.FLAG_PRIORITY: self.priority[0] if isinstance(self.priority, tuple) else self.priority,
self.FLAG_DISPLAY_ORDER: self.display_order,
self.FLAG_ACTIVE: self.active
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
}
def to_json_option(self):
return {
@@ -79,17 +83,3 @@ class Access_Level(db.Model, Store_Base):
access_level.display_order = json[cls.FLAG_DISPLAY_ORDER]
access_level.active = json[cls.FLAG_ACTIVE]
return access_level
class Filters_Access_Level(BaseModel):
get_inactive_access_level: bool
def __init__(self, get_inactive_access_level = False):
super().__init__(get_inactive_access_level = get_inactive_access_level)
def to_json(self):
return {
'a_get_inactive_access_level': self.get_inactive_access_level
}
@classmethod
def from_json(cls, json):
filters = cls()
filters.get_inactive_access_level = json['a_get_inactive_access_level']
return filters

View File

@@ -22,6 +22,7 @@ import lib.argument_validation as av
from business_objects.store.product import Product #, Filters_Product
from business_objects.store.discount import Discount
from business_objects.store.delivery_option import Delivery_Option
from business_objects.store.store_base import Store_Base
# from forms import Form_Product
# from models.model_view_store import Model_View_Store # circular
# from datastores.datastore_store import DataStore_Store # circular
@@ -107,7 +108,7 @@ class Basket_Item():
subtotal: {self.get_subtotal()}
'''
class Basket():
class Basket(Store_Base):
KEY_BASKET: str = 'basket'
KEY_ID_CURRENCY: str = 'id_currency'
KEY_ID_REGION_DELIVERY: str = 'id_region_delivery'
@@ -147,6 +148,7 @@ class Basket():
return json_list
def to_json(self):
return {
**self.get_shared_json_attributes(self),
Basket.KEY_ITEMS: self.to_json_list(),
Basket.KEY_IS_INCLUDED_VAT: self.is_included_VAT,
Basket.KEY_ID_CURRENCY: self.id_currency,

View File

@@ -11,7 +11,9 @@ Business object for product
"""
# internal
from business_objects.store.store_base import Store_Base
from extensions import db
from lib import argument_validation as av
# external
from typing import ClassVar
@@ -39,13 +41,10 @@ class Currency_Enum(Enum):
# return Resolution_Level_Enum.HIGH
"""
class Currency(db.Model):
ATTR_ID_CURRENCY: ClassVar[str] = 'id-currency'
FLAG_CODE: ClassVar[str] = 'code-currency'
FLAG_NAME: ClassVar[str] = 'name-currency'
FLAG_SYMBOL: ClassVar[str] = 'symbol-currency'
FLAG_FACTOR_FROM_GBP: ClassVar[str] = 'factor-from-GBP-currency'
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display-order-currency'
class Currency(db.Model, Store_Base):
FLAG_FACTOR_FROM_GBP: ClassVar[str] = 'factor-from-GBP'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_CURRENCY
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
id_currency = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(50))
@@ -53,29 +52,35 @@ class Currency(db.Model):
symbol = db.Column(db.String(50))
factor_from_GBP = db.Column(db.Float)
display_order = db.Column(db.Integer)
def from_DB_currency(query_row):
# _m = 'Currency.from_DB_currency'
# v_arg_type = 'class attribute'
currency = Currency()
active = db.Column(db.Boolean)
@classmethod
def from_DB_currency(cls, query_row):
_m = 'Currency.from_DB_currency'
v_arg_type = 'class attribute'
currency = cls()
currency.id_currency = query_row[0]
currency.code = query_row[1]
currency.name = query_row[2]
currency.symbol = query_row[3]
currency.factor_from_GBP = query_row[4]
currency.display_order = query_row[5]
currency.active = av.input_bool(query_row[6], 'active', _m, v_arg_type=v_arg_type)
return currency
"""
def from_DB_get_many_product_catalogue(query_row):
_m = 'Currency.from_DB_get_many_product_catalogue'
@classmethod
def from_DB_get_many_product_catalogue_product_permutation(cls, query_row):
_m = 'Currency.from_DB_get_many_product_catalogue_product_permutation'
v_arg_type = 'class attribute'
currency = Currency()
currency.id_permutation = query_row[0]
currency.id_product = query_row[1]
currency.id_category = query_row[2]
currency.id_variation = query_row[3]
currency = cls()
currency.id_currency = query_row[5]
currency.code = query_row[6]
currency.symbol = query_row[7]
return currency
@classmethod
def from_DB_get_many_product_price_and_discount_and_delivery_region(cls, query_row):
_m = 'Currency.from_DB_get_many_product_price_and_discount_and_delivery_region'
v_arg_type = 'class attribute'
currency = cls()
return currency
"""
def __repr__(self):
return f'''
id: {self.id_currency}
@@ -84,23 +89,35 @@ class Currency(db.Model):
symbol: {self.symbol}
factor from GBP: {self.factor_from_GBP}
display_order: {self.display_order}
active: {self.active}
'''
def to_json(self):
return {
Currency.ATTR_ID_CURRENCY: self.id_currency,
Currency.FLAG_CODE: self.code,
Currency.FLAG_NAME: self.name,
Currency.FLAG_SYMBOL: self.symbol,
Currency.FLAG_FACTOR_FROM_GBP: self.factor_from_GBP,
Currency.FLAG_DISPLAY_ORDER: self.display_order
**self.get_shared_json_attributes(self),
self.NAME_ATTR_OPTION_TEXT: self.FLAG_NAME,
self.NAME_ATTR_OPTION_VALUE: self.ATTR_ID_CURRENCY,
self.ATTR_ID_CURRENCY: self.id_currency,
self.FLAG_CODE: self.code,
self.FLAG_NAME: self.name,
self.FLAG_SYMBOL: self.symbol,
self.FLAG_FACTOR_FROM_GBP: self.factor_from_GBP,
self.FLAG_DISPLAY_ORDER: self.display_order,
self.FLAG_ACTIVE: self.active,
}
@staticmethod
def from_json(json_currency):
currency = Currency()
currency.id_currency = json_currency[Currency.ATTR_ID_CURRENCY]
currency.code = json_currency[Currency.FLAG_CODE]
currency.name = json_currency[Currency.FLAG_NAME]
currency.symbol = json_currency[Currency.FLAG_SYMBOL]
currency.factor_from_GBP = json_currency[Currency.FLAG_FACTOR_FROM_GBP]
currency.display_order = json_currency[Currency.FLAG_DISPLAY_ORDER]
return currency
@classmethod
def from_json(cls, json_currency, key_suffix = ''):
currency = cls()
currency.id_currency = json_currency[f'{cls.ATTR_ID_CURRENCY}{key_suffix}']
currency.code = json_currency.get(f'{cls.FLAG_CODE}{key_suffix}')
currency.name = json_currency.get(f'{cls.FLAG_NAME}{key_suffix}')
currency.symbol = json_currency.get(f'{cls.FLAG_SYMBOL}{key_suffix}')
currency.factor_from_GBP = json_currency.get(f'{cls.FLAG_FACTOR_FROM_GBP}{key_suffix}')
currency.display_order = json_currency.get(f'{cls.FLAG_DISPLAY_ORDER}{key_suffix}')
currency.active = json_currency.get(f'{cls.FLAG_ACTIVE}{key_suffix}')
return currency
def to_json_option(self):
return {
'value': self.id_currency,
'text': self.name
}

View File

@@ -11,7 +11,9 @@ Business object for delivery region
"""
# internal
from business_objects.store.store_base import Store_Base
from extensions import db
from lib import argument_validation as av
# external
from enum import Enum
from typing import ClassVar
@@ -20,12 +22,9 @@ from typing import ClassVar
class Enum_Delivery_Region(Enum):
UK = 0
class Delivery_Region(db.Model):
ATTR_ID_REGION: ClassVar[str] = 'id-region'
FLAG_CODE: ClassVar[str] = 'code-region'
FLAG_NAME: ClassVar[str] = 'name-region'
FLAG_ACTIVE: ClassVar[str] = 'active-region'
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display-order-region'
class Delivery_Region(db.Model, Store_Base):
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_DELIVERY_REGION
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
id_region = db.Column(db.Integer, primary_key=True)
"""
@@ -59,19 +58,21 @@ class Delivery_Region(db.Model):
self.code = code
self.display_order = display_order
"""
def from_DB_get_many_product_catalogue(query_row):
region = Delivery_Region()
@classmethod
def from_DB_get_many_product_catalogue(cls, query_row):
region = cls()
region.id_region = query_row[0]
region.name = query_row[1]
region.code = query_row[2]
# self.display_order = query_row[3]
return region
def from_DB_region(query_row):
region = Delivery_Region()
@classmethod
def from_DB_region(cls, query_row):
region = cls()
region.id_region = query_row[0]
region.code = query_row[1]
region.name = query_row[2]
region.active = query_row[3]
region.active = av.input_bool(query_row[3], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_region')
region.display_order = query_row[4]
return region
def __repr__(self):
@@ -84,11 +85,12 @@ class Delivery_Region(db.Model):
'''
def to_json(self):
return {
Delivery_Region.ATTR_ID_REGION: self.id_region,
Delivery_Region.FLAG_CODE: self.code,
Delivery_Region.FLAG_NAME: self.name,
Delivery_Region.FLAG_ACTIVE: self.active,
Delivery_Region.FLAG_DISPLAY_ORDER: self.display_order
**self.get_shared_json_attributes(self),
self.ATTR_ID_REGION: self.id_region,
self.FLAG_CODE: self.code,
self.FLAG_NAME: self.name,
self.FLAG_ACTIVE: self.active,
self.FLAG_DISPLAY_ORDER: self.display_order
}
@staticmethod
def from_json(json_region):

View File

@@ -11,8 +11,9 @@ Business object for product image
"""
# internal
import lib.argument_validation as av
from business_objects.store.store_base import Store_Base
from extensions import db
import lib.argument_validation as av
# external
from enum import Enum
@@ -46,7 +47,7 @@ class Resolution_Level_Enum(Enum):
return Resolution_Level_Enum.HIGH
class Image(db.Model):
class Image(db.Model, Store_Base):
id_image = db.Column(db.Integer, primary_key=True)
id_product = db.Column(db.Integer)
id_permutation = db.Column(db.Integer)
@@ -93,6 +94,15 @@ class Image(db.Model):
url: {self.url}
display_order: {self.display_order}
'''
def to_json(self):
return {
**self.get_shared_json_attributes(self),
self.ATTR_ID_PRODUCT_IMAGE: self.id_image,
self.ATTR_ID_PRODUCT: self.id_product,
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
self.FLAG_URL: self.url,
self.FLAG_DISPLAY_ORDER: self.display_order
}
class Product_Image_Filters():

View File

@@ -15,6 +15,7 @@ import lib.argument_validation as av
# from lib import data_types
from business_objects.store.product import Product
from business_objects.store.delivery_option import Delivery_Option
from business_objects.store.store_base import Store_Base
# from forms import Form_Product
# from models.model_view_store import Model_View_Store # circular
# external
@@ -26,7 +27,7 @@ import locale
# VARIABLE INSTANTIATION
# CLASSES
class Order():
class Order(Store_Base):
category: str
product: Product
quantity: int
@@ -69,6 +70,7 @@ class Order():
def to_json(self):
return {
**self.get_shared_json_attributes(self),
'product_id': self.product.id_product,
'price': self.product.price_GBP_full,
'quantity': self.quantity

View File

@@ -13,7 +13,8 @@ Business object for product
# internal
import lib.argument_validation as av
from lib import data_types
from forms.forms import Form_Basket_Add, Form_Basket_Edit, Form_Filters_Permutation
from forms.forms import Form_Basket_Add, Form_Basket_Edit
from forms.store.product_permutation import Filters_Product_Permutation
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
from business_objects.store.delivery_option import Delivery_Option
from business_objects.store.discount import Discount
@@ -52,14 +53,11 @@ class Enum_Status_Stock(Enum):
"""
class Product(SQLAlchemy_ABC, Store_Base):
FLAG_NAME: ClassVar[str] = 'name-product'
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display-order-product'
FLAG_CAN_VIEW: ClassVar[str] = 'can-view-product'
FLAG_CAN_EDIT: ClassVar[str] = 'can-edit-product'
FLAG_CAN_ADMIN: ClassVar[str] = 'can-admin-product'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME
FLAG_HAS_VARIATIONS: ClassVar[str] = 'has-variations-product'
FLAG_INDEX_PERMUTATION_SELECTED: ClassVar[str] = 'index-permutation-selected'
FLAG_VARIATION_TREES: ClassVar[str] = 'variation-trees'
FLAG_PRODUCT_VARIATION_TREES: ClassVar[str] = 'variation-trees'
id_product = db.Column(db.Integer, primary_key=True)
id_category = db.Column(db.Integer)
@@ -305,11 +303,12 @@ class Product(SQLAlchemy_ABC, Store_Base):
for json_permutation in json[cls.ATTR_ID_PRODUCT_PERMUTATION]:
product.permutations.append(Product_Permutation.from_json(json_permutation))
product.variation_trees = []
for json_tree in json[cls.FLAG_VARIATION_TREES]:
for json_tree in json[cls.FLAG_PRODUCT_VARIATION_TREES]:
product.variation_trees.append(Product_Variation_Tree.from_json(json_tree))
return product
def to_json(self):
return {
**self.get_shared_json_attributes(self),
self.ATTR_ID_PRODUCT: self.id_product,
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
self.FLAG_NAME: self.name,
@@ -320,7 +319,7 @@ class Product(SQLAlchemy_ABC, Store_Base):
self.FLAG_HAS_VARIATIONS: self.has_variations,
self.FLAG_INDEX_PERMUTATION_SELECTED: self.index_permutation_selected,
self.ATTR_ID_PRODUCT_PERMUTATION: [permutation.to_json() for permutation in self.permutations],
self.FLAG_VARIATION_TREES: [tree.to_json() for tree in self.variation_trees]
self.FLAG_PRODUCT_VARIATION_TREES: [tree.to_json() for tree in self.variation_trees]
}
def to_json_option(self):
return {
@@ -421,7 +420,7 @@ class Filters_Product():
@staticmethod
def from_form_filters_product(form):
# if not (form is Form_Filters_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Product)
has_filter_category = not (form.id_category.data == '0' or form.id_category.data == '')
is_not_empty = av.input_bool(form.is_not_empty.data, "is_not_empty", "Filters_Product.from_form_filters_product")
@@ -458,8 +457,8 @@ class Filters_Product():
)
@staticmethod
def from_form_filters_product_permutation(form):
# if not (form is Form_Filters_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Permutation)
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
av.val_instance(form, 'form', 'Filters_Product.from_form', Filters_Product_Permutation)
has_category_filter = not (form.id_category.data == '0' or form.id_category.data == '')
has_product_filter = not (form.id_product.data == '0' or form.id_product.data == '')
get_permutations_stock_below_min = av.input_bool(form.is_out_of_stock.data, "is_out_of_stock", "Filters_Product.from_form")
@@ -651,7 +650,7 @@ class Filters_Product(Get_Many_Parameters_Base):
@staticmethod
def from_form_filters_product(form):
# if not (form is Form_Filters_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Product)
has_filter_category = not (form.id_category.data == '0' or form.id_category.data == '')
is_not_empty = av.input_bool(form.is_not_empty.data, "is_not_empty", "Filters_Product.from_form_filters_product")
@@ -660,7 +659,7 @@ class Filters_Product(Get_Many_Parameters_Base):
get_all_product_category = not has_filter_category,
get_inactive_product_category = not active,
# get_first_product_category_only = False,
ids_product_category = form.id_category.data,
ids_product_category = str(form.id_category.data),
get_all_product = True,
get_inactive_product = not active,
# get_first_product_only = False,
@@ -686,23 +685,23 @@ class Filters_Product(Get_Many_Parameters_Base):
# ids_discount = '',
get_products_quantity_stock_below_min = False
)
@staticmethod
@staticmethod
def from_form_filters_product_permutation(form):
# if not (form is Form_Filters_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Permutation)
has_category_filter = not (form.id_category.data == '0' or form.id_category.data == '')
has_product_filter = not (form.id_product.data == '0' or form.id_product.data == '')
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
av.val_instance(form, 'form', 'Filters_Product.from_form', Filters_Product_Permutation)
has_category_filter = not (form.id_category.data is None or form.id_category.data == '0' or form.id_category.data == '')
has_product_filter = not (form.id_product.data is None or form.id_product.data == '0' or form.id_product.data == '')
get_permutations_stock_below_min = av.input_bool(form.is_out_of_stock.data, "is_out_of_stock", "Filters_Product.from_form")
print(f'form question: {type(form.is_out_of_stock)}\nbool interpretted: {get_permutations_stock_below_min}\type form: {type(form)}')
return Filters_Product(
get_all_product_category = not has_category_filter,
get_inactive_product_category = False,
# get_first_product_category_only = False,
ids_product_category = form.id_category.data,
ids_product_category = str(form.id_category.data) if has_category_filter else '',
get_all_product = not has_product_filter,
get_inactive_product = False,
# get_first_product_only = False,
ids_product = form.id_product.data,
ids_product = str(form.id_product.data) if has_product_filter else '',
get_all_permutation = not get_permutations_stock_below_min,
get_inactive_permutation = False,
# get_first_permutation_only = False,

View File

@@ -28,6 +28,9 @@ from typing import ClassVar
class Product_Category(SQLAlchemy_ABC, Store_Base):
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = 'id_access_level_required'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_CATEGORY
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
__tablename__ = 'Shop_Product_Category_Temp'
id_category = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(50))
@@ -48,8 +51,9 @@ class Product_Category(SQLAlchemy_ABC, Store_Base):
super().__init__()
Store_Base.__init__(self)
self.name_access_level_required = None
def from_DB_get_many_product_catalogue(query_row):
category = Product_Category()
@classmethod
def from_DB_get_many_product_catalogue(cls, query_row):
category = cls()
category.id_category = query_row[0]
category.code = query_row[1]
category.name = query_row[2]
@@ -57,10 +61,10 @@ class Product_Category(SQLAlchemy_ABC, Store_Base):
category.id_access_level_required = query_row[4]
category.name_access_level_required = query_row[5]
category.display_order = query_row[6]
category.active = query_row[7]
category.can_view = query_row[8]
category.can_edit = query_row[9]
category.can_admin = query_row[10]
category.active = av.input_bool(query_row[7], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_get_many_product_catalogue')
category.can_view = av.input_bool(query_row[8], cls.FLAG_CAN_VIEW, f'{cls.__name__}.from_DB_get_many_product_catalogue')
category.can_edit = av.input_bool(query_row[9], cls.FLAG_CAN_EDIT, f'{cls.__name__}.from_DB_get_many_product_catalogue')
category.can_admin = av.input_bool(query_row[10], cls.FLAG_CAN_ADMIN, f'{cls.__name__}.from_DB_get_many_product_catalogue')
return category
"""
def key_product_index_from_ids_product_permutation(id_product, id_permutation):
@@ -178,7 +182,7 @@ class Product_Category(SQLAlchemy_ABC, Store_Base):
return list_products
def to_json(self):
return {
self.FLAG_KEY_PRIMARY: self.ATTR_ID_PRODUCT_CATEGORY,
**self.get_shared_json_attributes(self),
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category[0] if isinstance(self.id_category, tuple) else self.id_category,
self.FLAG_CODE: self.code[0] if isinstance(self.code, tuple) else self.code,
self.FLAG_NAME: self.name[0] if isinstance(self.name, tuple) else self.name,
@@ -195,12 +199,12 @@ class Product_Category(SQLAlchemy_ABC, Store_Base):
def from_json(cls, json):
print(f' Category.from_json: {json}')
category = cls()
category.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY],
category.code = json[cls.FLAG_CODE],
category.name = json[cls.FLAG_NAME],
category.description = json[cls.FLAG_DESCRIPTION],
category.id_access_level_required = json[cls.ATTR_ID_ACCESS_LEVEL],
category.name_access_level_required = json.get(cls.FLAG_ACCESS_LEVEL_REQUIRED, ''),
category.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
category.code = json[cls.FLAG_CODE]
category.name = json[cls.FLAG_NAME]
category.description = json[cls.FLAG_DESCRIPTION]
category.id_access_level_required = json[cls.ATTR_ID_ACCESS_LEVEL]
category.name_access_level_required = json.get(cls.FLAG_ACCESS_LEVEL_REQUIRED, '')
category.display_order = json[cls.FLAG_DISPLAY_ORDER]
category.active = json[cls.FLAG_ACTIVE]
category.can_view = json.get(cls.FLAG_CAN_VIEW, False)
@@ -258,8 +262,9 @@ class Filters_Product_Category(BaseModel, Store_Base):
ids_product_category = '',
ids_product = ''
)
def to_json(self):
def to_json(self):
return {
**self.get_shared_json_attributes(self),
'a_ids_product_category': self.ids_product_category,
'a_ids_product': self.ids_product
}
@@ -282,10 +287,11 @@ class Filters_Product_Category(Get_Many_Parameters_Base):
is_not_empty = False,
active = True
)
def to_json(self):
def to_json(self):
return {
**self.get_shared_json_attributes(self),
self.FLAG_IS_NOT_EMPTY: self.is_not_empty,
self.FLAG_ACTIVE: self.active
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
}
@classmethod
def from_json(cls, json):
@@ -379,13 +385,19 @@ class Product_Category_Container(Store_Base):
for category in self.categories:
list_categories.append({'value': category.id_category, 'text': category.name})
return list_categories
def to_product_option_list(self):
def get_list_products(self):
list_products = []
for category in self.categories:
# list_products.append(category.to_product_option_list())
"""
for product in category.products:
list_products.append({'value': product.id_product, 'text': product.name, Product.ATTR_ID_PRODUCT_CATEGORY: product.id_category})
"""
list_products += category.products
return list_products
def to_product_option_list(self):
list_products = self.get_list_products()
return [{'value': product.id_product, 'text': product.name, Product.ATTR_ID_PRODUCT_CATEGORY: product.id_category} for product in list_products]
def get_product_option_lists_by_category(self):
dict_lists_products = {}
for category in self.categories:
@@ -393,6 +405,7 @@ class Product_Category_Container(Store_Base):
return dict_lists_products
def to_json(self):
return {
**self.get_shared_json_attributes(self),
f'{self.FLAG_ROWS}': [category.to_json() for category in self.categories]
}
"""
@@ -412,4 +425,64 @@ class Product_Category_Container(Store_Base):
for column in self.__table__.columns
if column.name not in ['created_on', 'created_by']
}
return self.to_object_with_missing_attributes(excluded_attributes)
return self.to_object_with_missing_attributes(excluded_attributes)
"""
class Table_Shop_Product_Category(db.Model):
__tablename__ = 'Shop_Product_Category'
id_category: int = db.Column(db.Integer, primary_key=True)
code: str = db.Column(db.String(50))
name: str = db.Column(db.String(255))
description: str = db.Column(db.String(4000))
active: bool = db.Column(db.Boolean)
display_order: int = db.Column(db.Integer)
created_on: datetime = db.Column(db.DateTime)
created_by: int = db.Column(db.Integer)
id_change_set: int = db.Column(db.Integer)
"""
class Product_Category_Temp(db.Model):
__tablename__ = 'Shop_Product_Category_Temp'
__table_args__ = { 'extend_existing': True }
id_category: int = db.Column(db.Integer, primary_key=True)
code: str = db.Column(db.String(50))
name: str = db.Column(db.String(255))
description: str = db.Column(db.String(4000))
id_access_level_required: int = db.Column(db.Integer)
active: bool = db.Column(db.Boolean)
display_order: int = db.Column(db.Integer)
guid: str = db.Column(db.BINARY(36))
# created_on: datetime = db.Column(db.DateTime)
# created_by: int = db.Column(db.Integer)
@classmethod
def from_product_category(cls, product_category):
row = cls()
row.id_category = product_category.id_category[0] if isinstance(product_category.id_category, tuple) else product_category.id_category
row.code = product_category.code[0] if isinstance(product_category.code, tuple) else product_category.code
row.name = product_category.name[0] if isinstance(product_category.name, tuple) else product_category.name
row.description = product_category.description[0] if isinstance(product_category.description, tuple) else product_category.description
row.id_access_level_required = product_category.id_access_level_required[0] if isinstance(product_category.id_access_level_required, tuple) else product_category.id_access_level_required
row.active = product_category.active
row.display_order = product_category.display_order
"""
row.guid = product_category.guid
row.created_on = product_category.created_on
row.created_by = product_category.created_by
"""
return row
def to_json(self):
return {
'id_category': self.id_category,
'code': self.code,
'name': self.name,
'description': self.description,
'id_access_level_required': self.id_access_level_required,
'active': av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
'display_order': self.display_order,
'guid': self.guid,
}
"""
'created_on': self.created_on,
'created_by': self.created_by
"""

View File

@@ -13,7 +13,8 @@ Business object for product permutation
# internal
import lib.argument_validation as av
from lib import data_types
from forms.forms import Form_Basket_Add, Form_Basket_Edit, Form_Filters_Permutation
from forms.forms import Form_Basket_Add, Form_Basket_Edit
from business_objects.store.currency import Currency
from business_objects.store.delivery_option import Delivery_Option
from business_objects.store.discount import Discount
from business_objects.store.image import Image
@@ -22,42 +23,91 @@ from business_objects.store.stock_item import Stock_Item
from business_objects.store.store_base import Store_Base
from business_objects.store.product_variation import Product_Variation
from business_objects.store.product_variation_tree import Product_Variation_Tree
from business_objects.unit_measurement import Unit_Measurement
from extensions import db
# external
from datetime import datetime, timedelta
import locale
from dataclasses import dataclass
from typing import ClassVar
class Product_Permutation(db.Model, Store_Base):
FLAG_QUANTITY_STOCK = 'quantity-stock'
FLAG_QUANTITY_MIN = 'quantity-min'
FLAG_QUANTITY_MAX = 'quantity-max'
FLAG_COST_LOCAL = 'cost-local'
NAME_ATTR_OPTION_VALUE = Store_Base.ATTR_ID_PRODUCT_PERMUTATION
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME
FLAG_CURRENCY_COST = f'{Currency.ATTR_ID_CURRENCY}_cost'
FLAG_CODE_CURRENCY_COST = f'{Currency.FLAG_CODE}_cost'
FLAG_SYMBOL_CURRENCY_COST = f'{Currency.FLAG_SYMBOL}_cost'
FLAG_COST_LOCAL = 'cost_local'
FLAG_PROFIT_LOCAL_MIN = 'profit_local_min'
FLAG_HAS_VARIATIONS = 'has_variations'
FLAG_LATENCY_MANUFACTURE_DAYS = 'latency_manufacture_days'
FLAG_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.ATTR_ID_UNIT_MEASUREMENT}_quantity'
FLAG_SYMBOL_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.FLAG_SYMBOL}_quantity'
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX}_quantity'
FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.FLAG_NAME_SINGULAR}_quantity'
FLAG_NAME_PLURAL_UNIT_MEASUREMENT_QUANTITY = f'{Unit_Measurement.FLAG_NAME_PLURAL}_quantity'
FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP = 'count_unit_measurement_per_quantity_step'
FLAG_QUANTITY_STOCK = 'quantity_stock'
FLAG_IS_SUBSCRIPTION = 'is_subscription'
FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.ATTR_ID_UNIT_MEASUREMENT}_interval_recurrence'
FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.FLAG_SYMBOL}_unit_measurement_interval_recurrence'
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX}_unit_measurement_interval_recurrence'
FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.FLAG_NAME_SINGULAR}_unit_measurement_interval_recurrence'
FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = f'{Unit_Measurement.FLAG_NAME_PLURAL}_unit_measurement_interval_recurrence'
FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE = 'count_interval_recurrence'
FLAG_ID_STRIPE_PRODUCT = 'id_stripe_product'
FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED = 'does_expire_faster_once_unsealed'
FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.ATTR_ID_UNIT_MEASUREMENT}_interval_expiration_unsealed'
FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.FLAG_SYMBOL}_interval_expiration_unsealed'
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX}_interval_expiration_unsealed'
FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.FLAG_NAME_SINGULAR}_interval_expiration_unsealed'
FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = f'{Unit_Measurement.FLAG_NAME_PLURAL}_interval_expiration_unsealed'
FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED = 'count_interval_expiration_unsealed'
id_product = db.Column(db.Integer, primary_key=True)
id_permutation = db.Column(db.Integer, primary_key=True)
id_product = db.Column(db.Integer)
id_category = db.Column(db.Integer)
# name = db.Column(db.String(255))
description = db.Column(db.String(4000))
# price_GBP_full = db.Column(db.Float)
# price_GBP_min = db.Column(db.Float)
"""
id_currency_cost = db.Column(db.Integer)
code_currency_cost = db.Column(db.String(3))
symbol_currency_cost = db.Column(db.String(3))
"""
# currency_cost: Currency
cost_local = db.Column(db.Float)
profit_local_min = db.Column(db.Float)
has_variations = db.Column(db.Boolean)
id_category = db.Column(db.Integer)
latency_manufacture = db.Column(db.Integer)
latency_manufacture_days = db.Column(db.Integer)
id_unit_measurement_quantity = db.Column(db.Integer)
symbol_unit_measurement_quantity = db.Column(db.String(50))
symbol_is_suffix_not_prefix_unit_measurement_quantity = db.Column(db.Boolean)
name_singular_unit_measurement_quantity = db.Column(db.String(255))
name_plural_unit_measurement_quantity = db.Column(db.String(256))
count_unit_measurement_per_quantity_step = db.Column(db.Integer)
quantity_min = db.Column(db.Float)
quantity_max = db.Column(db.Float)
quantity_step = db.Column(db.Float)
quantity_stock = db.Column(db.Float)
id_stripe_product = db.Column(db.String(100))
is_subscription = db.Column(db.Boolean)
name_recurrence_interval = db.Column(db.String(255))
name_plural_recurrence_interval = db.Column(db.String(256))
count_recurrence_interval = db.Column(db.Integer)
id_unit_measurement_interval_recurrence = db.Column(db.Integer)
symbol_unit_measurement_interval_recurrence = db.Column(db.String(50))
symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence = db.Column(db.Boolean)
name_singular_unit_measurement_interval_recurrence = db.Column(db.String(255))
name_plural_unit_measurement_interval_recurrence = db.Column(db.String(256))
count_interval_recurrence = db.Column(db.Integer)
id_stripe_product = db.Column(db.String(100))
does_expire_faster_once_unsealed = db.Column(db.Boolean)
id_unit_measurement_interval_expiration_unsealed = db.Column(db.Integer)
symbol_unit_measurement_interval_expiration_unsealed = db.Column(db.String(50))
symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed = db.Column(db.Boolean)
name_singular_unit_measurement_interval_expiration_unsealed = db.Column(db.String(255))
name_plural_unit_measurement_interval_expiration_unsealed = db.Column(db.String(256))
count_interval_expiration_unsealed = db.Column(db.Integer)
has_variations = db.Column(db.Boolean)
active = db.Column(db.Boolean)
display_order = db.Column(db.Integer)
# display_order = db.Column(db.Integer)
can_view = db.Column(db.Boolean)
can_edit = db.Column(db.Boolean)
can_admin = db.Column(db.Boolean)
@@ -82,41 +132,56 @@ class Product_Permutation(db.Model, Store_Base):
self.stock_item_index = {}
super().__init__()
Store_Base.__init__(self)
self.currency_cost = None
self.form_basket_add = Form_Basket_Add()
self.form_basket_edit = Form_Basket_Edit()
self.is_unavailable_in_currency_or_region = False
# self.is_available = False
self.variation_tree = None
def from_DB_get_many_product_catalogue(query_row):
_m = 'Product_Permutation.from_DB_get_many_product_catalogue'
@classmethod
def from_DB_get_many_product_catalogue(cls, query_row):
_m = f'{cls.__name__}.from_DB_get_many_product_catalogue'
v_arg_type = 'class attribute'
print(f'query_row: {query_row}')
permutation = Product_Permutation()
permutation = cls()
permutation.id_permutation = query_row[0]
permutation.id_product = query_row[1]
permutation.id_category = query_row[2]
permutation.description = query_row[3]
permutation.cost_local = query_row[4]
permutation.id_currency_cost = query_row[5]
permutation.code_currency_cost = query_row[6]
permutation.symbol_currency_cost = query_row[7]
# permutation.profit_local_min = query_row[8]
permutation.latency_manufacture = query_row[9]
permutation.quantity_min = query_row[10]
permutation.quantity_max = query_row[11]
permutation.quantity_step = query_row[12]
permutation.quantity_stock = query_row[13]
permutation.id_stripe_product = query_row[14]
permutation.is_subscription = av.input_bool(query_row[15], "is_subscription", _m, v_arg_type=v_arg_type)
permutation.name_recurrence_interval = query_row[16]
permutation.name_plural_recurrence_interval = query_row[17]
permutation.count_recurrence_interval = query_row[18]
permutation.active = query_row[19]
permutation.display_order = query_row[20]
permutation.can_view = av.input_bool(query_row[21], "can_view", _m, v_arg_type=v_arg_type)
permutation.can_edit = av.input_bool(query_row[22], "can_edit", _m, v_arg_type=v_arg_type)
permutation.can_admin = av.input_bool(query_row[23], "can_admin", _m, v_arg_type=v_arg_type)
permutation.currency_cost = Currency.from_DB_get_many_product_catalogue_product_permutation(query_row)
permutation.profit_local_min = query_row[8]
permutation.latency_manufacture_days = query_row[9]
permutation.id_unit_measurement_quantity = query_row[10]
permutation.symbol_unit_measurement_quantity = query_row[11]
permutation.symbol_is_suffix_not_prefix_unit_measurement_quantity = av.input_bool(query_row[12], cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_QUANTITY, _m, v_arg_type=v_arg_type)
permutation.name_singular_unit_measurement_quantity = query_row[13]
permutation.name_plural_unit_measurement_quantity = query_row[14]
permutation.count_unit_measurement_per_quantity_step = query_row[15]
permutation.quantity_min = query_row[16]
permutation.quantity_max = query_row[17]
permutation.quantity_stock = query_row[18]
permutation.is_subscription = av.input_bool(query_row[19], "is_subscription", _m, v_arg_type=v_arg_type)
permutation.id_unit_measurement_interval_recurrence = query_row[20]
permutation.symbol_unit_measurement_interval_recurrence = query_row[21]
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence = av.input_bool(query_row[22], cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_RECURRENCE, _m, v_arg_type=v_arg_type)
permutation.name_singular_unit_measurement_interval_recurrence = query_row[23]
permutation.name_plural_unit_measurement_interval_recurrence = query_row[24]
permutation.count_interval_recurrence = query_row[25]
permutation.id_stripe_product = query_row[26]
permutation.does_expire_faster_once_unsealed = av.input_bool(query_row[27], "does_expire_faster_once_unsealed", _m, v_arg_type=v_arg_type)
permutation.id_unit_measurement_interval_expiration_unsealed = query_row[28]
permutation.symbol_unit_measurement_interval_expiration_unsealed = query_row[29]
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed = av.input_bool(query_row[30], cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED, _m, v_arg_type=v_arg_type)
permutation.name_singular_unit_measurement_interval_expiration_unsealed = query_row[31]
permutation.name_plural_unit_measurement_interval_expiration_unsealed = query_row[32]
permutation.count_interval_expiration_unsealed = query_row[33]
permutation.has_variations = av.input_bool(query_row[34], cls.FLAG_HAS_VARIATIONS, _m, v_arg_type=v_arg_type)
permutation.active = av.input_bool(query_row[35], cls.FLAG_ACTIVE, _m, v_arg_type=v_arg_type)
# permutation.display_order = query_row[27]
permutation.can_view = av.input_bool(query_row[36], "can_view", _m, v_arg_type=v_arg_type)
permutation.can_edit = av.input_bool(query_row[37], "can_edit", _m, v_arg_type=v_arg_type)
permutation.can_admin = av.input_bool(query_row[38], "can_admin", _m, v_arg_type=v_arg_type)
return permutation
def from_DB_Stripe_product(query_row):
@@ -136,8 +201,8 @@ class Product_Permutation(db.Model, Store_Base):
# permutation.price_GBP_full = query_row[1]
permutation.id_stripe_product = query_row[2]
permutation.is_subscription = av.input_bool(query_row[3], "is_subscription", _m, v_arg_type=v_arg_type)
permutation.name_recurrence_interval = query_row[4]
permutation.count_recurrence_interval = query_row[5]
permutation.name_singular_unit_measurement_interval_recurrence = query_row[4]
permutation.count_interval_recurrence = query_row[5]
return permutation
"""
def from_json(json_basket_item, key_id_product, key_id_permutation):
@@ -150,49 +215,102 @@ class Product_Permutation(db.Model, Store_Base):
"""
@classmethod
def from_json(cls, json):
_m = f'{cls.__name__}.from_json'
permutation = cls()
permutation.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
permutation.id_product = json[cls.ATTR_ID_PRODUCT]
permutation.id_permutation = json[cls.ATTR_ID_PRODUCT_PERMUTATION]
permutation.has_variations = len(json[cls.ATTR_ID_PRODUCT_VARIATION]) > 0
if permutation.has_variations:
for jsonProductVariation in json[cls.ATTR_ID_PRODUCT_VARIATION]:
variation = Product_Variation.from_json(jsonProductVariation)
permutation.add_product_variation(variation)
permutation.quantity_stock = json[cls.FLAG_QUANTITY_STOCK]
permutation.id_product = json[cls.ATTR_ID_PRODUCT]
permutation.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
permutation.description = json[cls.FLAG_DESCRIPTION]
permutation.cost_local = json[cls.FLAG_COST_LOCAL]
permutation.currency_cost = Currency.from_json(json, '_cost')
permutation.profit_local_min = json[cls.FLAG_PROFIT_LOCAL_MIN]
permutation.latency_manufacture_days = json[cls.FLAG_LATENCY_MANUFACTURE_DAYS]
permutation.id_unit_measurement_quantity = json[cls.FLAG_UNIT_MEASUREMENT_QUANTITY]
permutation.symbol_unit_measurement_quantity = json.get(cls.FLAG_SYMBOL_UNIT_MEASUREMENT_QUANTITY)
permutation.symbol_is_suffix_not_prefix_unit_measurement_quantity = json.get(cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_QUANTITY)
permutation.name_singular_unit_measurement_quantity = json.get(cls.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_QUANTITY)
permutation.name_plural_unit_measurement_quantity = json.get(cls.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_QUANTITY)
permutation.count_unit_measurement_per_quantity_step = json[cls.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP]
permutation.quantity_min = json[cls.FLAG_QUANTITY_MIN]
permutation.quantity_max = json[cls.FLAG_QUANTITY_MAX]
permutation.quantity_stock = json[cls.FLAG_QUANTITY_STOCK]
permutation.is_subscription = 1 if av.input_bool(json[cls.FLAG_IS_SUBSCRIPTION], cls.FLAG_IS_SUBSCRIPTION, _m) else 0
permutation.id_unit_measurement_interval_recurrence = json[cls.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE] if json[cls.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE] != '' else None
permutation.symbol_unit_measurement_interval_recurrence = json.get(cls.FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE)
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence = json.get(cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_RECURRENCE)
permutation.name_singular_unit_measurement_interval_recurrence = json.get(cls.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_RECURRENCE)
permutation.name_plural_unit_measurement_interval_recurrence = json.get(cls.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE)
permutation.count_interval_recurrence = json[cls.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE] if json[cls.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE] != '' else None
permutation.id_stripe_product = json[cls.FLAG_ID_STRIPE_PRODUCT]
permutation.does_expire_faster_once_unsealed = 1 if av.input_bool(json[cls.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED], cls.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED, _m) else 0
permutation.id_unit_measurement_interval_expiration_unsealed = json[cls.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED] if json[cls.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED] != '' else None
permutation.symbol_unit_measurement_interval_expiration_unsealed = json.get(cls.FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED)
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed = json.get(cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED)
permutation.name_singular_unit_measurement_interval_expiration_unsealed = json.get(cls.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED)
permutation.name_plural_unit_measurement_interval_expiration_unsealed = json.get(cls.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED)
permutation.count_interval_expiration_unsealed = json[cls.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED] if json[cls.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED] != '' else None
permutation.has_variations = json[cls.FLAG_HAS_VARIATIONS]
permutation.active = 1 if av.input_bool(json[cls.FLAG_ACTIVE], cls.FLAG_ACTIVE, _m) else 0
if permutation.has_variations:
permutation.variation_tree = Product_Variation_Tree.from_json_str(json[cls.FLAG_PRODUCT_VARIATIONS])
"""
for jsonProductVariation in json[cls.FLAG_PRODUCT_VARIATIONS]:
variation = Product_Variation.from_json(jsonProductVariation)
permutation.add_product_variation(variation)
"""
return permutation
def to_json(self):
return {
'id_product': {self.id_product},
'id_permutation': {self.id_permutation},
'description': {self.description},
'id_category': {self.id_category},
'latency_manufacture': {self.latency_manufacture},
'quantity_min': {self.quantity_min},
'quantity_max': {self.quantity_max},
'quantity_step': {self.quantity_step},
'quantity_stock': {self.quantity_stock},
'id_stripe_product': {self.id_stripe_product},
'is_subscription': {self.is_subscription},
'name_recurrence_interval': {self.name_recurrence_interval},
'name_plural_recurrence_interval': {self.name_plural_recurrence_interval},
'count_recurrence_interval': {self.count_recurrence_interval},
'display_order': {self.display_order},
'can_view': {self.can_view},
'can_edit': {self.can_edit},
'can_admin': {self.can_admin},
'variations': {self.variations},
'images': {self.images},
'delivery_options': {self.delivery_options},
'prices': {self.prices}
**self.get_shared_json_attributes(self),
self.ATTR_ID_PRODUCT_PERMUTATION: self.id_permutation,
self.ATTR_ID_PRODUCT: self.id_product,
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
self.FLAG_DESCRIPTION: self.description,
self.FLAG_COST_LOCAL: self.cost_local,
self.FLAG_CURRENCY_COST: self.currency_cost.to_json(),
self.FLAG_PROFIT_LOCAL_MIN: self.profit_local_min,
self.FLAG_LATENCY_MANUFACTURE_DAYS: self.latency_manufacture_days,
self.FLAG_UNIT_MEASUREMENT_QUANTITY: self.id_unit_measurement_quantity,
self.FLAG_SYMBOL_UNIT_MEASUREMENT_QUANTITY: self.symbol_unit_measurement_quantity,
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_QUANTITY: self.symbol_is_suffix_not_prefix_unit_measurement_quantity,
self.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_QUANTITY: self.name_singular_unit_measurement_quantity,
self.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_QUANTITY: self.name_plural_unit_measurement_quantity,
self.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP: self.count_unit_measurement_per_quantity_step,
self.FLAG_QUANTITY_MIN: self.quantity_min,
self.FLAG_QUANTITY_MAX: self.quantity_max,
self.FLAG_QUANTITY_STOCK: self.quantity_stock,
self.FLAG_IS_SUBSCRIPTION: self.is_subscription,
self.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.id_unit_measurement_interval_recurrence,
self.FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.symbol_unit_measurement_interval_recurrence,
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence,
self.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.name_singular_unit_measurement_interval_recurrence,
self.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.name_plural_unit_measurement_interval_recurrence,
self.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: self.count_interval_recurrence,
self.FLAG_ID_STRIPE_PRODUCT: self.id_stripe_product,
self.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED: self.does_expire_faster_once_unsealed,
self.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.id_unit_measurement_interval_expiration_unsealed,
self.FLAG_SYMBOL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.symbol_unit_measurement_interval_expiration_unsealed,
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed,
self.FLAG_NAME_SINGULAR_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.name_singular_unit_measurement_interval_expiration_unsealed,
self.FLAG_NAME_PLURAL_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.name_plural_unit_measurement_interval_expiration_unsealed,
self.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: self.count_interval_expiration_unsealed,
self.FLAG_HAS_VARIATIONS: self.has_variations,
self.FLAG_ACTIVE: self.active,
self.FLAG_CAN_VIEW: self.can_view,
self.FLAG_CAN_EDIT: self.can_edit,
self.FLAG_CAN_ADMIN: self.can_admin,
self.FLAG_PRODUCT_VARIATION: [variation.to_json() for variation in self.variations],
self.FLAG_PRODUCT_IMAGE: [image.to_json() for image in self.images],
self.FLAG_DELIVERY_OPTION: [option.to_json() for option in self.delivery_options],
self.FLAG_PRODUCT_PRICE: [price.to_json() for price in self.prices],
}
def to_json_option(self):
return {
'value': self.id_permutation,
'text': self.get_name_variations()
}
def get_name(self):
return
def get_name_variations(self):
return self.variation_tree.get_name_variations()
def is_available(self):
@@ -207,10 +325,10 @@ class Product_Permutation(db.Model, Store_Base):
return price.value_local_VAT_excl
def output_lead_time(self):
return '1 day' if self.latency_manufacture == 1 else f'{self.latency_manufacture} days'
return '1 day' if self.latency_manufacture_days == 1 else f'{self.latency_manufacture_days} days'
def output_delivery_date(self):
return (datetime.now() + timedelta(days=self.latency_manufacture)).strftime('%A, %d %B %Y')
return (datetime.now() + timedelta(days=self.latency_manufacture_days)).strftime('%A, %d %B %Y')
def output_price(self, is_included_VAT):
if self.is_unavailable_in_currency_or_region:
@@ -252,21 +370,38 @@ class Product_Permutation(db.Model, Store_Base):
"""
def __repr__(self):
return f'''Product_Permutation
id_product: {self.id_product}
id_permutation: {self.id_permutation}
description: {self.description}
id_product: {self.id_product}
id_category: {self.id_category}
latency_manufacture: {self.latency_manufacture}
description: {self.description}
cost_local: {self.cost_local}
currency_cost: {self.currency_cost}
latency_manufacture_days: {self.latency_manufacture_days}
id_unit_measurement_quantity: {self.id_unit_measurement_quantity}
symbol_unit_measurement_quantity: {self.symbol_unit_measurement_quantity}
symbol_is_suffix_not_prefix_unit_measurement_quantity: {self.symbol_is_suffix_not_prefix_unit_measurement_quantity}
name_singular_unit_measurement_quantity: {self.name_singular_unit_measurement_quantity}
name_plural_unit_measurement_quantity: {self.name_plural_unit_measurement_quantity}
count_unit_measurement_per_quantity_step: {self.count_unit_measurement_per_quantity_step}
quantity_min: {self.quantity_min}
quantity_max: {self.quantity_max}
quantity_step: {self.quantity_step}
quantity_stock: {self.quantity_stock}
id_stripe_product: {self.id_stripe_product}
is_subscription: {self.is_subscription}
name_recurrence_interval: {self.name_recurrence_interval}
name_plural_recurrence_interval: {self.name_plural_recurrence_interval}
count_recurrence_interval: {self.count_recurrence_interval}
display_order: {self.display_order}
id_unit_measurement_interval_recurrence: {self.id_unit_measurement_interval_recurrence}
symbol_unit_measurement_interval_recurrence: {self.symbol_unit_measurement_interval_recurrence}
symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence: {self.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence}
name_singular_unit_measurement_interval_recurrence: {self.name_singular_unit_measurement_interval_recurrence}
name_plural_unit_measurement_interval_recurrence: {self.name_plural_unit_measurement_interval_recurrence}
count_interval_recurrence: {self.count_interval_recurrence}
id_stripe_product: {self.id_stripe_product}
does_expire_faster_once_unsealed: {self.does_expire_faster_once_unsealed}
id_unit_measurement_interval_expiration_unsealed: {self.id_unit_measurement_interval_expiration_unsealed}
symbol_unit_measurement_interval_expiration_unsealed: {self.symbol_unit_measurement_interval_expiration_unsealed}
symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed: {self.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed}
name_singular_unit_measurement_interval_expiration_unsealed: {self.name_singular_unit_measurement_interval_expiration_unsealed}
name_plural_unit_measurement_interval_expiration_unsealed: {self.name_plural_unit_measurement_interval_expiration_unsealed}
count_interval_expiration_unsealed: {self.count_interval_expiration_unsealed}
has_variations: {self.has_variations}
can_view: {self.can_view}
can_edit: {self.can_edit}
can_admin: {self.can_admin}
@@ -378,3 +513,104 @@ class Permutation_Product_Variation_Link(db.Model):
link.id_variation = query_row[3]
return link
"""
class Product_Permutation_Temp(db.Model, Store_Base):
__tablename__: ClassVar[str] = 'Shop_Product_Permutation_Temp'
__table_args__ = { 'extend_existing': True }
id_permutation: int = db.Column(db.Integer, primary_key=True)
id_product: int = db.Column(db.Integer)
description: str = db.Column(db.String(4000))
cost_local: float = db.Column(db.Float)
id_currency_cost: int = db.Column(db.Integer)
profit_local_min: float = db.Column(db.Float)
latency_manufacture_days: int = db.Column(db.Integer)
id_unit_measurement_quantity: int = db.Column(db.Integer)
count_unit_measurement_per_quantity_step: int = db.Column(db.Float)
quantity_min: int = db.Column(db.Integer)
quantity_max: int = db.Column(db.Integer)
quantity_stock: int = db.Column(db.Integer)
is_subscription: bool = db.Column(db.Boolean)
id_unit_measurement_interval_recurrence: int = db.Column(db.Integer)
count_interval_recurrence: int = db.Column(db.Float)
id_stripe_product: str = db.Column(db.String(50))
does_expire_faster_once_unsealed: bool = db.Column(db.Boolean)
id_unit_measurement_interval_expiration_unsealed: int = db.Column(db.Integer)
count_interval_expiration_unsealed: int = db.Column(db.Integer)
active: bool = db.Column(db.Boolean)
guid: str = db.Column(db.String(36))
@classmethod
def from_product_permutation(cls, product_permutation):
row = cls()
row.id_permutation = product_permutation.id_permutation
row.id_product = product_permutation.id_product
row.description = product_permutation.description
row.cost_local = product_permutation.cost_local
row.id_currency_cost = product_permutation.currency_cost.id_currency
row.profit_local_min = product_permutation.profit_local_min
row.latency_manufacture_days = product_permutation.latency_manufacture_days
row.id_unit_measurement_quantity = product_permutation.id_unit_measurement_quantity
row.count_unit_measurement_per_quantity_step = product_permutation.count_unit_measurement_per_quantity_step
row.quantity_min = product_permutation.quantity_min
row.quantity_max = product_permutation.quantity_max
row.quantity_stock = product_permutation.quantity_stock
row.is_subscription = product_permutation.is_subscription
row.id_unit_measurement_interval_recurrence = product_permutation.id_unit_measurement_interval_recurrence
row.count_interval_recurrence = product_permutation.count_interval_recurrence
row.id_stripe_product = product_permutation.id_stripe_product
row.does_expire_faster_once_unsealed = product_permutation.does_expire_faster_once_unsealed
row.id_unit_measurement_interval_expiration_unsealed = product_permutation.id_unit_measurement_interval_expiration_unsealed
row.count_interval_expiration_unsealed = product_permutation.count_interval_expiration_unsealed
row.active = product_permutation.active
return row
def __repr__(self):
return f'''
id_permutation: {self.id_permutation}
id_product: {self.id_product}
description: {self.description}
cost_local: {self.cost_local}
id_currency_cost: {self.id_currency_cost}
profit_local_min: {self.profit_local_min}
latency_manufacture_days: {self.latency_manufacture_days}
id_unit_measurement_quantity: {self.id_unit_measurement_quantity}
{Product_Permutation.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP}: {self.count_unit_measurement_per_quantity_step}
quantity_min: {self.quantity_min}
quantity_max: {self.quantity_max}
quantity_stock: {self.quantity_stock}
is_subscription: {self.is_subscription}
id_unit_measurement_interval_recurrence: {self.id_unit_measurement_interval_recurrence}
count_interval_recurrence: {self.count_interval_recurrence}
id_stripe_product: {self.id_stripe_product}
does_expire_faster_once_unsealed: {self.does_expire_faster_once_unsealed}
id_unit_measurement_interval_expiration_unsealed: {self.id_unit_measurement_interval_expiration_unsealed}
count_interval_expiration_unsealed: {self.count_interval_expiration_unsealed}
active: {self.active}
guid: {self.guid}
'''
"""
def to_json(self):
return {
self.ATTR_ID_PRODUCT_PERMUTATION: int(self.id_permutation),
self.ATTR_ID_PRODUCT: int(self.id_product),
self.FLAG_DESCRIPTION: self.description,
Product_Permutation.FLAG_COST_LOCAL: float(self.cost_local),
Product_Permutation.FLAG_CURRENCY_COST: int(self.id_currency_cost),
Product_Permutation.FLAG_PROFIT_LOCAL_MIN: float(self.profit_local_min),
Product_Permutation.FLAG_LATENCY_MANUFACTURE_DAYS: int(self.latency_manufacture_days),
Product_Permutation.FLAG_UNIT_MEASUREMENT_QUANTITY: int(self.id_unit_measurement_quantity),
Product_Permutation.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP: float(self.count_unit_measurement_per_quantity_step),
self.FLAG_QUANTITY_MIN: float(self.quantity_min),
self.FLAG_QUANTITY_MAX: float(self.quantity_max),
Product_Permutation.FLAG_QUANTITY_STOCK: float(self.quantity_stock),
Product_Permutation.FLAG_IS_SUBSCRIPTION: bool(self.is_subscription),
Product_Permutation.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: int(self.id_unit_measurement_interval_recurrence) if self.id_unit_measurement_interval_recurrence != '' else None,
Product_Permutation.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE: float(self.count_interval_recurrence) if self.count_interval_recurrence != '' else None,
Product_Permutation.FLAG_ID_STRIPE_PRODUCT: self.id_stripe_product,
Product_Permutation.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED: bool(self.does_expire_faster_once_unsealed),
Product_Permutation.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: int(self.id_unit_measurement_interval_expiration_unsealed) if self.id_unit_measurement_interval_expiration_unsealed != '' else None,
Product_Permutation.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED: float(self.count_interval_expiration_unsealed) if self.count_interval_expiration_unsealed != '' else None,
self.FLAG_ACTIVE: bool(self.active),
self.FLAG_GUID: self.guid
}
"""

View File

@@ -20,19 +20,21 @@ from dataclasses import dataclass
from typing import ClassVar
class Product_Price(db.Model, Store_Base):
ATTR_ID_PRODUCT_PRICE: ClassVar[str] = 'id-price'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_PRICE
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_TEXT
FLAG_VALUE_LOCAL_VAT_INCL: ClassVar[str] = 'value-local-vat-incl'
FLAG_VALUE_LOCAL_VAT_EXCL: ClassVar[str] = 'value-local-vat-excl'
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display-order-price'
id_price = db.Column(db.Integer, primary_key=True)
id_permutation = db.Column(db.Integer)
id_product = db.Column(db.Integer)
id_category = db.Column(db.Integer)
"""
id_currency = db.Column(db.Integer)
code_currency = db.Column(db.String(50))
name_currency = db.Column(db.String(255))
symbol_currency = db.Column(db.String(50))
"""
id_region = db.Column(db.Integer)
value_local_VAT_incl = db.Column(db.Float)
value_local_VAT_excl = db.Column(db.Float)
@@ -41,18 +43,23 @@ class Product_Price(db.Model, Store_Base):
def __init__(self):
super().__init__()
Store_Base.__init__(self)
def from_DB_get_many_product_catalogue(query_row):
self.currency = None
self.delivery_region = None
@classmethod
def from_DB_get_many_product_catalogue(cls, query_row):
# _m = 'Product_Price.from_DB_get_many_product_catalogue'
price = Product_Price()
price = cls()
price.id_price = query_row[0]
price.id_permutation = query_row[1]
price.id_product = query_row[2]
price.id_category = query_row[3]
price.currency = Currency.from_DB_get_many_product_price_and_discount_and_delivery_region(query_row)
"""
price.id_currency = query_row[4]
price.code_currency = query_row[5]
price.name_currency = query_row[6]
price.symbol_currency = query_row[7]
"""
price.id_region = query_row[8]
price.value_local_VAT_incl = query_row[9]
price.value_local_VAT_excl = query_row[10]
@@ -65,35 +72,26 @@ class Product_Price(db.Model, Store_Base):
id_permutation: {self.id_permutation}
id_product: {self.id_product}
id_category: {self.id_category}
id_currency: {self.id_currency}
code_currency: {self.code_currency}
name_currency: {self.name_currency}
symbol_currency: {self.symbol_currency}
currency: {self.currency}
id_region: {self.id_region}
value_local (VAT incl): {self.value_local_VAT_incl}
value_local (VAT excl): {self.value_local_VAT_excl}
display_order (UID): {self.display_order}
{self.FLAG_TEXT}: {self.currency.symbol} {self.value_local_VAT_incl}
'''
def to_json(self):
return {
self.ATTR_ID_PRODUCT_PRICE: {self.id_price},
self.ATTR_ID_PRODUCT_PERMUTATION: {self.id_permutation},
self.ATTR_ID_PRODUCT: {self.id_product},
self.ATTR_ID_PRODUCT_CATEGORY: {self.id_category},
Currency.ATTR_ID_CURRENCY: {self.id_currency},
Currency.FLAG_CODE: {self.code_currency},
Currency.FLAG_NAME: {self.name_currency},
Currency.FLAG_SYMBOL: {self.symbol_currency},
Delivery_Region.ATTR_ID_REGION: {self.id_region},
self.FLAG_VALUE_LOCAL_VAT_INCL: {self.value_local_VAT_incl},
self.FLAG_VALUE_LOCAL_VAT_EXCL: {self.value_local_VAT_excl},
self.FLAG_DISPLAY_ORDER: {self.display_order}
}
def to_json_option(self):
return {
'value': self.id_price,
'text': f'{self.symbol_currency} {self.value_local_VAT_incl}'
**self.get_shared_json_attributes(self),
self.ATTR_ID_PRODUCT_PRICE: self.id_price,
self.ATTR_ID_PRODUCT_PERMUTATION: self.id_permutation,
self.ATTR_ID_PRODUCT: self.id_product,
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
self.FLAG_CURRENCY: self.currency.to_json(),
Delivery_Region.ATTR_ID_DELIVERY_REGION: self.id_region,
self.FLAG_VALUE_LOCAL_VAT_INCL: self.value_local_VAT_incl,
self.FLAG_VALUE_LOCAL_VAT_EXCL: self.value_local_VAT_excl,
self.FLAG_DISPLAY_ORDER: self.display_order
}
@classmethod
@@ -103,11 +101,8 @@ class Product_Price(db.Model, Store_Base):
price.id_permutation = json[cls.ATTR_ID_PRODUCT_PERMUTATION]
price.id_product = json[cls.ATTR_ID_PRODUCT]
price.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
price.id_currency = json[Currency.ATTR_ID_CURRENCY]
price.code_currency = json[Currency.FLAG_CODE]
price.name_currency = json[Currency.FLAG_NAME]
price.symbol_currency = json[Currency.FLAG_SYMBOL]
price.id_region = json[Delivery_Region.ATTR_ID_REGION]
price.currency = Currency.from_json(json)
price.id_region = json[Delivery_Region.ATTR_ID_DELIVERY_REGION]
price.value_local_VAT_incl = json[cls.FLAG_VALUE_LOCAL_VAT_INCL]
price.value_local_VAT_excl = json[cls.FLAG_VALUE_LOCAL_VAT_EXCL]
price.display_order = json[cls.FLAG_DISPLAY_ORDER]

View File

@@ -19,124 +19,103 @@ Business object for product variation
# internal
import lib.argument_validation as av
from business_objects.store.store_base import Store_Base
from business_objects.store.product_variation_type import Product_Variation_Type
from extensions import db
# external
from dataclasses import dataclass
from typing import ClassVar
from pydantic import BaseModel
from itertools import filterfalse
from operator import attrgetter
# CLASSES
class Product_Variation(db.Model, Store_Base):
KEY_ACTIVE_VARIATION: ClassVar[str] = 'active_variation'
KEY_ACTIVE_VARIATION_TYPE: ClassVar[str] = 'active_variation_type'
KEY_CODE_VARIATION: ClassVar[str] = 'code_variation'
KEY_CODE_VARIATION_TYPE: ClassVar[str] = 'code_variation_type'
KEY_DISPLAY_ORDER_VARIATION: ClassVar[str] = 'display_order_variation'
KEY_DISPLAY_ORDER_VARIATION_TYPE: ClassVar[str] = 'display_order_variation_type'
KEY_NAME_VARIATION: ClassVar[str] = 'name_variation'
KEY_NAME_VARIATION_TYPE: ClassVar[str] = 'name_variation_type'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_VARIATION
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME
id_variation = db.Column(db.Integer, primary_key=True)
code_variation = db.Column(db.String(50))
name_variation = db.Column(db.String(255))
active_variation = db.Column(db.Boolean)
display_order_variation = db.Column(db.Integer)
id_type = db.Column(db.Integer)
code_variation_type = db.Column(db.String(50))
name_variation_type = db.Column(db.String(255))
name_plural_variation_type = db.Column(db.String(255))
active_variation_type = db.Column(db.Boolean)
display_order_variation_type = db.Column(db.Integer)
id_product = db.Column(db.Integer)
id_permutation = db.Column(db.Integer)
id_category = db.Column(db.Integer)
code = db.Column(db.String(50))
name = db.Column(db.String(255))
display_order = db.Column(db.Integer)
active = db.Column(db.Boolean)
id_permutation = db.Column(db.Integer)
id_product = db.Column(db.Integer)
id_category = db.Column(db.Integer)
def __init__(self):
super().__init__()
Store_Base.__init__(self)
self.variation_type = None
def from_DB_get_many_product_catalogue(query_row):
variation = Product_Variation.from_DB_variation(query_row)
@classmethod
def from_DB_get_many_product_catalogue(cls, query_row):
variation = Product_Variation.from_DB_get_many_product_variation(query_row)
variation.id_product = query_row[11]
variation.id_permutation = query_row[12]
variation.id_category = query_row[13]
variation.variation_type = Product_Variation_Type.from_DB_get_many_product_catalogue(query_row)
return variation
def from_DB_variation(query_row):
_m = 'Product_Variation.from_DB_variation'
variation = Product_Variation()
@classmethod
def from_DB_get_many_product_variation(cls, query_row):
variation = cls()
variation.id_variation = query_row[0]
variation.code_variation = query_row[1]
variation.name_variation = query_row[2]
variation.active_variation = av.input_bool(query_row[3], 'active_variation', _m)
variation.display_order_variation = query_row[4]
variation.id_type = query_row[5]
variation.code_variation_type = query_row[6]
variation.name_variation_type = query_row[7]
variation.name_plural_variation_type = query_row[8]
variation.active_variation_type = av.input_bool(query_row[9], 'active_variation', _m)
variation.display_order_variation_type = query_row[10]
variation.id_type = query_row[1]
variation.code = query_row[2]
variation.name = query_row[3]
variation.display_order = query_row[4]
variation.active = av.input_bool(query_row[5], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_get_many_product_variation')
return variation
@classmethod
def from_json(cls, json):
variation = cls()
variation.id_variation = json[cls.ATTR_ID_VARIATION]
variation.id_variation = json[cls.ATTR_ID_PRODUCT_VARIATION]
variation.code = json[cls.FLAG_CODE]
variation.name = json[cls.FLAG_NAME]
variation.display_order = json[cls.FLAG_DISPLAY_ORDER]
variation.active = json[cls.FLAG_ACTIVE]
variation.id_permutation = json[cls.ATTR_ID_PRODUCT_PERMUTATION]
variation.id_product = json[cls.ATTR_ID_PRODUCT]
variation.id_permutation = json[cls.ATTR_ID_PERMUTATION]
variation.id_category = json[cls.ATTR_ID_CATEGORY]
variation.name_variation_type = json[cls.KEY_NAME_VARIATION_TYPE]
variation.name_variation = json[cls.KEY_NAME_VARIATION]
variation.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
return variation
def __repr__(self):
return f'''
id: {self.id_variation}
id_product: {self.id_product}
{self.__class__.__name__}
id_variation: {self.id_variation}
id_type: {self.id_type}
code: {self.code}
name: {self.name}
display_order: {self.display_order}
active: {self.active}
id_permutation: {self.id_permutation}
id_product: {self.id_product}
id_category: {self.id_category}
code_variation_type: {self.code_variation_type}
name_variation_type: {self.name_variation_type}
code_variation: {self.code_variation}
name_variation: {self.name_variation}
active_variation: {self.active_variation}
active_variation_type: {self.active_variation_type}
display_order_variation: {self.display_order_variation}
display_order_variation_type: {self.display_order_variation_type}
variation_type: {self.variation_type}
'''
def to_json(self):
return {
**self.get_shared_json_attributes(self),
self.ATTR_ID_PRODUCT_VARIATION: self.id_variation,
self.ATTR_ID_PRODUCT_VARIATION_TYPE: self.id_type,
self.FLAG_CODE: self.code,
self.FLAG_NAME: self.name,
self.FLAG_DISPLAY_ORDER: self.display_order,
self.FLAG_ACTIVE: self.active,
self.ATTR_ID_PRODUCT: self.id_product,
self.ATTR_ID_PRODUCT_PERMUTATION: self.id_permutation,
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
self.ATTR_ID_PRODUCT_VARIATION_TYPE: self.id_type,
self.KEY_CODE_VARIATION_TYPE: self.code_variation_type,
self.KEY_CODE_VARIATION: self.code_variation,
self.KEY_DISPLAY_ORDER_VARIATION_TYPE: self.display_order_variation_type,
self.KEY_DISPLAY_ORDER_VARIATION: self.display_order_variation,
self.KEY_NAME_VARIATION_TYPE: self.name_variation_type,
self.KEY_NAME_VARIATION: self.name_variation,
self.KEY_ACTIVE_VARIATION_TYPE: self.active_variation_type,
self.KEY_ACTIVE_VARIATION: self.active_variation,
}
def to_json_option(self):
return {
'value': self.id_variation,
'text': self.name_variation
}
def to_json_variation_type(self):
return {
self.ATTR_ID_PRODUCT_VARIATION_TYPE: self.id_type,
self.KEY_CODE_VARIATION_TYPE: self.code_variation_type,
self.KEY_DISPLAY_ORDER_VARIATION_TYPE: self.display_order_variation_type,
self.KEY_NAME_VARIATION_TYPE: self.name_variation_type,
self.KEY_ACTIVE_VARIATION_TYPE: self.active_variation_type,
'text': self.name
}
@dataclass
class Product_Variation_Filters():
get_all_variation_type: bool
@@ -198,30 +177,35 @@ class Product_Variation_Filters():
get_first_variation = False,
ids_variation = ''
)
class Product_Variation_List(BaseModel):
class Product_Variation_Container(BaseModel):
variation_types: list = []
variations: list = []
def add_product_variation_type(self, variation_type):
av.val_instance(variation_type, 'variation_type', 'Product_Variation_Container.add_product_variation_type', Product_Variation_Type)
self.variations.append(variation_type)
def add_product_variation(self, variation):
av.val_instance(variation, 'variation', 'Product_Variation_List.add_product_variation', Product_Variation)
av.val_instance(variation, 'variation', 'Product_Variation_Container.add_product_variation', Product_Variation)
if variation.variation_type is None:
variation_type = next(filterfalse(lambda x: x.id_type != variation.id_type, self.variation_types), None)
if variation_type is not None:
variation.variation_type = variation_type
self.variations.append(variation)
def __repr__(self):
return f'variations: {self.variations}'
return f'Product_Variation_Container:\nvariations_types: {self.variation_types}\nvariations: {self.variations}'
def to_list_variations(self):
def to_list_variation_options(self):
list_variations = []
for variation in self.variations:
list_variations.append(variation.to_json())
list_variations.append(variation.to_json_option())
print(f'list_variations: {list_variations}')
return list_variations
def to_list_variation_types(self):
def to_list_variation_type_options(self):
list_variation_types = []
list_variation_ids = []
for variation in self.variations:
if variation.id_type not in list_variation_ids:
list_variation_ids.append(variation.id_type)
list_variation_types.append(variation.to_json_variation_type())
for variation_type in self.variation_types:
list_variation_types.append(variation_type.to_json_option())
return list_variation_types

View File

@@ -55,20 +55,42 @@ class Product_Variation_Tree():
is_equal = (sz_me == sz_other)
if is_equal:
for index_type in range(sz_me):
if sz_me[index_type] != sz_other[index_type]:
if my_type_list[index_type] != other_type_list[index_type]:
is_equal = False
break
return is_equal
def from_product_permutation(product_permutation):
@classmethod
def from_product_permutation(cls, product_permutation):
depth_max = len(product_permutation.variations)
node_root = Product_Variation_Tree_Node.from_variation_and_node_parent(product_permutation.variations[0], None)
node = node_root
for depth in range(depth_max - 1):
node = Product_Variation_Tree_Node.from_variation_and_node_parent(product_permutation.variations[depth + 1], node)
return Product_Variation_Tree.from_node_root(node_root)
def from_product_variation(product_variation):
return cls.from_node_root(node_root)
@classmethod
def from_product_variation(cls, product_variation):
node_root = Product_Variation_Tree_Node.from_variation_and_node_parent(product_variation, None)
return Product_Variation_Tree.from_node_root(node_root)
return cls.from_node_root(node_root)
@classmethod
def from_product_variations(cls, product_variations):
node_root = Product_Variation_Tree_Node.from_variation_and_node_parent(product_variations[0], None)
tree = cls.from_node_root(node_root)
if len(product_variations) > 1:
for variation in product_variations[1:]:
tree.add_product_variation(variation)
return tree
@classmethod
def from_json_str(cls, json_str):
variations = []
for json_variation in json_str.split(','):
parts = json_variation.split(':')
if len(parts) != 2: continue
variation = Product_Variation()
variation.id_type = parts[0]
variation.id_variation = parts[1]
variations.append(variation)
return cls.from_product_variations(variations)
"""
def get_name_variations(self):
node = self.node_root
name = node.variation.name_variation_type
@@ -78,6 +100,7 @@ class Product_Variation_Tree():
name += f', {node.variation.name_variation_type}'
at_leaf_node = node.is_leaf()
return name
"""
def get_node_leaf(self):
node = self.node_root
at_leaf_node = node.is_leaf()
@@ -102,8 +125,64 @@ class Product_Variation_Tree():
variations = []
node = self.node_root
at_leaf_node = node.is_leaf()
variations.append(node.variation)
while not at_leaf_node:
variations.append(node.variation)
node = node.nodes_child[0]
at_leaf_node = node.is_leaf()
return variations
variations.append(node.variation)
return variations
def to_preview_str(self):
print(f'Product_Variation_Tree.to_preview_str')
variations = self.get_product_variations()
print(f'variations: {variations}')
preview_str = ''
for variation in variations:
is_first = (preview_str == '')
preview_str += f'{variation.variation_type.name_singular}: {variation.name}'
if is_first:
preview_str += '\n'
print(f'preview_str: {preview_str}')
return preview_str
def to_json(self):
variations = self.get_product_variations()
json_variations = []
for variation in variations:
json_variations.append(variation.to_json())
return json_variations
def to_variation_id_pairs_str(self):
variations = self.get_product_variations()
pairs_str = ''
for variation in variations:
pairs_str += f'{variation.id_type}:{variation.id_variation},'
return pairs_str
"""
class Product_Variation_Container(BaseModel):
variation_types: list = []
variations: list = []
def add_product_variation_type(self, variation_type):
av.val_instance(variation_type, 'variation_type', 'Product_Variation_Container.add_product_variation_type', Product_Variation_Type)
self.variations.append(variation_type)
def add_product_variation(self, variation):
av.val_instance(variation, 'variation', 'Product_Variation_Container.add_product_variation', Product_Variation)
if variation.variation_type is None:
variation_type = next(filterfalse(lambda x: x.id_type != variation.id_type, self.variation_types), None)
if variation_type is not None:
variation.variation_type = variation_type
self.variations.append(variation)
def __repr__(self):
return f'Product_Variation_Container:\nvariations_types: {self.variation_types}\nvariations: {self.variations}'
def to_list_variation_options(self):
list_variations = []
for variation in self.variations:
list_variations.append(variation.to_json_option())
print(f'list_variations: {list_variations}')
return list_variations
def to_list_variation_type_options(self):
list_variation_types = []
for variation_type in self.variation_types:
list_variation_types.append(variation_type.to_json_option())
return list_variation_types
"""

View File

@@ -0,0 +1,103 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Business Objects
Feature: Product Product_Variation Business Object
Description:
Business object for product variation
"""
# IMPORTS
# VARIABLE INSTANTIATION
# CLASSES
# METHODS
# IMPORTS
# internal
import lib.argument_validation as av
from business_objects.store.store_base import Store_Base
from extensions import db
# external
from dataclasses import dataclass
from typing import ClassVar
from pydantic import BaseModel
from itertools import filterfalse
from operator import attrgetter
class Product_Variation_Type(db.Model, Store_Base):
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_VARIATION_TYPE
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME_SINGULAR
id_type = db.Column(db.Integer, primary_key=True)
code = db.Column(db.String(50))
name_singular = db.Column(db.String(255))
name_plural = db.Column(db.String(255))
display_order = db.Column(db.Integer)
active = db.Column(db.Boolean)
def __init__(self):
super().__init__()
@classmethod
def from_DB_get_many_product_catalogue(cls, query_row):
variation_type = cls()
variation_type.id_type = query_row[1]
variation_type.code = query_row[6]
variation_type.name_singular = query_row[7]
variation_type.name_plural = query_row[8]
variation_type.display_order = query_row[9]
variation_type.active = av.input_bool(query_row[10], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_get_many_product_catalogue')
return variation_type
@classmethod
def from_DB_get_many_product_variation(cls, query_row):
variation_type = cls()
variation_type.id_type = query_row[0]
variation_type.code = query_row[1]
variation_type.name_singular = query_row[2]
variation_type.name_plural = query_row[3]
variation_type.display_order = query_row[4]
variation_type.active = av.input_bool(query_row[5], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_get_many_product_variation')
return variation_type
@classmethod
def from_json(cls, json):
variation_type = cls()
variation_type.id_type = json[cls.ATTR_ID_PRODUCT_VARIATION_TYPE]
variation_type.code = json[cls.FLAG_CODE]
variation_type.name_singular = json[cls.FLAG_NAME_SINGULAR]
variation_type.name_plural = json[cls.FLAG_NAME_PLURAL]
variation_type.display_order = json[cls.FLAG_DISPLAY_ORDER]
variation_type.active = json[cls.FLAG_ACTIVE]
return variation_type
def __repr__(self):
return f'''
{self.__class__.__name__}
id_type: {self.id_type}
code: {self.code}
name_singular: {self.name_singular}
name_plural: {self.name_plural}
display_order: {self.display_order}
active: {self.active}
'''
def to_json(self):
return {
**self.get_shared_json_attributes(self),
self.ATTR_ID_PRODUCT_VARIATION_TYPE: self.id_type,
self.FLAG_CODE: self.code,
self.FLAG_NAME_SINGULAR: self.name_singular,
self.FLAG_NAME_PLURAL: self.name_plural,
self.FLAG_DISPLAY_ORDER: self.display_order,
self.FLAG_ACTIVE: self.active,
}
def to_json_option(self):
return {
'value': self.id_type,
'text': self.name_singular
}

View File

@@ -24,6 +24,8 @@ from datetime import datetime
class Stock_Item(db.Model, Store_Base):
ATTR_ID_CURRENCY_COST: ClassVar[str] = f'{Store_Base.ATTR_ID_CURRENCY}-cost'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_CURRENCY
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_NAME
FLAG_DATE_CONSUMED: ClassVar[str] = 'date-consumed'
FLAG_DATE_EXPIRATION: ClassVar[str] = 'date-expiration'
FLAG_DATE_PURCHASED: ClassVar[str] = 'date-purchased'
@@ -175,6 +177,7 @@ class Stock_Item(db.Model, Store_Base):
'''
def to_json(self):
return {
**self.get_shared_json_attributes(self),
self.ATTR_ID_PRODUCT: {self.id_product},
self.ATTR_ID_PRODUCT_CATEGORY: {self.id_category},
self.FLAG_NAME: {self.name},
@@ -183,8 +186,8 @@ class Stock_Item(db.Model, Store_Base):
self.FLAG_CAN_EDIT: {self.can_edit},
self.FLAG_CAN_ADMIN: {self.can_admin},
self.FLAG_HAS_VARIATIONS: {self.has_variations},
self.FLAG_PERMUTATIONS: {self.permutations},
self.FLAG_VARIATION_TREES: {self.variation_trees},
self.FLAG_PRODUCT_PERMUTATION: {self.permutations},
self.FLAG_PRODUCT_VARIATION_TREES: {self.variation_trees},
}
def has_permutations(self):
return len(self.permutations) > 0

View File

@@ -12,6 +12,7 @@ Abstract business object for store objects
# internal
# from helpers.DEPRECATED.helper_abc import Interface_ABC
from business_objects.base import Base
from extensions import db
import lib.argument_validation as av
# external
@@ -55,40 +56,33 @@ class I_Store_Base():
""
"""
class Store_Base():
ATTR_ID_ACCESS_LEVEL: ClassVar[str] = 'id_access_level'
ATTR_ID_CURRENCY: ClassVar[str] = 'id_currency'
class Store_Base(Base):
# ATTR_ID_CURRENCY_COST: ClassVar[str] = 'id_currency_cost'
ATTR_ID_DELIVERY_REGION: ClassVar[str] = 'id_delivery_region'
ATTR_ID_DISCOUNT: ClassVar[str] = 'id_discount'
ATTR_ID_IMAGE: ClassVar[str] = 'id_image'
ATTR_ID_LOCATION_STORAGE: ClassVar[str] = 'id_location_storage'
ATTR_ID_PRODUCT: ClassVar[str] = 'id_product'
ATTR_ID_PRODUCT_CATEGORY: ClassVar[str] = 'id_category'
ATTR_ID_PRODUCT_IMAGE: ClassVar[str] = 'id_image'
ATTR_ID_PRODUCT_PERMUTATION: ClassVar[str] = 'id_permutation'
ATTR_ID_PRODUCT_PRICE: ClassVar[str] = 'id_price'
ATTR_ID_PRODUCT_VARIATION: ClassVar[str] = 'id_variation'
ATTR_ID_PRODUCT_VARIATION_TYPE: ClassVar[str] = 'id_variation_type'
ATTR_ID_PRODUCT_VARIATION_TYPE: ClassVar[str] = 'id_type'
ATTR_ID_STOCK_ITEM: ClassVar[str] = 'id_stock_item'
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = 'access_level_required'
FLAG_ACTIVE: ClassVar[str] = 'active'
FLAG_CAN_ADMIN: ClassVar[str] = 'can_admin'
FLAG_CAN_EDIT: ClassVar[str] = 'can_edit'
FLAG_CAN_VIEW: ClassVar[str] = 'can_view'
FLAG_CODE: ClassVar[str] = 'code'
FLAG_DESCRIPTION: ClassVar[str] = 'description'
FLAG_DISPLAY_ORDER: ClassVar[str] = 'display_order'
FLAG_CURRENCY: ClassVar[str] = 'currency'
FLAG_DELIVERY_OPTION: ClassVar[str] = 'delivery_option'
FLAG_HAS_VARIATIONS: ClassVar[str] = 'has_variations'
FLAG_IS_NOT_EMPTY: ClassVar[str] = 'is_not_empty'
FLAG_KEY_PRIMARY: ClassVar[str] = 'key_primary'
FLAG_NAME: ClassVar[str] = 'name'
FLAG_PERMUTATIONS: ClassVar[str] = 'permutations'
FLAG_PRIORITY: ClassVar[str] = 'priority'
FLAG_ROWS: ClassVar[str] = 'rows'
FLAG_VARIATION_TREES: ClassVar[str] = 'variation_trees'
@classmethod
def output_bool(cls, value):
return av.input_bool(value, f'{cls.__name__} bool attribute', f'{cls.__name__}.output_bool')
@staticmethod
def convert_list_objects_to_list_options(objects):
return [object.to_json_option() for object in objects]
FLAG_IS_OUT_OF_STOCK: ClassVar[str] = 'is_out_of_stock'
FLAG_PRODUCT: ClassVar[str] = 'product'
FLAG_PRODUCT_CATEGORY: ClassVar[str] = 'product_category'
FLAG_PRODUCT_IMAGE: ClassVar[str] = 'product_image'
FLAG_PRODUCT_PERMUTATION: ClassVar[str] = 'product_permutation'
FLAG_PRODUCT_PRICE: ClassVar[str] = 'product_price'
FLAG_PRODUCT_VARIATION: ClassVar[str] = 'product_variation'
FLAG_PRODUCT_VARIATIONS: ClassVar[str] = f'{FLAG_PRODUCT_VARIATION}s'
FLAG_PRODUCT_VARIATION_TYPE: ClassVar[str] = 'product_variation_type'
FLAG_QUANTITY_MIN: ClassVar[str] = 'quantity_min'
FLAG_QUANTITY_MAX: ClassVar[str] = 'quantity_max'
FLAG_TEXT: ClassVar[str] = 'text'
FLAG_VALUE_TEXT: ClassVar[str] = 'value_text'

View File

@@ -0,0 +1,160 @@
"""
Project: PARTS Website
Author: Edward Middleton-Smith
Precision And Research Technology Systems Limited
Technology: Business Objects
Feature: Unit of Measurement Business Object
"""
# internal
from business_objects.base import Base
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
from extensions import db
# from forms.forms import Form_Filters_User
import lib.argument_validation as av
# external
from dataclasses import dataclass
from typing import ClassVar
class Unit_Measurement(SQLAlchemy_ABC, Base):
ATTR_ID_UNIT_MEASUREMENT: ClassVar[str] = 'id_unit_measurement'
FLAG_IS_BASE_UNIT: ClassVar[str] = 'is_base_unit'
FLAG_IS_UNIT_OF_DISTANCE: ClassVar[str] = 'is_unit_of_distance'
FLAG_IS_UNIT_OF_MASS: ClassVar[str] = 'is_unit_of_mass'
FLAG_IS_UNIT_OF_TIME: ClassVar[str] = 'is_unit_of_time'
FLAG_IS_UNIT_OF_VOLUME: ClassVar[str] = 'is_unit_of_volume'
FLAG_NAME_PLURAL: ClassVar[str] = 'name_plural'
FLAG_NAME_SINGULAR: ClassVar[str] = 'name_singular'
FLAG_SYMBOL: ClassVar[str] = 'symbol'
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX: ClassVar[str] = 'symbol_is_suffix_not_prefix'
# KEY_UNIT_MEASUREMENT: ClassVar[str] = 'unit_of_measurement'
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_ID_UNIT_MEASUREMENT
NAME_ATTR_OPTION_TEXT: ClassVar[str] = FLAG_NAME_SINGULAR
id_unit_measurement = db.Column(db.Integer, primary_key=True)
name_singular = db.Column(db.String(255))
name_plural = db.Column(db.String(256))
symbol = db.Column(db.String(50))
symbol_is_suffix_not_prefix = db.Column(db.Boolean)
is_base_unit = db.Column(db.Boolean)
is_unit_of_distance = db.Column(db.Boolean)
is_unit_of_mass = db.Column(db.Boolean)
is_unit_of_time = db.Column(db.Boolean)
is_unit_of_volume = db.Column(db.Boolean)
active = db.Column(db.Boolean)
def from_DB_unit_measurement(query_row):
_m = 'Unit_Measurement.from_DB_unit_measurement'
unit = Unit_Measurement()
unit.id_unit_measurement = query_row[0]
unit.name_singular = query_row[1]
unit.name_plural = query_row[2]
unit.symbol = query_row[3]
unit.symbol_is_suffix_not_prefix = av.input_bool(query_row[4], 'symbol_is_suffix_not_prefix', _m)
unit.is_base_unit = av.input_bool(query_row[5], 'is_base_unit', _m)
unit.is_unit_of_distance = av.input_bool(query_row[6], 'is_unit_of_distance', _m)
unit.is_unit_of_mass = av.input_bool(query_row[7], 'is_unit_of_mass', _m)
unit.is_unit_of_time = av.input_bool(query_row[8], 'is_unit_of_time', _m)
unit.is_unit_of_volume = av.input_bool(query_row[9], 'is_unit_of_volume', _m)
unit.active = av.input_bool(query_row[10], 'active', _m)
return unit
def to_json(self):
return {
**self.get_shared_json_attributes(self),
self.ATTR_ID_UNIT_MEASUREMENT: self.id_unit_measurement,
self.FLAG_NAME_SINGULAR: self.name_singular,
self.FLAG_NAME_PLURAL: self.name_plural,
self.FLAG_SYMBOL: self.symbol,
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX: self.symbol_is_suffix_not_prefix,
self.FLAG_IS_BASE_UNIT: self.is_base_unit,
self.FLAG_IS_UNIT_OF_DISTANCE: self.is_unit_of_distance,
self.FLAG_IS_UNIT_OF_MASS: self.is_unit_of_mass,
self.FLAG_IS_UNIT_OF_TIME: self.is_unit_of_time,
self.FLAG_IS_UNIT_OF_VOLUME: self.is_unit_of_volume,
self.FLAG_ACTIVE: self.active,
}
@classmethod
def from_json(cls, json):
print(f' Unit_Measurement.from_json: {json}')
unit = cls()
unit.id_unit_measurement = json[cls.ATTR_ID_UNIT_MEASUREMENT]
unit.name_singular = json[cls.FLAG_NAME_SINGULAR]
unit.name_plural = json[cls.FLAG_NAME_PLURAL]
unit.symbol = json[cls.FLAG_SYMBOL]
unit.symbol_is_suffix_not_prefix = json[cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX]
unit.is_base_unit = json[cls.FLAG_IS_BASE_UNIT]
unit.is_unit_of_distance = json[cls.FLAG_IS_UNIT_OF_DISTANCE]
unit.is_unit_of_mass = json[cls.FLAG_IS_UNIT_OF_MASS]
unit.is_unit_of_time = json[cls.FLAG_IS_UNIT_OF_TIME]
unit.is_unit_of_volume = json[cls.FLAG_IS_UNIT_OF_VOLUME]
unit.active = json[cls.FLAG_ACTIVE]
return unit
def __repr__(self):
return f'''
id_unit_of_measurement: {self.id_unit_measurement},
name_singular: {self.name_singular},
name_plural: {self.name_plural},
symbol: {self.symbol},
symbol_is_suffix_not_prefix: {self.symbol_is_suffix_not_prefix},
is_base_unit: {self.is_base_unit},
is_unit_of_distance: {self.is_unit_of_distance},
is_unit_of_mass: {self.is_unit_of_mass},
is_unit_of_time: {self.is_unit_of_time},
is_unit_of_volume: {self.is_unit_of_volume},
active: {self.active}
'''
"""
@dataclass
class Filters_Unit_Measurement():
active_only: bool = False
def to_json(self):
return {
**self.get_shared_json_attributes(self),
'a_get_all_user': self.get_all_user,
'a_get_inactive_user': self.get_inactive_user,
'a_get_first_user_only': self.get_first_user_only,
'a_ids_user': self.ids_user,
'a_ids_user_auth0': self.ids_user_auth0,
}
@staticmethod
def from_form(form):
av.val_instance(form, 'form', 'User_Filters.from_form', Form_Filters_User)
get_inactive = av.input_bool(form.active.data, "active", "User_Filters.from_form")
id_user = form.id_user.data
return User_Filters(
get_all_user = (id_user is None),
get_inactive_user = get_inactive,
get_first_user_only = False,
ids_user = id_user,
ids_user_auth0 = '',
)
@staticmethod
def from_user(user):
av.val_instance(user, 'user', 'User_Filters.from_user', User)
return User_Filters(
get_all_user = (user.id_user is None and user.id_user_auth0 is None),
get_inactive_user = False,
get_first_user_only = False,
ids_user = user.id_user,
ids_user_auth0 = user.id_user_auth0,
)
@staticmethod
def get_default(datastore_store):
user = datastore_store.get_login_user()
return User_Filters(
get_all_user = False,
get_inactive_user = False,
get_first_user_only = False,
ids_user = user.id_user,
ids_user_auth0 = '',
)
"""

View File

@@ -8,6 +8,7 @@ Feature: User Business Object
"""
# internal
from business_objects.base import Base
import lib.argument_validation as av
from forms.forms import Form_Filters_User
from extensions import db
@@ -16,8 +17,10 @@ from dataclasses import dataclass
from typing import ClassVar
class User(db.Model):
class User(db.Model, Base):
KEY_USER: ClassVar[str] = 'authorisedUser' # 'user' already used
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_ID_USER
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'email'
id_user = db.Column(db.Integer, primary_key=True)
id_user_auth0 = db.Column(db.String(255))
@@ -200,8 +203,9 @@ class User_Filters():
ids_access_level: str
ids_product: str
def to_json(self):
def to_json(self):
return {
**self.get_shared_json_attributes(self),
'a_ids_user': self.ids_user,
'a_get_inactive_users': self.get_inactive_users,
'a_ids_permission': self.ids_permission,