refactor(SQL): Staging tables and Calc stored procedures used for modular stored procedure archicture for scalability. Implemented for Product Catalogue. \n BREAKING CHANGE: BIT argument a_debug added to all but basic stored procedures for analysis of performance and results.
This commit is contained in:
@@ -23,20 +23,25 @@ from sqlalchemy.ext.declarative import DeclarativeMeta
|
||||
|
||||
|
||||
class Get_Many_Parameters_Base(BaseModel, metaclass=ABCMeta):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
a_id_user: int
|
||||
def __init__(self, a_id_user, **kwargs):
|
||||
super().__init__(a_id_user=a_id_user, **kwargs)
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def get_default(cls):
|
||||
def get_default(cls, id_user):
|
||||
pass
|
||||
"""
|
||||
@abstractmethod
|
||||
def to_json(self):
|
||||
pass
|
||||
"""
|
||||
"""
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
"""
|
||||
"""
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_form(cls, form):
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -26,6 +26,7 @@ from business_objects.store.stock_item import Stock_Item
|
||||
from business_objects.store.product_variation import Product_Variation
|
||||
from business_objects.store.product_variation_tree import Product_Variation_Tree
|
||||
from extensions import db
|
||||
from forms.base import Form_Base
|
||||
from forms.store.product import Form_Filters_Product
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
@@ -688,7 +689,7 @@ class Filters_Product(Get_Many_Parameters_Base):
|
||||
@staticmethod
|
||||
def from_form_filters_product_permutation(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', Filters_Product_Permutation)
|
||||
# av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Base)
|
||||
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")
|
||||
@@ -806,4 +807,7 @@ class Filters_Product(Get_Many_Parameters_Base):
|
||||
get_inactive_image = False,
|
||||
ids_image = '',
|
||||
get_products_quantity_stock_below_min = False
|
||||
)
|
||||
)
|
||||
@classmethod
|
||||
def from_filters_stock_item(cls, filters_stock_item):
|
||||
return cls.from_form_filters_product_permutation(filters_stock_item)
|
||||
@@ -11,7 +11,8 @@ Feature: Stock Item Business Object
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from lib import data_types
|
||||
from forms.forms import Form_Filters_Stock_Item
|
||||
from forms.store.stock_item import Filters_Stock_Item
|
||||
from business_objects.db_base import Get_Many_Parameters_Base
|
||||
from business_objects.store.product_price import Product_Price
|
||||
# from business_objects.discount import Discount
|
||||
from business_objects.store.store_base import Store_Base
|
||||
@@ -23,18 +24,18 @@ from datetime import datetime
|
||||
|
||||
|
||||
class Stock_Item(db.Model, Store_Base):
|
||||
ATTR_ID_CURRENCY_COST: ClassVar[str] = f'{Store_Base.ATTR_ID_CURRENCY}-cost'
|
||||
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'
|
||||
FLAG_DATE_RECEIVED: ClassVar[str] = 'date-received'
|
||||
FLAG_DATE_UNSEALED: ClassVar[str] = 'date-unsealed'
|
||||
FLAG_IS_CONSUMED: ClassVar[str] = 'is-consumed'
|
||||
FLAG_IS_SEALED: ClassVar[str] = 'is-sealed'
|
||||
FLAG_VALUE_LOCAL_VAT_EXCL_COST: ClassVar[str] = f'{Product_Price.FLAG_VALUE_LOCAL_VAT_EXCL}-cost'
|
||||
FLAG_VALUE_LOCAL_VAT_INCL_COST: ClassVar[str] = f'{Product_Price.FLAG_VALUE_LOCAL_VAT_INCL}-cost'
|
||||
FLAG_DATE_CONSUMED: ClassVar[str] = 'date_consumed'
|
||||
FLAG_DATE_EXPIRATION: ClassVar[str] = 'date_expiration'
|
||||
FLAG_DATE_PURCHASED: ClassVar[str] = 'date_purchased'
|
||||
FLAG_DATE_RECEIVED: ClassVar[str] = 'date_received'
|
||||
FLAG_DATE_UNSEALED: ClassVar[str] = 'date_unsealed'
|
||||
FLAG_IS_CONSUMED: ClassVar[str] = 'is_consumed'
|
||||
FLAG_IS_SEALED: ClassVar[str] = 'is_sealed'
|
||||
FLAG_VALUE_LOCAL_VAT_EXCL_COST: ClassVar[str] = f'{Product_Price.FLAG_VALUE_LOCAL_VAT_EXCL}_cost'
|
||||
FLAG_VALUE_LOCAL_VAT_INCL_COST: ClassVar[str] = f'{Product_Price.FLAG_VALUE_LOCAL_VAT_INCL}_cost'
|
||||
|
||||
id_stock = db.Column(db.Integer, primary_key=True)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
@@ -74,19 +75,19 @@ class Stock_Item(db.Model, Store_Base):
|
||||
stock_item.id_category = query_row[3]
|
||||
# stock_item.name_category = query_row[4]
|
||||
# stock_item.name_product = query_row[5]
|
||||
stock_item.date_purchased = query_row[6]
|
||||
stock_item.date_received = query_row[7]
|
||||
stock_item.id_location_storage = query_row[8]
|
||||
stock_item.date_purchased = query_row[4]
|
||||
stock_item.date_received = query_row[5]
|
||||
stock_item.id_location_storage = query_row[6]
|
||||
# stock_item.name_location_storage = query_row[9]
|
||||
stock_item.id_currency_cost = query_row[10]
|
||||
stock_item.cost_local_VAT_incl = query_row[13]
|
||||
stock_item.cost_local_VAT_excl = query_row[14]
|
||||
stock_item.is_sealed = av.input_bool(query_row[15], "is_sealed", _m, v_arg_type=v_arg_type)
|
||||
stock_item.date_unsealed = query_row[16]
|
||||
stock_item.date_expiration = query_row[17]
|
||||
stock_item.is_consumed = av.input_bool(query_row[18], "is_consumed", _m, v_arg_type=v_arg_type)
|
||||
stock_item.date_consumed = query_row[19]
|
||||
stock_item.active = av.input_bool(query_row[20], "active", _m, v_arg_type=v_arg_type)
|
||||
stock_item.id_currency_cost = query_row[7]
|
||||
stock_item.cost_local_VAT_incl = query_row[8]
|
||||
stock_item.cost_local_VAT_excl = query_row[9]
|
||||
stock_item.is_sealed = av.input_bool(query_row[10], "is_sealed", _m, v_arg_type=v_arg_type)
|
||||
stock_item.date_unsealed = query_row[11]
|
||||
stock_item.date_expiration = query_row[12]
|
||||
stock_item.is_consumed = av.input_bool(query_row[13], "is_consumed", _m, v_arg_type=v_arg_type)
|
||||
stock_item.date_consumed = query_row[14]
|
||||
stock_item.active = av.input_bool(query_row[15], "active", _m, v_arg_type=v_arg_type)
|
||||
"""
|
||||
stock_item.can_view = av.input_bool(query_row[24], "can_view", _m, v_arg_type=v_arg_type)
|
||||
stock_item.can_edit = av.input_bool(query_row[25], "can_edit", _m, v_arg_type=v_arg_type)
|
||||
@@ -204,174 +205,66 @@ class Stock_Item(db.Model, Store_Base):
|
||||
for permutation in self.permutations:
|
||||
list_rows.append(permutation.to_row_permutation())
|
||||
return list_rows
|
||||
"""
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_stock_item,
|
||||
'text': self.id_stock_item
|
||||
}
|
||||
"""
|
||||
|
||||
@dataclass
|
||||
class Stock_Item_Filters():
|
||||
# id_user: str
|
||||
get_all_category: bool
|
||||
get_inactive_category: bool
|
||||
get_first_category_only: bool
|
||||
ids_category: str
|
||||
get_all_product: bool
|
||||
get_inactive_product: bool
|
||||
get_first_product_only: bool
|
||||
ids_product: str
|
||||
get_all_permutation: bool
|
||||
get_inactive_permutation: bool
|
||||
get_first_permutation_only: bool
|
||||
ids_permutation: str
|
||||
get_all_stock_item: bool
|
||||
get_inactive_stock_item: bool
|
||||
get_first_stock_item_only: bool
|
||||
ids_stock_item: str
|
||||
get_all_region_storage: bool
|
||||
get_inactive_region_storage: bool
|
||||
get_first_region_storage_only: bool
|
||||
ids_region_storage: str
|
||||
get_all_plant_storage: bool
|
||||
get_inactive_plant_storage: bool
|
||||
get_first_plant_storage_only: bool
|
||||
ids_plant_storage: str
|
||||
get_all_location_storage: bool
|
||||
get_inactive_location_storage: bool
|
||||
get_first_location_storage_only: bool
|
||||
ids_location_storage: str
|
||||
date_received_to: datetime
|
||||
get_sealed_stock_item_only: bool
|
||||
get_unsealed_stock_item_only: bool
|
||||
get_expired_stock_item_only: bool
|
||||
get_nonexpired_stock_item_only: bool
|
||||
get_consumed_stock_item_only: bool
|
||||
get_nonconsumed_stock_item_only: bool
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
'a_id_user': None,
|
||||
'a_get_all_category': self.get_all_category,
|
||||
'a_get_inactive_category': self.get_inactive_category,
|
||||
'a_get_first_category_only': self.get_first_category_only,
|
||||
'a_ids_category': self.ids_category,
|
||||
'a_get_all_product': self.get_all_product,
|
||||
'a_get_inactive_product': self.get_inactive_product,
|
||||
'a_get_first_product_only': self.get_first_product_only,
|
||||
'a_ids_product': self.ids_product,
|
||||
'a_get_all_permutation': self.get_all_permutation,
|
||||
'a_get_inactive_permutation': self.get_inactive_permutation,
|
||||
'a_get_first_permutation_only': self.get_first_permutation_only,
|
||||
'a_ids_permutation': self.ids_permutation,
|
||||
'a_get_all_stock_item': self.get_all_stock_item,
|
||||
'a_get_inactive_stock_item': self.get_inactive_stock_item,
|
||||
'a_get_first_stock_item_only': self.get_first_stock_item_only,
|
||||
'a_ids_stock_item': self.ids_stock_item,
|
||||
'a_get_all_delivery_region_storage': self.get_all_region_storage,
|
||||
'a_get_inactive_delivery_region_storage': self.get_inactive_region_storage,
|
||||
'a_get_first_delivery_region_storage_only': self.get_first_region_storage_only,
|
||||
'a_ids_delivery_region_storage': self.ids_region_storage,
|
||||
'a_get_all_plant_storage': self.get_all_plant_storage,
|
||||
'a_get_inactive_plant_storage': self.get_inactive_plant_storage,
|
||||
'a_get_first_plant_storage_only': self.get_first_plant_storage_only,
|
||||
'a_ids_plant_storage': self.ids_plant_storage,
|
||||
'a_get_all_location_storage': self.get_all_location_storage,
|
||||
'a_get_inactive_location_storage': self.get_inactive_location_storage,
|
||||
'a_get_first_location_storage_only': self.get_first_location_storage_only,
|
||||
'a_ids_location_storage': self.ids_location_storage,
|
||||
'a_date_received_to': self.date_received_to,
|
||||
'a_get_sealed_stock_item_only': self.get_sealed_stock_item_only,
|
||||
'a_get_unsealed_stock_item_only': self.get_unsealed_stock_item_only,
|
||||
'a_get_expired_stock_item_only': self.get_expired_stock_item_only,
|
||||
'a_get_nonexpired_stock_item_only': self.get_nonexpired_stock_item_only,
|
||||
'a_get_consumed_stock_item_only': self.get_consumed_stock_item_only,
|
||||
'a_get_nonconsumed_stock_item_only': self.get_nonconsumed_stock_item_only
|
||||
}
|
||||
class Parameters_Stock_Item(Get_Many_Parameters_Base):
|
||||
a_get_all_product_permutation: bool
|
||||
a_get_inactive_product_permutation: bool
|
||||
a_ids_product_permutation: str
|
||||
a_get_all_stock_item: bool
|
||||
a_get_inactive_stock_item: bool
|
||||
a_ids_stock_item: str
|
||||
a_get_all_region_storage: bool
|
||||
a_get_inactive_region_storage: bool
|
||||
a_ids_region_storage: str
|
||||
a_get_all_plant_storage: bool
|
||||
a_get_inactive_plant_storage: bool
|
||||
a_get_first_plant_storage_only: bool
|
||||
a_ids_plant_storage: str
|
||||
a_get_all_location_storage: bool
|
||||
a_get_inactive_location_storage: bool
|
||||
a_ids_location_storage: str
|
||||
a_date_received_to: datetime
|
||||
a_get_sealed_stock_item_only: bool
|
||||
a_get_unsealed_stock_item_only: bool
|
||||
a_get_expired_stock_item_only: bool
|
||||
a_get_nonexpired_stock_item_only: bool
|
||||
a_get_consumed_stock_item_only: bool
|
||||
a_get_nonconsumed_stock_item_only: bool
|
||||
|
||||
@staticmethod
|
||||
def from_form(form):
|
||||
# if not (form is Form_Filters_Permutations): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Filters_Product.from_form', Form_Filters_Stock_Item)
|
||||
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")
|
||||
print(f'form question: {type(form.is_out_of_stock)}\nbool interpretted: {get_permutations_stock_below_min}\type form: {type(form)}')
|
||||
return Stock_Item_Filters(
|
||||
get_all_category = not has_category_filter,
|
||||
get_inactive_category = False,
|
||||
get_first_category_only = False,
|
||||
ids_category = form.id_category.data,
|
||||
get_all_product = not has_product_filter,
|
||||
get_inactive_product = False,
|
||||
get_first_product_only = False,
|
||||
ids_product = form.id_product.data,
|
||||
get_all_permutation = not get_permutations_stock_below_min,
|
||||
get_inactive_permutation = False,
|
||||
get_first_permutation_only = False,
|
||||
ids_permutation = '',
|
||||
get_all_stock_item = False,
|
||||
get_inactive_stock_item = False,
|
||||
get_first_stock_item_only = False,
|
||||
ids_stock_item = '',
|
||||
get_all_region_storage = False,
|
||||
get_inactive_region_storage = False,
|
||||
get_first_region_storage_only = False,
|
||||
ids_region_storage = '',
|
||||
get_all_plant_storage = False,
|
||||
get_inactive_plant_storage = False,
|
||||
get_first_plant_storage_only = False,
|
||||
ids_plant_storage = '',
|
||||
get_all_location_storage = False,
|
||||
get_inactive_location_storage = False,
|
||||
get_first_location_storage_only = False,
|
||||
ids_location_storage = '',
|
||||
date_received_to = None,
|
||||
get_sealed_stock_item_only = False,
|
||||
get_unsealed_stock_item_only = False,
|
||||
get_expired_stock_item_only = False,
|
||||
get_nonexpired_stock_item_only = False,
|
||||
get_consumed_stock_item_only = False,
|
||||
get_nonconsumed_stock_item_only = False
|
||||
@classmethod
|
||||
def get_default(cls, id_user):
|
||||
return cls(
|
||||
a_id_user = id_user,
|
||||
a_get_all_product_permutation = True,
|
||||
a_get_inactive_product_permutation = False,
|
||||
a_ids_product_permutation = '',
|
||||
a_get_all_stock_item = True,
|
||||
a_get_inactive_stock_item = False,
|
||||
a_ids_stock_item = '',
|
||||
a_get_all_region_storage = True,
|
||||
a_get_inactive_region_storage = False,
|
||||
a_ids_region_storage = '',
|
||||
a_get_all_plant_storage = True,
|
||||
a_get_inactive_plant_storage = False,
|
||||
a_ids_plant_storage = '',
|
||||
a_get_all_location_storage = True,
|
||||
a_get_inactive_location_storage = False,
|
||||
a_ids_location_storage = '',
|
||||
a_date_received_to = None,
|
||||
a_get_sealed_stock_item_only = False,
|
||||
a_get_unsealed_stock_item_only = False,
|
||||
a_get_expired_stock_item_only = False,
|
||||
a_get_nonexpired_stock_item_only = False,
|
||||
a_get_consumed_stock_item_only = False,
|
||||
a_get_nonconsumed_stock_item_only = False
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_default():
|
||||
return Stock_Item_Filters(
|
||||
get_all_category = True,
|
||||
get_inactive_category = False,
|
||||
get_first_category_only = False,
|
||||
ids_category = '',
|
||||
get_all_product = True,
|
||||
get_inactive_product = False,
|
||||
get_first_product_only = False,
|
||||
ids_product = '',
|
||||
get_all_permutation = True,
|
||||
get_inactive_permutation = False,
|
||||
get_first_permutation_only = False,
|
||||
ids_permutation = '',
|
||||
get_all_stock_item = True,
|
||||
get_inactive_stock_item = False,
|
||||
get_first_stock_item_only = False,
|
||||
ids_stock_item = '',
|
||||
get_all_region_storage = True,
|
||||
get_inactive_region_storage = False,
|
||||
get_first_region_storage_only = False,
|
||||
ids_region_storage = '',
|
||||
get_all_plant_storage = True,
|
||||
get_inactive_plant_storage = False,
|
||||
get_first_plant_storage_only = False,
|
||||
ids_plant_storage = '',
|
||||
get_all_location_storage = True,
|
||||
get_inactive_location_storage = False,
|
||||
get_first_location_storage_only = False,
|
||||
ids_location_storage = '',
|
||||
date_received_to = None,
|
||||
get_sealed_stock_item_only = False,
|
||||
get_unsealed_stock_item_only = False,
|
||||
get_expired_stock_item_only = False,
|
||||
get_nonexpired_stock_item_only = False,
|
||||
get_consumed_stock_item_only = False,
|
||||
get_nonconsumed_stock_item_only = False
|
||||
)
|
||||
@classmethod
|
||||
def from_form_stock_item(cls, id_user, form):
|
||||
return cls.get_default(id_user)
|
||||
69
business_objects/store/storage_location.py
Normal file
69
business_objects/store/storage_location.py
Normal file
@@ -0,0 +1,69 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Category Business Object
|
||||
|
||||
Description:
|
||||
Business object for product
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
# external
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Storage_Location(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_STORAGE_LOCATION
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
__tablename__ = 'Shop_Storage_Location_Temp'
|
||||
id_location = db.Column(db.Integer, primary_key=True)
|
||||
id_plant = db.Column(db.Integer)
|
||||
code = db.Column(db.String(50))
|
||||
name = db.Column(db.String(255))
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
@classmethod
|
||||
def from_DB_storage_location(cls, query_row):
|
||||
location = cls()
|
||||
location.id_location = query_row[0]
|
||||
location.id_plant = query_row[1]
|
||||
location.code = query_row[2]
|
||||
location.name = query_row[3]
|
||||
location.active = query_row[4]
|
||||
return location
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_STORAGE_LOCATION}: {self.id_location}
|
||||
{self.ATTR_ID_PLANT}: {self.id_plant}
|
||||
{self.FLAG_CODE}: {self.code}
|
||||
{self.FLAG_NAME}: {self.name}
|
||||
{self.FLAG_ACTIVE}: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_STORAGE_LOCATION: self.id_location,
|
||||
self.ATTR_ID_PLANT: self.id_plant,
|
||||
self.FLAG_CODE: self.code,
|
||||
self.FLAG_NAME: self.name,
|
||||
self.FLAG_ACTIVE: 1 if av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json') else 0
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
print(f'{cls.__name__}.from_json: {json}')
|
||||
location = cls()
|
||||
location.id_location = json[cls.ATTR_ID_STORAGE_LOCATION],
|
||||
location.id_plant = json[cls.ATTR_ID_PLANT],
|
||||
location.code = json[cls.FLAG_CODE],
|
||||
location.name = json[cls.FLAG_NAME],
|
||||
location.active = json[cls.FLAG_ACTIVE]
|
||||
return location
|
||||
@@ -61,6 +61,7 @@ class Store_Base(Base):
|
||||
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_PLANT: ClassVar[str] = 'id_plant'
|
||||
ATTR_ID_PRODUCT: ClassVar[str] = 'id_product'
|
||||
ATTR_ID_PRODUCT_CATEGORY: ClassVar[str] = 'id_category'
|
||||
ATTR_ID_PRODUCT_IMAGE: ClassVar[str] = 'id_image'
|
||||
|
||||
Reference in New Issue
Block a user