Compare commits
1 Commits
revert-2-r
...
demo
| Author | SHA1 | Date | |
|---|---|---|---|
| b3c22d9cf0 |
72
README.md
72
README.md
@@ -1,41 +1,55 @@
|
||||
Precision and Research Technology Systems Limited
|
||||
Website with online store
|
||||
ERP system with e-commerce store
|
||||
|
||||
Powered by flask
|
||||
|
||||
enter virtual environment:
|
||||
# Run
|
||||
1. enter virtual environment:
|
||||
python -m venv VIRTUAL_ENVIRONMENT_NAME
|
||||
|
||||
run module bundler:
|
||||
2. install required packages:
|
||||
pip install -r requirements.txt
|
||||
|
||||
3. run module bundler:
|
||||
npm run build
|
||||
|
||||
host for machine:
|
||||
4. host for machine:
|
||||
python -m flask run
|
||||
|
||||
host for local network:
|
||||
(or 4.) host for local network:
|
||||
python -m flask run --host=0.0.0.0
|
||||
|
||||
|
||||
files dedicated to each page:
|
||||
CSS
|
||||
page
|
||||
HTML
|
||||
page
|
||||
row
|
||||
JavaScript
|
||||
page
|
||||
api
|
||||
router
|
||||
base - navigation buttons
|
||||
MySQL
|
||||
get
|
||||
save
|
||||
table
|
||||
staging table
|
||||
audit table
|
||||
Python
|
||||
business object
|
||||
controller
|
||||
datastore
|
||||
form
|
||||
model
|
||||
# Code review
|
||||
Sample files:
|
||||
CSS:
|
||||
Page styles
|
||||
static/css/pages/store/supplier.css
|
||||
JavaScript:
|
||||
Page object
|
||||
static/js/pages/store/product_categories.js
|
||||
Router
|
||||
static/js/router.js
|
||||
|
||||
HTML:
|
||||
Layout template
|
||||
templates/layouts/layout.html
|
||||
Page template
|
||||
templates/pages/store/_supplier.html
|
||||
|
||||
Python:
|
||||
Business object:
|
||||
business_objects/store/product_price.py
|
||||
Controller:
|
||||
controllers/core.py
|
||||
Datastore:
|
||||
datastores/datastore_store_product_category.py
|
||||
Model:
|
||||
models/model_view_store_product_permutation.py
|
||||
|
||||
SQL:
|
||||
Table:
|
||||
static/MySQL/1403_tbl_Shop_Supplier_Address.sql
|
||||
Trigger
|
||||
static/MySQL/3000_tri_Shop_Access_Level.sql
|
||||
Save procedure
|
||||
static/MySQL/7200_p_shop_save_product_category.sql
|
||||
|
||||
18
app.py
18
app.py
@@ -19,6 +19,15 @@ Initializes the Flask application, sets the configuration based on the environme
|
||||
from config import app_config, Config
|
||||
from controllers.core import routes_core
|
||||
from controllers.legal import routes_legal
|
||||
from controllers.store.store import routes_store
|
||||
from controllers.store.manufacturing_purchase_order import routes_store_manufacturing_purchase_order
|
||||
from controllers.store.product import routes_store_product
|
||||
from controllers.store.product_category import routes_store_product_category
|
||||
from controllers.store.product_permutation import routes_store_product_permutation
|
||||
from controllers.store.product_variation import routes_store_product_variation
|
||||
from controllers.store.stock_item import routes_store_stock_item
|
||||
from controllers.store.supplier import routes_store_supplier
|
||||
from controllers.store.supplier_purchase_order import routes_store_supplier_purchase_order
|
||||
from controllers.user import routes_user
|
||||
from extensions import db, csrf, cors, mail, oauth
|
||||
from helpers.helper_app import Helper_App
|
||||
@@ -107,6 +116,15 @@ with app.app_context():
|
||||
|
||||
app.register_blueprint(routes_core)
|
||||
app.register_blueprint(routes_legal)
|
||||
app.register_blueprint(routes_store)
|
||||
app.register_blueprint(routes_store_manufacturing_purchase_order)
|
||||
app.register_blueprint(routes_store_product)
|
||||
app.register_blueprint(routes_store_product_category)
|
||||
app.register_blueprint(routes_store_product_permutation)
|
||||
app.register_blueprint(routes_store_product_variation)
|
||||
app.register_blueprint(routes_store_stock_item)
|
||||
app.register_blueprint(routes_store_supplier)
|
||||
app.register_blueprint(routes_store_supplier_purchase_order)
|
||||
app.register_blueprint(routes_user)
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
0
business_objects/store/__init__.py
Normal file
0
business_objects/store/__init__.py
Normal file
BIN
business_objects/store/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
business_objects/store/__pycache__/access_level.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/access_level.cpython-312.pyc
Normal file
Binary file not shown.
BIN
business_objects/store/__pycache__/basket.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/basket.cpython-312.pyc
Normal file
Binary file not shown.
BIN
business_objects/store/__pycache__/currency.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/currency.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
business_objects/store/__pycache__/discount.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/discount.cpython-312.pyc
Normal file
Binary file not shown.
BIN
business_objects/store/__pycache__/image.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/image.cpython-312.pyc
Normal file
Binary file not shown.
BIN
business_objects/store/__pycache__/order.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/order.cpython-312.pyc
Normal file
Binary file not shown.
BIN
business_objects/store/__pycache__/product.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/product.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
business_objects/store/__pycache__/product_price.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/product_price.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
business_objects/store/__pycache__/stock_item.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/stock_item.cpython-312.pyc
Normal file
Binary file not shown.
BIN
business_objects/store/__pycache__/store_base.cpython-312.pyc
Normal file
BIN
business_objects/store/__pycache__/store_base.cpython-312.pyc
Normal file
Binary file not shown.
@@ -12,7 +12,7 @@ Business object for product
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.base import Base
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
@@ -20,9 +20,9 @@ from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Access_Level(db.Model, Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_ID_ACCESS_LEVEL
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
|
||||
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))
|
||||
@@ -35,7 +35,7 @@ class Access_Level(db.Model, Base):
|
||||
created_by = db.Column(db.Integer)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Base.__init__(self)
|
||||
Store_Base.__init__(self)
|
||||
@classmethod
|
||||
def from_DB_access_level(cls, query_row):
|
||||
access_level = cls()
|
||||
@@ -83,4 +83,4 @@ class Access_Level(db.Model, Base):
|
||||
access_level.description = json[cls.FLAG_DESCRIPTION],
|
||||
access_level.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
access_level.active = json[cls.FLAG_ACTIVE]
|
||||
return access_level
|
||||
return access_level
|
||||
184
business_objects/store/basket.py
Normal file
184
business_objects/store/basket.py
Normal file
@@ -0,0 +1,184 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Basket Business Object
|
||||
|
||||
Description:
|
||||
Business object for basket
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# VARIABLE INSTANTIATION
|
||||
# CLASSES
|
||||
# METHODS
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
# from lib import data_types
|
||||
from business_objects.store.product import Product #, Parameters_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
|
||||
# from forms import Form_Basket_Add, Form_Basket_Edit # possibly circular
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
# from enum import Enum
|
||||
from flask import jsonify
|
||||
import locale
|
||||
|
||||
|
||||
# VARIABLE INSTANTIATION
|
||||
|
||||
# CLASSES
|
||||
class Basket_Item():
|
||||
product: Product
|
||||
quantity: int
|
||||
delivery_option: Delivery_Option
|
||||
discounts: list
|
||||
# form: Form_Product
|
||||
is_included_VAT: bool
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
self.is_unavailable_in_currency_or_region = False
|
||||
self.is_available = True
|
||||
"""
|
||||
|
||||
def from_product_and_quantity_and_VAT_included(product, quantity, is_included_VAT):
|
||||
# Initialiser - validation
|
||||
_m = 'Basket_Item.from_product_and_quantity'
|
||||
v_arg_type = 'class attribute'
|
||||
av.val_instance(product, 'product', _m, Product, v_arg_type=v_arg_type)
|
||||
av.full_val_float(quantity, 'quantity', _m, product.get_quantity_min(), v_arg_type=v_arg_type)
|
||||
basket_item = Basket_Item()
|
||||
basket_item.product = product
|
||||
basket_item.quantity = quantity
|
||||
basket_item.is_included_VAT = is_included_VAT
|
||||
return basket_item
|
||||
|
||||
def add_product_price_discount(self, discount):
|
||||
av.val_instance(discount, 'discount', 'Basket_Item.add_product_price_discount', Discount, v_arg_type='class attribute')
|
||||
self.discounts.append(discount)
|
||||
|
||||
def set_delivery_option(self, delivery_option):
|
||||
av.val_instance(delivery_option, 'delivery_option', 'Basket_Item.set_delivery_option', Delivery_Option, v_arg_type='class attribute')
|
||||
self.delivery_option = delivery_option
|
||||
|
||||
def update_quantity(self, quantity):
|
||||
_m = 'Basket_Item.update_quantity'
|
||||
v_arg_type = 'class attribute'
|
||||
av.full_val_float(quantity, 'quantity', _m, self.product.get_quantity_min(), v_arg_type=v_arg_type)
|
||||
self.quantity = quantity
|
||||
|
||||
def jsonify(self):
|
||||
return jsonify(self)
|
||||
|
||||
def to_json(self):
|
||||
permutation = self.product.get_permutation_selected()
|
||||
return {
|
||||
'product_id': self.product.id_product,
|
||||
'permutation_id': permutation.id_permutation,
|
||||
'price': permutation.output_price(self.is_included_VAT),
|
||||
'quantity': self.quantity
|
||||
}
|
||||
|
||||
def get_subtotal(self):
|
||||
permutation = self.product.get_permutation_selected()
|
||||
return round(self.product.get_price_local(self.is_included_VAT) * self.quantity, 2) if permutation.is_available else 0
|
||||
|
||||
def output_currency(self):
|
||||
return self.product.output_currency()
|
||||
|
||||
def output_subtotal(self):
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
subtotal = self.get_subtotal()
|
||||
permutation = self.product.get_permutation_selected()
|
||||
return 'Not available in this currency or region' if permutation.is_unavailable_in_currency_or_region else 'Not available' if not permutation.is_available else f'{self.product.output_currency()} {locale.format_string("%d", subtotal, grouping=True)}'
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
product: {self.product}
|
||||
quantity: {self.quantity}
|
||||
subtotal: {self.get_subtotal()}
|
||||
'''
|
||||
|
||||
class Basket(Store_Base):
|
||||
KEY_BASKET: str = 'basket'
|
||||
KEY_ID_CURRENCY: str = 'id_currency'
|
||||
KEY_ID_REGION_DELIVERY: str = 'id_region_delivery'
|
||||
KEY_IS_INCLUDED_VAT: str = 'is_included_VAT'
|
||||
KEY_ITEMS: str = 'items'
|
||||
items: list
|
||||
is_included_VAT: bool
|
||||
id_region_delivery: int
|
||||
id_currency: int
|
||||
|
||||
def __init__(self, is_included_VAT, id_currency, id_region_delivery):
|
||||
self.items = []
|
||||
self.is_included_VAT = is_included_VAT
|
||||
self.id_currency = id_currency
|
||||
self.id_region_delivery = id_region_delivery
|
||||
def add_item(self, item):
|
||||
av.val_instance(item, 'item', 'Basket.add_item', Basket_Item)
|
||||
self.items.append(item)
|
||||
def to_csv(self):
|
||||
ids_permutation = ''
|
||||
quantities_permutation = ''
|
||||
for b_i in range(len(self.items)):
|
||||
basket_item = self.items[b_i]
|
||||
product = basket_item.product
|
||||
if b_i > 0:
|
||||
ids_permutation += ','
|
||||
quantities_permutation += ','
|
||||
ids_permutation += str(product.get_id_permutation())
|
||||
quantities_permutation += str(basket_item.quantity)
|
||||
Helper_App.console_log(f'ids_permutation_basket = {ids_permutation}')
|
||||
Helper_App.console_log(f'quantities_permutation_basket = {quantities_permutation}')
|
||||
return ids_permutation, quantities_permutation
|
||||
def to_json_list(self):
|
||||
json_list = []
|
||||
for item in self.items:
|
||||
json_list.append(item.to_json())
|
||||
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,
|
||||
Basket.KEY_ID_REGION_DELIVERY: self.id_region_delivery
|
||||
}
|
||||
def output_total(self):
|
||||
sum = 0
|
||||
for b_i in self.items:
|
||||
sum += b_i.get_subtotal()
|
||||
symbol = self.items[0].output_currency() if len(self.items) > 0 else ''
|
||||
|
||||
return f'{symbol} {locale.format_string("%d", sum, grouping=True)}'
|
||||
def len(self):
|
||||
return len(self.items)
|
||||
"""
|
||||
def get_key_product_index_from_ids_product_permutation(id_product, id_permutation):
|
||||
return f'{id_product},{"" if id_permutation is None else id_permutation}'
|
||||
"""
|
||||
def __repr__(self):
|
||||
repr = f'Basket:'
|
||||
for basket_item in self.items:
|
||||
Helper_App.console_log(f'{basket_item}')
|
||||
repr = f'{repr}\n{basket_item}'
|
||||
return repr
|
||||
|
||||
def get_ids_permutation_unavailable(self):
|
||||
ids_permutation = []
|
||||
for item in self.items:
|
||||
permutation = item.product.get_permutation_selected()
|
||||
if not permutation.is_available:
|
||||
ids_permutation.append(permutation.id_permutation)
|
||||
return ids_permutation
|
||||
98
business_objects/store/delivery_option.py
Normal file
98
business_objects/store/delivery_option.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Delivery Option Business Object
|
||||
|
||||
Description:
|
||||
Business object for delivery option
|
||||
"""
|
||||
|
||||
# internal
|
||||
from extensions import db
|
||||
|
||||
|
||||
# CLASSES
|
||||
"""
|
||||
class Delivery_Option():
|
||||
name: str
|
||||
delay_min: int # days
|
||||
delay_max: int
|
||||
quantity_min: float
|
||||
quantity_max: float
|
||||
regions: list # [Enum_Region]
|
||||
cost: float
|
||||
|
||||
def __new__(cls, name, delay_min, delay_max, quantity_min, quantity_max, regions, cost):
|
||||
_m = 'Delivery_Option.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
av.val_str(name, 'name', _m, v_arg_type = v_arg_type)
|
||||
av.val_int(delay_min, 'delay_min', _m, 0, v_arg_type = v_arg_type)
|
||||
av.val_int(delay_max, 'delay_max', _m, 0, v_arg_type = v_arg_type)
|
||||
av.val_float(quantity_min, 'quantity_min', _m, 0, v_arg_type = v_arg_type)
|
||||
av.val_float(quantity_max, 'quantity_max', _m, 0, v_arg_type = v_arg_type)
|
||||
av.val_list_instances(regions, 'regions', _m, Enum_Region, v_arg_type = v_arg_type)
|
||||
av.val_float(cost, 'cost', _m, 0, v_arg_type = v_arg_type)
|
||||
return super(Delivery_Option, cls).__new__(cls)
|
||||
|
||||
def __init__(self, name, delay_min, delay_max, quantity_min, quantity_max, regions, cost):
|
||||
self.name = name
|
||||
self.delay_min = delay_min
|
||||
self.delay_max = delay_max
|
||||
self.quantity_min = quantity_min
|
||||
self.quantity_max = quantity_max
|
||||
self.regions = regions
|
||||
self.cost = cost
|
||||
"""
|
||||
class Delivery_Option(db.Model):
|
||||
id_option = db.Column(db.Integer, primary_key=True)
|
||||
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(100))
|
||||
latency_min = db.Column(db.Integer)
|
||||
latency_max = db.Column(db.Integer)
|
||||
quantity_min = db.Column(db.Integer)
|
||||
quantity_max = db.Column(db.Integer)
|
||||
codes_region = db.Column(db.String(4000))
|
||||
names_region = db.Column(db.String(4000))
|
||||
price_GBP = db.Column(db.Float)
|
||||
display_order = db.Column(db.Integer)
|
||||
def __init__(self):
|
||||
self.delivery_regions = []
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
option = Delivery_Option()
|
||||
option.id_option = query_row[0]
|
||||
option.id_product = query_row[1]
|
||||
option.id_permutation = query_row[2]
|
||||
option.id_category = query_row[3]
|
||||
option.code = query_row[4]
|
||||
option.name = query_row[5]
|
||||
option.latency_min = query_row[6]
|
||||
option.latency_max = query_row[7]
|
||||
option.quantity_min = query_row[8]
|
||||
option.quantity_max = query_row[9]
|
||||
option.codes_region = query_row[10]
|
||||
option.names_region = query_row[11]
|
||||
option.price_GBP = query_row[12]
|
||||
option.display_order = query_row[13]
|
||||
return option
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_option}
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
name: {self.name}
|
||||
code: {self.code}
|
||||
latency_min: {self.latency_min}
|
||||
latency_max: {self.latency_max}
|
||||
quantity_min: {self.quantity_min}
|
||||
quantity_max: {self.quantity_max}
|
||||
codes_region: {self.codes_region}
|
||||
names_region: {self.names_region}
|
||||
price_GBP: {self.price_GBP}
|
||||
display_order: {self.display_order}
|
||||
'''
|
||||
75
business_objects/store/discount.py
Normal file
75
business_objects/store/discount.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Discount Business Object
|
||||
|
||||
Description:
|
||||
Business object for discount
|
||||
"""
|
||||
|
||||
# internal
|
||||
from extensions import db
|
||||
|
||||
|
||||
# CLASSES
|
||||
class Discount(db.Model):
|
||||
id_discount = db.Column(db.Integer, primary_key=True)
|
||||
id_category = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
code = db.Column(db.String(50))
|
||||
name = db.Column(db.String(200))
|
||||
multiplier = db.Column(db.Float)
|
||||
subtractor = db.Column(db.Float)
|
||||
apply_multiplier_first = db.Column(db.Boolean)
|
||||
quantity_min = db.Column(db.Integer)
|
||||
quantity_max = db.Column(db.Integer)
|
||||
date_start = db.Column(db.DateTime)
|
||||
date_end = db.Column(db.DateTime)
|
||||
codes_region = db.Column(db.String(4000))
|
||||
names_region = db.Column(db.String(4000))
|
||||
codes_currency = db.Column(db.String(4000))
|
||||
names_currency = db.Column(db.String(4000))
|
||||
display_order = db.Column(db.Integer)
|
||||
|
||||
def __init__(self):
|
||||
self.delivery_regions = []
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
discount = Discount()
|
||||
discount.id_discount = query_row[0]
|
||||
discount.id_category = query_row[1]
|
||||
discount.id_product = query_row[2]
|
||||
discount.id_permutation = query_row[3]
|
||||
discount.code = query_row[4]
|
||||
discount.name = query_row[5]
|
||||
discount.multiplier = query_row[6]
|
||||
discount.subtractor = query_row[7]
|
||||
discount.apply_multiplier_first = query_row[8]
|
||||
discount.quantity_min = query_row[9]
|
||||
discount.quantity_max = query_row[10]
|
||||
discount.date_start = query_row[11]
|
||||
discount.date_end = query_row[12]
|
||||
discount.codes_region = query_row[13]
|
||||
discount.names_region = query_row[14]
|
||||
discount.codes_currency = query_row[15]
|
||||
discount.names_currency = query_row[16]
|
||||
discount.display_order = query_row[17]
|
||||
return discount
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_discount}
|
||||
id_category: {self.id_category}
|
||||
id_product: {self.id_product}
|
||||
name: {self.name}
|
||||
code: {self.code}
|
||||
multiplier: {self.multiplier}
|
||||
quantity_min: {self.quantity_min}
|
||||
quantity_max: {self.quantity_max}
|
||||
date_start: {self.date_start}
|
||||
date_end: {self.date_end}
|
||||
display_order: {self.display_order}
|
||||
'''
|
||||
|
||||
131
business_objects/store/image.py
Normal file
131
business_objects/store/image.py
Normal file
@@ -0,0 +1,131 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Image Business Object
|
||||
|
||||
Description:
|
||||
Business object for product image
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from enum import Enum
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Resolution_Level_Enum(Enum):
|
||||
THUMBNAIL = 0
|
||||
LOW = 1
|
||||
HIGH = 2
|
||||
FULL = 3
|
||||
|
||||
def text(self):
|
||||
return Resolution_Level_Enum.Resolution_Level_Enum_Text(self)
|
||||
|
||||
def Resolution_Level_Enum_Text(category):
|
||||
av.val_instance(category, 'category', 'Resolution_Level_Enum_Text', Resolution_Level_Enum)
|
||||
if category == Resolution_Level_Enum.THUMBNAIL:
|
||||
return 'Thumbnail'
|
||||
elif category == Resolution_Level_Enum.LOW:
|
||||
return 'Low resolution'
|
||||
elif category == Resolution_Level_Enum.HIGH:
|
||||
return 'High resolution'
|
||||
elif category == Resolution_Level_Enum.FULL:
|
||||
return 'Full resolution'
|
||||
else:
|
||||
return 'Unknown'
|
||||
|
||||
def get_member_by_text(text):
|
||||
for member in Resolution_Level_Enum.__members__.values():
|
||||
if member.name == text:
|
||||
return member
|
||||
return Resolution_Level_Enum.HIGH
|
||||
|
||||
|
||||
class Image(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'url'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'id_image'
|
||||
id_image = db.Column(db.Integer, primary_key=True)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
url = db.Column(db.String(255))
|
||||
active = db.Column(db.Boolean)
|
||||
display_order = db.Column(db.Integer)
|
||||
"""
|
||||
def __new__(cls, id, id_product, id_category, url, display_order):
|
||||
_m = 'Image.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
av.val_int(id, 'id', _m, 0, v_arg_type=v_arg_type)
|
||||
av.val_int(id_product, 'id_product', _m, 0, v_arg_type=v_arg_type)
|
||||
av.val_int(id_category, 'id_category', _m, 0, v_arg_type=v_arg_type)
|
||||
av.val_str(url, 'url', _m, max_len=254, v_arg_type=v_arg_type)
|
||||
av.val_int(display_order, 'display_order', _m, v_arg_type=v_arg_type)
|
||||
return super(Image, cls).__new__(cls)
|
||||
|
||||
def __init__(self, id, id_product, id_category, url, display_order):
|
||||
self.id_image = id
|
||||
self.id_product = id_product
|
||||
self.id_category = id_category
|
||||
self.url = url
|
||||
self.display_order = display_order
|
||||
super().__init__()
|
||||
"""
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
_m = 'Image.from_DB_get_many_product_catalogue'
|
||||
# Helper_App.console_log(f'image: {query_row}')
|
||||
image = Image()
|
||||
image.id_image = query_row[0]
|
||||
image.id_product = query_row[1]
|
||||
image.id_permutation = query_row[2]
|
||||
image.id_category = query_row[3]
|
||||
image.url = query_row[4]
|
||||
image.active = query_row[5]
|
||||
image.display_order = query_row[6]
|
||||
return image
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_image}
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
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():
|
||||
product_id: int
|
||||
get_thumbnail: bool
|
||||
get_remaining_LQ: bool
|
||||
|
||||
def __new__(cls, product_id, get_thumbnail, get_remaining_LQ):
|
||||
# Initialiser - validation
|
||||
_m = 'Parameters_Product.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
av.val_int(product_id, 'product_id', _m, v_arg_type=v_arg_type)
|
||||
av.val_bool(get_thumbnail, 'get_thumbnail', _m, v_arg_type=v_arg_type)
|
||||
av.val_bool(get_remaining_LQ, 'get_remaining_LQ', _m, v_arg_type=v_arg_type)
|
||||
return super(Product, cls).__new__(cls)
|
||||
|
||||
def __init__(self, product_id, get_thumbnail, get_remaining_LQ):
|
||||
# Constructor
|
||||
self.product_id = product_id
|
||||
self.get_thumbnail = get_thumbnail
|
||||
self.get_remaining_LQ = get_remaining_LQ
|
||||
|
||||
354
business_objects/store/manufacturing_purchase_order.py
Normal file
354
business_objects/store/manufacturing_purchase_order.py
Normal file
@@ -0,0 +1,354 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Manufacturing_Purchase_Order Business Object
|
||||
|
||||
Description:
|
||||
Business object for manufacturing_purchase_order
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.currency import Currency
|
||||
from business_objects.db_base import Get_Many_Parameters_Base
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar, Optional
|
||||
from datetime import datetime
|
||||
|
||||
class Manufacturing_Purchase_Order(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_MANUFACTURING_PURCHASE_ORDER
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
# __tablename__ = 'Shop_Manufacturing_Purchase_Order_Temp'
|
||||
id_order = db.Column(db.Integer, primary_key=True)
|
||||
id_currency = db.Column(db.Integer)
|
||||
cost_total_local_VAT_excl = db.Column(db.Float)
|
||||
cost_total_local_VAT_incl = db.Column(db.Float)
|
||||
price_total_local_VAT_excl = db.Column(db.Float)
|
||||
price_total_local_VAT_incl = db.Column(db.Float)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
created_by = db.Column(db.Integer)
|
||||
name = db.Column(db.String(255))
|
||||
# items: list = None
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.items = []
|
||||
self.currency = None
|
||||
@classmethod
|
||||
def from_DB_manufacturing_purchase_order(cls, query_row):
|
||||
manufacturing_purchase_order = cls()
|
||||
manufacturing_purchase_order.id_order = query_row[0]
|
||||
manufacturing_purchase_order.id_currency = query_row[1]
|
||||
manufacturing_purchase_order.currency = Currency.from_DB_manufacturing_purchase_order(query_row)
|
||||
manufacturing_purchase_order.cost_total_local_VAT_excl = query_row[4]
|
||||
manufacturing_purchase_order.cost_total_local_VAT_incl = query_row[5]
|
||||
manufacturing_purchase_order.price_total_local_VAT_excl = query_row[6]
|
||||
manufacturing_purchase_order.price_total_local_VAT_incl = query_row[7]
|
||||
manufacturing_purchase_order.active = av.input_bool(query_row[8], 'active', f'{cls.__name__}.from_DB_manufacturing_purchase_order')
|
||||
manufacturing_purchase_order.created_on = query_row[9]
|
||||
manufacturing_purchase_order.name = query_row[10]
|
||||
return manufacturing_purchase_order
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_MANUFACTURING_PURCHASE_ORDER}: {self.id_order},
|
||||
{self.ATTR_ID_CURRENCY}: {self.id_currency},
|
||||
{self.FLAG_COST_TOTAL_LOCAL_VAT_EXCL}: {self.cost_total_local_VAT_excl},
|
||||
{self.FLAG_COST_TOTAL_LOCAL_VAT_INCL}: {self.cost_total_local_VAT_incl},
|
||||
{self.FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL}: {self.price_total_local_VAT_excl},
|
||||
{self.FLAG_PRICE_TOTAL_LOCAL_VAT_INCL}: {self.price_total_local_VAT_incl},
|
||||
{self.FLAG_ACTIVE}: {self.active},
|
||||
{self.FLAG_CREATED_ON}: {self.created_on},
|
||||
{self.FLAG_NAME}: {self.name}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_MANUFACTURING_PURCHASE_ORDER: self.id_order,
|
||||
self.ATTR_ID_CURRENCY: self.id_currency,
|
||||
self.FLAG_COST_TOTAL_LOCAL_VAT_EXCL: self.cost_total_local_VAT_excl,
|
||||
self.FLAG_COST_TOTAL_LOCAL_VAT_INCL: self.cost_total_local_VAT_incl,
|
||||
self.FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL: self.price_total_local_VAT_excl,
|
||||
self.FLAG_PRICE_TOTAL_LOCAL_VAT_INCL: self.price_total_local_VAT_incl,
|
||||
self.FLAG_ORDER_ITEMS: [item.to_json() for item in self.items],
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
self.FLAG_CREATED_ON: self.created_on,
|
||||
self.FLAG_NAME: self.name,
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_order,
|
||||
'text': self.name,
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
||||
manufacturing_purchase_order = cls()
|
||||
manufacturing_purchase_order.id_order = json[cls.ATTR_ID_MANUFACTURING_PURCHASE_ORDER]
|
||||
manufacturing_purchase_order.id_currency = json[cls.ATTR_ID_CURRENCY]
|
||||
manufacturing_purchase_order.cost_total_local_VAT_excl = json.get(cls.FLAG_COST_TOTAL_LOCAL_VAT_EXCL, None)
|
||||
manufacturing_purchase_order.cost_total_local_VAT_incl = json.get(cls.FLAG_COST_TOTAL_LOCAL_VAT_INCL, None)
|
||||
manufacturing_purchase_order.price_total_local_VAT_excl = json.get(cls.FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL, None)
|
||||
manufacturing_purchase_order.price_total_local_VAT_incl = json.get(cls.FLAG_PRICE_TOTAL_LOCAL_VAT_INCL, None)
|
||||
manufacturing_purchase_order.items = [Manufacturing_Purchase_Order_Product_Link.from_json(item) for item in json[cls.FLAG_ORDER_ITEMS]]
|
||||
manufacturing_purchase_order.active = json[cls.FLAG_ACTIVE]
|
||||
manufacturing_purchase_order.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||
manufacturing_purchase_order.name = json.get(cls.FLAG_NAME, None)
|
||||
return manufacturing_purchase_order
|
||||
def get_items_preview_str(self):
|
||||
preview = ''
|
||||
if self.items is not None:
|
||||
for item in self.items:
|
||||
if preview != '':
|
||||
preview += '\n'
|
||||
preview += f'{item.name_permutation}{f" -(x{item.quantity_used})" if item.quantity_used > 0 else ""}{f" +(x{item.quantity_produced})" if item.quantity_produced > 0 else ""}'
|
||||
return preview
|
||||
|
||||
class Manufacturing_Purchase_Order_Product_Link(db.Model, Store_Base):
|
||||
FLAG_QUANTITY_PRODUCED: ClassVar[str] = 'quantity_produced'
|
||||
FLAG_QUANTITY_USED: ClassVar[str] = 'quantity_used'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_MANUFACTURING_PURCHASE_ORDER_PRODUCT_LINK
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
# __tablename__ = 'Shop_Manufacturing_Purchase_Order_Temp'
|
||||
id_link = db.Column(db.Integer, primary_key=True)
|
||||
id_order = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
id_unit_quantity = db.Column(db.Integer)
|
||||
name_permutation = db.Column(db.String(255))
|
||||
csv_id_pairs_variation = db.Column(db.String)
|
||||
quantity_used = db.Column(db.Float)
|
||||
quantity_produced = db.Column(db.Float)
|
||||
id_unit_latency_manufacture = db.Column(db.Integer)
|
||||
latency_manufacture = db.Column(db.Integer)
|
||||
display_order = db.Column(db.Integer)
|
||||
cost_unit_local_VAT_excl = db.Column(db.Float)
|
||||
cost_unit_local_VAT_incl = db.Column(db.Float)
|
||||
price_unit_local_VAT_excl = db.Column(db.Float)
|
||||
price_unit_local_VAT_incl = db.Column(db.Float)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
created_by = db.Column(db.Integer)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
@classmethod
|
||||
def from_DB_manufacturing_purchase_order(cls, query_row):
|
||||
link = cls()
|
||||
link.id_link = query_row[0]
|
||||
link.id_order = query_row[1]
|
||||
link.id_category = query_row[2]
|
||||
link.id_product = query_row[3]
|
||||
link.id_permutation = query_row[4]
|
||||
link.name_permutation = query_row[5]
|
||||
link.csv_id_pairs_variation = query_row[6]
|
||||
link.id_unit_quantity = query_row[7]
|
||||
link.quantity_used = query_row[8]
|
||||
link.quantity_produced = query_row[9]
|
||||
link.id_unit_latency_manufacture = query_row[10]
|
||||
link.latency_manufacture = query_row[11]
|
||||
link.display_order = query_row[12]
|
||||
link.cost_unit_local_VAT_excl = query_row[13]
|
||||
link.cost_unit_local_VAT_incl = query_row[14]
|
||||
link.price_unit_local_VAT_excl = query_row[15]
|
||||
link.price_unit_local_VAT_incl = query_row[16]
|
||||
link.active = query_row[17]
|
||||
return link
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_MANUFACTURING_PURCHASE_ORDER_PRODUCT_LINK}: {self.id_link},
|
||||
{self.ATTR_ID_MANUFACTURING_PURCHASE_ORDER}: {self.id_order},
|
||||
{self.ATTR_ID_PRODUCT_CATEGORY}: {self.id_category},
|
||||
{self.ATTR_ID_PRODUCT}: {self.id_product},
|
||||
{self.ATTR_ID_PRODUCT_PERMUTATION}: {self.id_permutation},
|
||||
{self.FLAG_NAME}: {self.name_permutation},
|
||||
{self.FLAG_PRODUCT_VARIATIONS}: {self.csv_id_pairs_variation},
|
||||
{self.ATTR_ID_UNIT_MEASUREMENT_QUANTITY}: {self.id_unit_quantity},
|
||||
{self.FLAG_QUANTITY_USED}: {self.quantity_used},
|
||||
{self.FLAG_QUANTITY_PRODUCED}: {self.quantity_produced},
|
||||
{self.ATTR_ID_UNIT_MEASUREMENT_LATENCY_MANUFACTURE}: {self.id_unit_latency_manufacture},
|
||||
{self.FLAG_LATENCY_MANUFACTURE}: {self.latency_manufacture},
|
||||
{self.FLAG_DISPLAY_ORDER}: {self.display_order},
|
||||
{self.FLAG_COST_UNIT_LOCAL_VAT_EXCL}: {self.cost_unit_local_VAT_excl},
|
||||
{self.FLAG_COST_UNIT_LOCAL_VAT_INCL}: {self.cost_unit_local_VAT_incl},
|
||||
{self.FLAG_PRICE_UNIT_LOCAL_VAT_EXCL}: {self.price_unit_local_VAT_excl},
|
||||
{self.FLAG_PRICE_UNIT_LOCAL_VAT_INCL}: {self.price_unit_local_VAT_incl},
|
||||
{self.FLAG_ACTIVE}: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_MANUFACTURING_PURCHASE_ORDER_PRODUCT_LINK: self.id_link,
|
||||
self.ATTR_ID_MANUFACTURING_PURCHASE_ORDER: self.id_order,
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
|
||||
self.ATTR_ID_PRODUCT: self.id_product,
|
||||
self.ATTR_ID_PRODUCT_PERMUTATION: self.id_permutation,
|
||||
self.FLAG_NAME: self.name_permutation,
|
||||
self.FLAG_PRODUCT_VARIATIONS: self.csv_id_pairs_variation,
|
||||
self.ATTR_ID_UNIT_MEASUREMENT_QUANTITY: self.id_unit_quantity,
|
||||
self.FLAG_QUANTITY_USED: self.quantity_used,
|
||||
self.FLAG_QUANTITY_PRODUCED: self.quantity_produced,
|
||||
self.ATTR_ID_UNIT_MEASUREMENT_LATENCY_MANUFACTURE: self.id_unit_latency_manufacture,
|
||||
self.FLAG_LATENCY_MANUFACTURE: self.latency_manufacture,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_COST_UNIT_LOCAL_VAT_EXCL: self.cost_unit_local_VAT_excl,
|
||||
self.FLAG_COST_UNIT_LOCAL_VAT_INCL: self.cost_unit_local_VAT_incl,
|
||||
self.FLAG_PRICE_UNIT_LOCAL_VAT_EXCL: self.price_unit_local_VAT_excl,
|
||||
self.FLAG_PRICE_UNIT_LOCAL_VAT_INCL: self.price_unit_local_VAT_incl,
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_order,
|
||||
'text': self.name_permutation,
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
||||
link = cls()
|
||||
link.id_link = json[cls.ATTR_ID_MANUFACTURING_PURCHASE_ORDER_PRODUCT_LINK]
|
||||
link.id_order = json[cls.ATTR_ID_MANUFACTURING_PURCHASE_ORDER]
|
||||
link.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
link.id_product = json[cls.ATTR_ID_PRODUCT]
|
||||
link.id_permutation = json.get(cls.ATTR_ID_PRODUCT_PERMUTATION, None)
|
||||
link.name_permutation = json.get(cls.FLAG_NAME, None)
|
||||
link.csv_id_pairs_variation = json[cls.FLAG_PRODUCT_VARIATIONS]
|
||||
link.id_unit_quantity = json[cls.ATTR_ID_UNIT_MEASUREMENT_QUANTITY]
|
||||
link.quantity_used = json[cls.FLAG_QUANTITY_USED]
|
||||
link.quantity_produced = json[cls.FLAG_QUANTITY_PRODUCED]
|
||||
link.id_unit_latency_manufacture = json[cls.ATTR_ID_UNIT_MEASUREMENT_LATENCY_MANUFACTURE]
|
||||
link.latency_manufacture = json[cls.FLAG_LATENCY_MANUFACTURE]
|
||||
link.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
link.cost_unit_local_VAT_excl = json.get(cls.FLAG_COST_UNIT_LOCAL_VAT_EXCL, None)
|
||||
link.cost_unit_local_VAT_incl = json.get(cls.FLAG_COST_UNIT_LOCAL_VAT_INCL, None)
|
||||
link.active = json[cls.FLAG_ACTIVE]
|
||||
return link
|
||||
|
||||
class Parameters_Manufacturing_Purchase_Order(Get_Many_Parameters_Base):
|
||||
a_get_all_order: bool
|
||||
a_get_inactive_order: bool
|
||||
a_ids_order: str
|
||||
a_ids_permutation: str
|
||||
a_date_from: Optional[datetime]
|
||||
a_date_to: Optional[datetime]
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls(
|
||||
a_get_all_order = True,
|
||||
a_get_inactive_order = False,
|
||||
a_ids_order = '',
|
||||
a_ids_permutation = '',
|
||||
a_date_from = None,
|
||||
a_date_to = None
|
||||
)
|
||||
@classmethod
|
||||
def from_filters_manufacturing_purchase_order(cls, form):
|
||||
parameters = cls.get_default()
|
||||
parameters.a_get_inactive_order = form.active.data
|
||||
parameters.a_date_from = form.date_from.data
|
||||
parameters.a_date_to = form.date_to.data
|
||||
return parameters
|
||||
|
||||
class Manufacturing_Purchase_Order_Temp(db.Model, Store_Base):
|
||||
__tablename__: ClassVar[str] = 'Shop_Manufacturing_Purchase_Order_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_order: int = db.Column(db.Integer)
|
||||
id_currency: int = db.Column(db.Integer)
|
||||
active: bool = db.Column(db.Boolean)
|
||||
guid: str = db.Column(db.String(36))
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_manufacturing_purchase_order(cls, manufacturing_purchase_order):
|
||||
row = cls()
|
||||
row.id_order = manufacturing_purchase_order.id_order
|
||||
row.id_currency = manufacturing_purchase_order.id_currency
|
||||
row.active = 1 if manufacturing_purchase_order.active else 0
|
||||
return row
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_order: {self.id_order}
|
||||
id_currency: {self.id_currency}
|
||||
active: {self.active}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
|
||||
class Manufacturing_Purchase_Order_Product_Link_Temp(db.Model, Store_Base):
|
||||
__tablename__: ClassVar[str] = 'Shop_Manufacturing_Purchase_Order_Product_Link_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_link: int = db.Column(db.Integer)
|
||||
id_order: int = db.Column(db.Integer)
|
||||
# id_category: int = db.Column(db.Integer)
|
||||
id_product: int = db.Column(db.Integer)
|
||||
id_permutation: int = db.Column(db.Integer)
|
||||
csv_list_variations: str = db.Column(db.String)
|
||||
id_unit_quantity: int = db.Column(db.Integer)
|
||||
quantity_used: float = db.Column(db.Float)
|
||||
quantity_produced: float = db.Column(db.Float)
|
||||
id_unit_latency_manufacture = db.Column(db.Integer)
|
||||
latency_manufacture: int = db.Column(db.Integer)
|
||||
display_order: int = db.Column(db.Integer)
|
||||
"""
|
||||
cost_unit_local_VAT_excl: float = db.Column(db.Float)
|
||||
cost_unit_local_VAT_incl: float = db.Column(db.Float)
|
||||
price_unit_local_VAT_excl: float = db.Column(db.Float)
|
||||
price_unit_local_VAT_incl: float = db.Column(db.Float)
|
||||
"""
|
||||
active: bool = db.Column(db.Boolean)
|
||||
guid: str = db.Column(db.String(36))
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_manufacturing_purchase_order_product_link(cls, manufacturing_purchase_order_product_link):
|
||||
row = cls()
|
||||
row.id_link = manufacturing_purchase_order_product_link.id_link
|
||||
row.id_order = manufacturing_purchase_order_product_link.id_order
|
||||
# row.id_category = manufacturing_purchase_order_product_link.id_category
|
||||
row.id_product = manufacturing_purchase_order_product_link.id_product
|
||||
row.id_permutation = manufacturing_purchase_order_product_link.id_permutation
|
||||
row.csv_list_variations = manufacturing_purchase_order_product_link.csv_id_pairs_variation
|
||||
row.id_unit_quantity = manufacturing_purchase_order_product_link.id_unit_quantity
|
||||
row.quantity_used = manufacturing_purchase_order_product_link.quantity_used
|
||||
row.quantity_produced = manufacturing_purchase_order_product_link.quantity_produced
|
||||
row.id_unit_latency_manufacture = manufacturing_purchase_order_product_link.id_unit_latency_manufacture
|
||||
row.latency_manufacture = manufacturing_purchase_order_product_link.latency_manufacture
|
||||
row.display_order = manufacturing_purchase_order_product_link.display_order
|
||||
"""
|
||||
row.cost_unit_local_VAT_excl = manufacturing_purchase_order_product_link.cost_unit_local_VAT_excl
|
||||
row.cost_unit_local_VAT_incl = manufacturing_purchase_order_product_link.cost_unit_local_VAT_incl
|
||||
row.price_unit_local_VAT_excl = manufacturing_purchase_order_product_link.price_unit_local_VAT_excl
|
||||
row.price_unit_local_VAT_incl = manufacturing_purchase_order_product_link.price_unit_local_VAT_incl
|
||||
"""
|
||||
row.active = 1 if manufacturing_purchase_order_product_link.active else 0
|
||||
return row
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_link: {self.id_link}
|
||||
id_order: {self.id_order}
|
||||
id_product: {self.id_product}
|
||||
id_permutation: {self.id_permutation}
|
||||
csv_list_variations: {self.csv_list_variations}
|
||||
id_unit_quantity: {self.id_unit_quantity}
|
||||
quantity_used: {self.quantity_used}
|
||||
quantity_produced: {self.quantity_produced}
|
||||
{self.ATTR_ID_UNIT_MEASUREMENT_LATENCY_MANUFACTURE}: {self.id_unit_latency_manufacture}
|
||||
latency_manufacture: {self.latency_manufacture}
|
||||
display_order: {self.display_order}
|
||||
active: {self.active}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
89
business_objects/store/order.py
Normal file
89
business_objects/store/order.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Order Business Object
|
||||
|
||||
Description:
|
||||
Business object for order
|
||||
"""
|
||||
|
||||
# internal
|
||||
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
|
||||
# from enum import Enum
|
||||
from flask import jsonify
|
||||
import locale
|
||||
|
||||
|
||||
# VARIABLE INSTANTIATION
|
||||
|
||||
# CLASSES
|
||||
class Order(Store_Base):
|
||||
category: str
|
||||
product: Product
|
||||
quantity: int
|
||||
subtotal: float
|
||||
delivery_option: Delivery_Option
|
||||
# form: Form_Product
|
||||
|
||||
def __new__(cls, category, product, quantity):
|
||||
# Initialiser - validation
|
||||
_m = 'Product.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
av.val_str(category, 'category', _m, v_arg_type=v_arg_type)
|
||||
av.val_instance(product, 'product', _m, Product, v_arg_type=v_arg_type)
|
||||
av.full_val_float(quantity, 'quantity', _m, product.quantity_min, v_arg_type=v_arg_type)
|
||||
return super(Basket_Item, cls).__new__(cls)
|
||||
|
||||
def __init__(self, category, product, quantity):
|
||||
# Constructor
|
||||
self.category = category
|
||||
self.product = product
|
||||
self.quantity = quantity
|
||||
self.subtotal = round(self.product.price_GBP_full * self.quantity, 2)
|
||||
"""
|
||||
self.form = Form_Product()
|
||||
if self.form.validate_on_submit():
|
||||
# Handle form submission
|
||||
|
||||
pass
|
||||
"""
|
||||
|
||||
def update_quantity(self, quantity):
|
||||
_m = 'Basket_Item.update_quantity'
|
||||
v_arg_type = 'class attribute'
|
||||
av.full_val_float(quantity, 'quantity', _m, self.product.quantity_min, v_arg_type=v_arg_type)
|
||||
self.quantity = quantity
|
||||
self.subtotal = round(self.product.price_GBP_full * self.quantity, 2)
|
||||
|
||||
def jsonify(self):
|
||||
return jsonify(self)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
def output_subtotal(self):
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
return locale.format_string("%d", self.subtotal, grouping=True)
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
category: {self.category}
|
||||
product: {self.product}
|
||||
quantity: {self.quantity}
|
||||
subtotal: {self.subtotal}
|
||||
'''
|
||||
93
business_objects/store/plant.py
Normal file
93
business_objects/store/plant.py
Normal file
@@ -0,0 +1,93 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Plant Business Object
|
||||
|
||||
Description:
|
||||
Business object for plant
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.address import Address
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Plant(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PLANT
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
__tablename__ = 'Shop_Plant'
|
||||
id_plant = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
name = db.Column(db.String(255))
|
||||
id_address = db.Column(db.Integer)
|
||||
id_user_manager = db.Column(db.Integer)
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
# address = None
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.address = None
|
||||
@classmethod
|
||||
def from_DB_storage_location(cls, query_row):
|
||||
plant = cls()
|
||||
plant.id_plant = query_row[1]
|
||||
plant.id_address = query_row[2]
|
||||
plant.address = Address.from_DB_storage_location(query_row)
|
||||
return plant
|
||||
@classmethod
|
||||
def from_DB_plant(cls, query_row):
|
||||
plant = cls()
|
||||
plant.id_plant = query_row[0]
|
||||
plant.id_address = query_row[1]
|
||||
plant.address = Address.from_DB_plant(query_row)
|
||||
plant.code = query_row[4]
|
||||
plant.name = query_row[5]
|
||||
plant.active = query_row[6]
|
||||
return plant
|
||||
@classmethod
|
||||
def from_DB_stock_item(cls, query_row):
|
||||
plant = cls()
|
||||
plant.id_plant = query_row[5]
|
||||
plant.code = query_row[10]
|
||||
plant.name = query_row[11]
|
||||
return plant
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_PLANT}: {self.id_plant}
|
||||
{self.FLAG_CODE}: {self.code}
|
||||
{self.FLAG_NAME}: {self.name}
|
||||
{self.FLAG_ADDRESS}: {self.address}
|
||||
{self.ATTR_ID_USER_MANAGER}: {self.id_user_manager}
|
||||
{self.FLAG_ACTIVE}: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_PLANT: self.id_plant,
|
||||
self.FLAG_CODE: self.code,
|
||||
self.FLAG_NAME: self.name,
|
||||
self.FLAG_ADDRESS: None if self.address is None else self.address.to_json(),
|
||||
self.ATTR_ID_USER_MANAGER: self.id_user_manager,
|
||||
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):
|
||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
||||
plant = cls()
|
||||
plant.id_plant = json[cls.ATTR_ID_PLANT],
|
||||
plant.code = json[cls.FLAG_CODE],
|
||||
plant.name = json[cls.FLAG_NAME],
|
||||
plant.address = Address.from_json(json[cls.FLAG_ADDRESS]),
|
||||
plant.id_user_manager = json[cls.ATTR_ID_USER_MANAGER],
|
||||
plant.active = json[cls.FLAG_ACTIVE]
|
||||
return plant
|
||||
917
business_objects/store/product.py
Normal file
917
business_objects/store/product.py
Normal file
@@ -0,0 +1,917 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Business Object
|
||||
|
||||
Description:
|
||||
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
|
||||
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
|
||||
from business_objects.store.image import Image
|
||||
from business_objects.store.product_permutation import Product_Permutation
|
||||
from business_objects.store.product_price import Product_Price
|
||||
from business_objects.store.store_base import Store_Base
|
||||
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 Filters_Product
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar, List
|
||||
"""
|
||||
class Enum_Status_Stock(Enum):
|
||||
OUT = 0
|
||||
LOW = 1
|
||||
IN = 99
|
||||
|
||||
def text(self):
|
||||
return Enum_Status_Stock.Enum_Status_Stock_Text(self)
|
||||
|
||||
def Enum_Status_Stock_Text(status):
|
||||
av.val_instance(status, 'category', 'Enum_Status_Stock_Text', Enum_Status_Stock)
|
||||
if status == Enum_Status_Stock.OUT:
|
||||
return 'Out of stock'
|
||||
elif status == Enum_Status_Stock.LOW:
|
||||
return 'Low on stock'
|
||||
else:
|
||||
return 'Fully stocked'
|
||||
|
||||
def get_member_by_text(text):
|
||||
return data_types.get_enum_member_by_text(Enum_Status_Stock, text.upper())
|
||||
|
||||
"""
|
||||
class Product(SQLAlchemy_ABC, Store_Base):
|
||||
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_PRODUCT_VARIATION_TREES: ClassVar[str] = 'variation-trees'
|
||||
|
||||
id_product = db.Column(db.Integer, primary_key=True)
|
||||
id_category = db.Column(db.Integer)
|
||||
name = db.Column(db.String(255))
|
||||
id_access_level_required = db.Column(db.Integer)
|
||||
active = db.Column(db.Boolean)
|
||||
display_order = db.Column(db.Integer)
|
||||
can_view = db.Column(db.Boolean)
|
||||
can_edit = db.Column(db.Boolean)
|
||||
can_admin = db.Column(db.Boolean)
|
||||
# form_basket_add: Form_Basket_Add
|
||||
# form_basket_edit: Form_Basket_Edit
|
||||
# has_variations: bool
|
||||
# index_permutation_selected: int
|
||||
|
||||
"""
|
||||
permutations: list = None
|
||||
permutation_index: dict = None
|
||||
variation_trees: list = None
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.permutations = []
|
||||
self.permutation_index = {}
|
||||
self.variation_trees = []
|
||||
self.index_permutation_selected = None
|
||||
self.has_variations = False
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.form_basket_add = Form_Basket_Add()
|
||||
self.form_basket_edit = Form_Basket_Edit()
|
||||
self.name_access_level_required = None
|
||||
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
_m = 'Product.from_DB_get_many_product_catalogue'
|
||||
v_arg_type = 'class attribute'
|
||||
product = Product()
|
||||
product.id_product = query_row[0]
|
||||
product.id_category = query_row[1]
|
||||
product.name = query_row[2]
|
||||
product.has_variations = av.input_bool(query_row[3], "has_variations", _m, v_arg_type=v_arg_type)
|
||||
product.id_access_level_required = query_row[4]
|
||||
product.name_access_level_required = query_row[5]
|
||||
product.active = av.input_bool(query_row[6], "active", _m, v_arg_type=v_arg_type)
|
||||
product.display_order = query_row[7]
|
||||
product.can_view = av.input_bool(query_row[8], "can_view", _m, v_arg_type=v_arg_type)
|
||||
product.can_edit = av.input_bool(query_row[9], "can_edit", _m, v_arg_type=v_arg_type)
|
||||
product.can_admin = av.input_bool(query_row[10], "can_admin", _m, v_arg_type=v_arg_type)
|
||||
return product
|
||||
"""
|
||||
def from_permutation(permutation, has_variations = False):
|
||||
_m = 'Product.from_permutation'
|
||||
v_arg_type = 'class attribute'
|
||||
av.val_instance(permutation, 'permutation', _m, Product_Permutation, v_arg_type=v_arg_type)
|
||||
product = Product()
|
||||
product.has_variations = has_variations
|
||||
product.index_permutation_selected = 0
|
||||
product.id_product = permutation.id_product
|
||||
product.id_category = permutation.id_category
|
||||
product.display_order = permutation.display_order
|
||||
product.can_view = permutation.can_view
|
||||
product.can_edit = permutation.can_edit
|
||||
product.can_admin = permutation.can_admin
|
||||
product.permutations.append(permutation)
|
||||
# product.get_variation_trees()
|
||||
return product
|
||||
"""
|
||||
def add_product_permutation(self, permutation):
|
||||
_m = 'Product.add_product_permutation'
|
||||
av.val_instance(permutation, 'permutation', _m, Product_Permutation)
|
||||
try:
|
||||
self.permutation_index[permutation.id_permutation]
|
||||
raise ValueError(f"{av.error_msg_str(permutation, 'permutation', _m, Product_Permutation)}\nPermutation ID already in product")
|
||||
except KeyError:
|
||||
self.permutation_index[permutation.id_permutation] = len(self.permutations)
|
||||
self.permutations.append(permutation)
|
||||
"""
|
||||
if self.has_variations:
|
||||
self.has_variations = False
|
||||
"""
|
||||
if self.index_permutation_selected is None:
|
||||
self.index_permutation_selected = self.permutation_index[permutation.id_permutation]
|
||||
Helper_App.console_log(f'setting selected permutation for product {self.id_product} to {self.index_permutation_selected}') # :\n{self.permutations[self.index_permutation_selected]}
|
||||
"""
|
||||
def from_permutations(permutations):
|
||||
_m = 'Product.from_permutations'
|
||||
v_arg_type = 'class attribute'
|
||||
if len(permutations) == 0:
|
||||
raise ValueError(av.error_msg_str(permutations, 'permutations', _m, list, v_arg_type=v_arg_type))
|
||||
product = Product()
|
||||
product.has_variations = True
|
||||
product.index_permutation_selected = 0
|
||||
product.id_product = permutations[0].id_product
|
||||
product.id_category = permutations[0].id_category
|
||||
product.display_order = permutations[0].display_order
|
||||
product.can_view = True
|
||||
product.can_edit = True
|
||||
product.can_admin = True
|
||||
for permutation in permutations:
|
||||
product.can_view &= permutation.can_view
|
||||
product.can_edit &= permutation.can_edit
|
||||
product.can_admin &= permutation.can_admin
|
||||
product.permutations.append(permutations)
|
||||
product.get_variation_trees()
|
||||
return product
|
||||
"""
|
||||
def get_variation_trees(self):
|
||||
self.variation_trees = []
|
||||
for index_permutation in range(len(self.permutations)):
|
||||
permutation = self.permutations[index_permutation]
|
||||
variation_tree = permutation.variation_tree # Product_Variation_Tree.from_product_permutation(permutation)
|
||||
found_variation_tree_match = False
|
||||
for index_tree in range(len(self.variation_trees)):
|
||||
if self.variation_trees[index_tree].is_equal(variation_tree):
|
||||
found_variation_tree_match = True
|
||||
break
|
||||
if not found_variation_tree_match and variation_tree is not None:
|
||||
self.variation_trees.append(variation_tree)
|
||||
def from_DB_Stripe_product(query_row):
|
||||
permutation = Product_Permutation.from_DB_Stripe_product(query_row)
|
||||
product = Product.from_permutation(permutation)
|
||||
return product
|
||||
def from_DB_Stripe_price(query_row):
|
||||
permutation = Product_Permutation.from_DB_Stripe_price(query_row)
|
||||
product = Product.from_permutation(permutation)
|
||||
return product
|
||||
"""
|
||||
def from_json(json_basket_item, key_id_product, key_id_permutation):
|
||||
permutation = Product_Permutation.from_json(json_basket_item, key_id_product, key_id_permutation)
|
||||
product = Product.from_permutation(permutation)
|
||||
return product
|
||||
"""
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
product = cls()
|
||||
product.id_product = json[cls.ATTR_ID_PRODUCT]
|
||||
product.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
product.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
product.name = json[cls.FLAG_NAME]
|
||||
product.has_variations = av.input_bool(json.get(cls.FLAG_HAS_VARIATIONS, None), cls.FLAG_HAS_VARIATIONS, f'{cls.__name__}.from_json')
|
||||
product.id_access_level_required = json.get(cls.ATTR_ID_ACCESS_LEVEL, None)
|
||||
product.active = 1 if av.input_bool(json[cls.FLAG_ACTIVE], cls.FLAG_ACTIVE, f'{cls.__name__}.from_json') else 0
|
||||
product.can_view = json.get(cls.FLAG_CAN_VIEW, None)
|
||||
product.can_edit = json.get(cls.FLAG_CAN_EDIT, None)
|
||||
product.can_admin = json.get(cls.FLAG_CAN_ADMIN, None)
|
||||
return product
|
||||
def get_permutation_selected(self):
|
||||
try:
|
||||
return self.permutations[self.index_permutation_selected]
|
||||
except:
|
||||
raise ValueError(f'list index {self.index_permutation_selected} out of range')
|
||||
def output_lead_time(self):
|
||||
return self.get_permutation_selected().output_lead_time()
|
||||
def output_delivery_date(self):
|
||||
return self.get_permutation_selected().output_delivery_date()
|
||||
def output_price(self, is_included_VAT):
|
||||
return self.get_permutation_selected().output_price(is_included_VAT)
|
||||
def output_price_VAT_incl(self):
|
||||
return self.get_permutation_selected().output_price(True)
|
||||
def output_price_VAT_excl(self):
|
||||
return self.get_permutation_selected().output_price(False)
|
||||
def get_price_local(self, is_included_VAT):
|
||||
if is_included_VAT:
|
||||
return self.get_price_local_VAT_incl()
|
||||
else:
|
||||
return self.get_price_local_VAT_excl()
|
||||
def get_price_local_VAT_incl(self):
|
||||
return self.get_permutation_selected().get_price_local_VAT_incl()
|
||||
def get_price_local_VAT_excl(self):
|
||||
return self.get_permutation_selected().get_price_local_VAT_excl()
|
||||
def get_quantity_min(self):
|
||||
return self.get_permutation_selected().quantity_min
|
||||
def get_id_permutation(self):
|
||||
return self.get_permutation_selected().id_permutation
|
||||
def get_image_from_index(self, index_image):
|
||||
return self.get_permutation_selected().images[index_image]
|
||||
def get_name(self):
|
||||
return self.get_permutation_selected().name
|
||||
def get_description(self):
|
||||
return self.get_permutation_selected().description
|
||||
def output_currency(self):
|
||||
return self.get_permutation_selected().get_price().symbol_currency
|
||||
"""
|
||||
def add_form_basket_add(self):
|
||||
self.form_basket_add = None
|
||||
|
||||
def add_form_basket_edit(self):
|
||||
self.form_basket_edit = None
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''Product
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
name: {self.name}
|
||||
display_order: {self.display_order}
|
||||
can_view: {self.can_view}
|
||||
can_edit: {self.can_edit}
|
||||
can_admin: {self.can_admin}
|
||||
has_variations: {self.has_variations}
|
||||
permutations: {self.permutations}
|
||||
variation trees: {self.variation_trees}
|
||||
active: {self.active}
|
||||
'''
|
||||
"""
|
||||
def get_index_permutation_from_id(self, id_permutation):
|
||||
if id_permutation is None and not self.has_variations:
|
||||
return 0
|
||||
for index_permutation in range(len(self.permutations)):
|
||||
permutation = self.permutations[index_permutation]
|
||||
if permutation.id_permutation == id_permutation:
|
||||
return index_permutation
|
||||
raise ValueError(f"{av.error_msg_str(id_permutation, 'id_permutation', 'Product.get_index_permutation_from_id', int)}\nPermutation ID not found.")
|
||||
"""
|
||||
"""
|
||||
def add_product_variation(self, variation):
|
||||
av.val_instance(variation, 'variation', 'Product.add_product_variation', Product_Variation)
|
||||
# Helper_App.console_log(f'variation: {variation}')
|
||||
index_permutation = self.permutation_index[variation.id_permutation] # self.get_index_permutation_from_id(variation.id_permutation)
|
||||
self.permutations[index_permutation].add_product_variation(variation)
|
||||
"""
|
||||
def add_product_variation_type(self, variation_type):
|
||||
variation = variation_type.variations[0]
|
||||
index_permutation = self.permutation_index[variation.id_permutation]
|
||||
self.permutations[index_permutation].add_product_variation_type(variation_type)
|
||||
def add_product_price(self, price):
|
||||
av.val_instance(price, 'price', 'Product.add_product_price', Product_Price)
|
||||
index_permutation = self.permutation_index[price.id_permutation] # self.get_index_permutation_from_id(price.id_permutation)
|
||||
self.permutations[index_permutation].add_product_price(price)
|
||||
def add_product_image(self, image):
|
||||
av.val_instance(image, 'image', 'Product.add_product_image', Image)
|
||||
index_permutation = self.permutation_index[image.id_permutation] # self.get_index_permutation_from_id(image.id_permutation)
|
||||
self.permutations[index_permutation].add_product_image(image)
|
||||
def add_delivery_option(self, delivery_option):
|
||||
av.val_instance(delivery_option, 'delivery_option', 'Product.add_delivery_option', Delivery_Option)
|
||||
index_permutation = self.permutation_index[delivery_option.id_permutation] # self.get_index_permutation_from_id(delivery_option.id_permutation)
|
||||
self.permutations[index_permutation].add_delivery_option(delivery_option)
|
||||
def add_product_price_discount(self, discount):
|
||||
av.val_instance(discount, 'discount', 'Product.add_product_price_discount', Discount)
|
||||
index_permutation = self.permutation_index[discount.id_permutation] # self.get_index_permutation_from_id(discount.id_permutation)
|
||||
self.permutations[index_permutation].add_product_price_discount(discount)
|
||||
def add_stock_item(self, stock_item):
|
||||
av.val_instance(stock_item, 'stock_item', 'Product.add_stock_item', Stock_Item)
|
||||
index_permutation = self.permutation_index[stock_item.id_permutation]
|
||||
self.permutations[index_permutation].add_stock_item(stock_item)
|
||||
def has_permutations(self):
|
||||
return len(self.permutations) > 0
|
||||
def is_available(self):
|
||||
if len(self.permutations) == 0:
|
||||
return False
|
||||
for permutation in self.permutations:
|
||||
if permutation.is_available():
|
||||
return True
|
||||
return False
|
||||
def to_permutation_row_list(self):
|
||||
list_rows = []
|
||||
for permutation in self.permutations:
|
||||
list_rows.append(permutation.to_row_permutation())
|
||||
return list_rows
|
||||
"""
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
product = cls()
|
||||
product.id_product = json[cls.ATTR_ID_PRODUCT]
|
||||
product.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
product.name = json[cls.FLAG_NAME]
|
||||
product.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
product.can_view = json[cls.FLAG_CAN_VIEW]
|
||||
product.can_edit = json[cls.FLAG_CAN_EDIT]
|
||||
product.can_admin = json[cls.FLAG_CAN_ADMIN]
|
||||
product.has_variations = json[cls.FLAG_HAS_VARIATIONS]
|
||||
product.index_permutation_selected = json[cls.FLAG_INDEX_PERMUTATION_SELECTED]
|
||||
product.permutations = []
|
||||
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_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,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_CAN_VIEW: self.can_view,
|
||||
self.FLAG_CAN_EDIT: self.can_edit,
|
||||
self.FLAG_CAN_ADMIN: self.can_admin,
|
||||
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_PRODUCT_VARIATION_TREES: [tree.to_json() for tree in self.variation_trees]
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_product,
|
||||
'text': self.name
|
||||
}
|
||||
def get_variation_types_unique(self):
|
||||
list_types = []
|
||||
for tree in self.variation_trees:
|
||||
for type in tree.get_types_unique():
|
||||
if type not in list_types:
|
||||
list_types.append(type)
|
||||
return list_types
|
||||
"""
|
||||
def get_json_str_types_variation_trees(self):
|
||||
json_str = ''
|
||||
for tree in self.variation_trees:
|
||||
if json_str != '':
|
||||
json_str += '\n'
|
||||
json_str += tree.get_json_str_types()
|
||||
return json_str
|
||||
def get_text_input_variation_types(self):
|
||||
text_input = ''
|
||||
for tree in self.variation_trees:
|
||||
if text_input != '':
|
||||
text_input += '\n'
|
||||
text_input += tree.get_text_input_types()
|
||||
return text_input
|
||||
"""
|
||||
def get_csv_ids_permutation(self):
|
||||
csv = ''
|
||||
for permutation in self.permutations:
|
||||
if csv != '':
|
||||
csv += ','
|
||||
csv += str(permutation.id_permutation)
|
||||
return csv
|
||||
|
||||
|
||||
class Parameters_Product(Get_Many_Parameters_Base):
|
||||
# id_user: str
|
||||
get_all_product_category: bool
|
||||
get_inactive_product_category: bool
|
||||
# get_first_product_category_only: bool
|
||||
ids_product_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_image: bool
|
||||
get_inactive_image: bool
|
||||
# get_first_image_only: bool
|
||||
ids_image: str
|
||||
"""
|
||||
get_all_region: bool
|
||||
get_inactive_region: bool
|
||||
get_first_region_only: bool
|
||||
ids_region: str
|
||||
get_all_currency: bool
|
||||
get_inactive_currency: bool
|
||||
get_first_currency_only: bool
|
||||
ids_currency: str
|
||||
get_all_discount: bool
|
||||
get_inactive_discount: bool
|
||||
ids_discount: str
|
||||
"""
|
||||
get_products_quantity_stock_below_min: bool
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
# 'a_id_user': None,
|
||||
'a_get_all_product_category': self.get_all_product_category,
|
||||
'a_get_inactive_product_category': self.get_inactive_product_category,
|
||||
# 'a_get_first_product_category_only': self.get_first_product_category_only,
|
||||
'a_ids_product_category': self.ids_product_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_image': self.get_all_image,
|
||||
'a_get_inactive_image': self.get_inactive_image,
|
||||
# 'a_get_first_image_only': self.get_first_image_only,
|
||||
'a_ids_image': self.ids_image,
|
||||
# 'a_get_all_delivery_region': self.get_all_region,
|
||||
# 'a_get_inactive_delivery_region': self.get_inactive_region,
|
||||
# 'a_get_first_delivery_region_only': self.get_first_region_only,
|
||||
# 'a_ids_delivery_region': self.ids_region,
|
||||
# 'a_get_all_currency': self.get_all_currency,
|
||||
# 'a_get_inactive_currency': self.get_inactive_currency,
|
||||
# 'a_get_first_currency_only': self.get_first_currency_only,
|
||||
# 'a_ids_currency': self.ids_currency,
|
||||
# 'a_get_all_discount': self.get_all_discount,
|
||||
# 'a_get_inactive_discount': self.get_inactive_discount,
|
||||
# 'a_ids_discount': self.ids_discount,
|
||||
'a_get_products_quantity_stock_below_min': self.get_products_quantity_stock_below_min
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def from_form_filters_product(form):
|
||||
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Parameters_Product.from_form', Filters_Product)
|
||||
has_filter_category = not (form.id_category.data == '0' or form.id_category.data == '' or form.id_category.data is None)
|
||||
is_not_empty = av.input_bool(form.is_not_empty.data, "is_not_empty", "Parameters_Product.from_form_filters_product")
|
||||
active = av.input_bool(form.active.data, "active", "Parameters_Product.from_form_filters_product")
|
||||
return Parameters_Product(
|
||||
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 if form.id_category.data is not None else '',
|
||||
get_all_product = True,
|
||||
get_inactive_product = not active,
|
||||
# get_first_product_only = False,
|
||||
ids_product = '',
|
||||
get_all_permutation = True,
|
||||
get_inactive_permutation = not active,
|
||||
# get_first_permutation_only = False,
|
||||
ids_permutation = '',
|
||||
get_all_image = False,
|
||||
get_inactive_image = False,
|
||||
# get_first_image_only = False,
|
||||
ids_image = '',
|
||||
# get_all_region = False,
|
||||
# get_inactive_region = False,
|
||||
# get_first_region_only = False,
|
||||
# ids_region = '',
|
||||
# get_all_currency = False,
|
||||
# get_inactive_currency = False,
|
||||
# get_first_currency_only = False,
|
||||
# ids_currency = '',
|
||||
# get_all_discount = False,
|
||||
# get_inactive_discount = False,
|
||||
# ids_discount = '',
|
||||
get_products_quantity_stock_below_min = False
|
||||
)
|
||||
@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', 'Parameters_Product.from_form', Filters_Product_Permutation)
|
||||
has_category_filter = not (form.id_category.data == '0' or form.id_category.data == '' or form.id_category.data is None)
|
||||
has_product_filter = not (form.id_product.data == '0' or form.id_product.data == '' or form.id_product.data is None)
|
||||
get_permutations_stock_below_min = av.input_bool(form.is_out_of_stock.data, "is_out_of_stock", "Parameters_Product.from_form_filters_product_permutation")
|
||||
get_inactive = not av.input_bool(form.active.data, "active", "Parameters_Product.from_form_filters_product_permutation")
|
||||
Helper_App.console_log(f'form question: {type(form.is_out_of_stock)}\nbool interpretted: {get_permutations_stock_below_min}\nform question: {type(form.active)}\nget_inactive:{get_inactive}\ntype form: {type(form)}')
|
||||
return Parameters_Product(
|
||||
get_all_product_category = not has_category_filter,
|
||||
get_inactive_product_category = get_inactive,
|
||||
# get_first_product_category_only = False,
|
||||
ids_product_category = form.id_category.data if form.id_category.data is not None else '',
|
||||
get_all_product = not has_product_filter,
|
||||
get_inactive_product = get_inactive,
|
||||
# get_first_product_only = False,
|
||||
ids_product = form.id_product.data if form.id_product.data is not None else '',
|
||||
get_all_permutation = not get_permutations_stock_below_min,
|
||||
get_inactive_permutation = get_inactive,
|
||||
# get_first_permutation_only = False,
|
||||
ids_permutation = '',
|
||||
get_all_image = False,
|
||||
get_inactive_image = False,
|
||||
# get_first_image_only = False,
|
||||
ids_image = '',
|
||||
# get_all_region = False,
|
||||
# get_inactive_region = False,
|
||||
# get_first_region_only = False,
|
||||
# ids_region = '',
|
||||
# get_all_currency = False,
|
||||
# get_inactive_currency = False,
|
||||
# get_first_currency_only = False,
|
||||
# ids_currency = '',
|
||||
# get_all_discount = False,
|
||||
# get_inactive_discount = False,
|
||||
# ids_discount = '',
|
||||
get_products_quantity_stock_below_min = get_permutations_stock_below_min
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_default():
|
||||
return Parameters_Product(
|
||||
get_all_product_category = True,
|
||||
get_inactive_product_category = False,
|
||||
# get_first_product_category_only = False,
|
||||
ids_product_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_image = True,
|
||||
get_inactive_image = False,
|
||||
# get_first_image_only = False,
|
||||
ids_image = '',
|
||||
# get_all_region = True,
|
||||
# et_inactive_region = False,
|
||||
# get_first_region_only = False,
|
||||
# ids_region = '',
|
||||
# get_all_currency = True,
|
||||
# get_inactive_currency = False,
|
||||
# get_first_currency_only = False,
|
||||
# ids_currency = '',
|
||||
# get_all_discount = True,
|
||||
# get_inactive_discount = False,
|
||||
# ids_discount = '',
|
||||
get_products_quantity_stock_below_min = True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
return cls(
|
||||
get_all_product_category = json.get('a_get_all_product_category', False),
|
||||
get_inactive_product_category = json.get('a_get_inactive_product_category', False),
|
||||
# get_first_product_category_only = json.get('a_get_first_product_category_only', False),
|
||||
ids_product_category = json.get('a_ids_product_category', ''),
|
||||
get_all_product = json.get('a_get_all_product', False),
|
||||
get_inactive_product = json.get('a_get_inactive_product', False),
|
||||
# get_first_product_only = json.get('a_get_first_product_only', False),
|
||||
ids_product = json.get('a_ids_product', ''),
|
||||
get_all_permutation = json.get('a_get_all_permutation', False),
|
||||
get_inactive_permutation = json.get('a_get_inactive_permutation', False),
|
||||
# get_first_permutation_only = json.get('a_get_first_permutation_only', False),
|
||||
ids_permutation = json.get('a_ids_permutation', ''),
|
||||
get_all_image = json.get('a_get_all_image', False),
|
||||
get_inactive_image = json.get('a_get_inactive_image', False),
|
||||
# get_first_image_only = json.get('a_get_first_image_only', False),
|
||||
ids_image = json.get('a_ids_image', ''),
|
||||
# get_all_region = json.get('a_get_all_region', False),
|
||||
# get_inactive_region = json.get('a_get_inactive_region', False),
|
||||
# get_first_region_only = json.get('a_get_first_region_only', False),
|
||||
# ids_region = json.get('a_ids_region', ''),
|
||||
# get_all_currency = json.get('a_get_all_currency', False),
|
||||
# get_inactive_currency = json.get('a_get_inactive_currency', False),
|
||||
# get_first_currency_only = json.get('a_get_first_currency_only', False),
|
||||
# ids_currency = json.get('a_ids_currency', ''),
|
||||
# get_all_discount = json.get('a_get_all_discount', False),
|
||||
# get_inactive_discount = json.get('a_get_inactive_discount', False),
|
||||
# ids_discount = json.get('a_ids_discount', ''),
|
||||
get_products_quantity_stock_below_min = json.get('a_get_products_quantity_stock_below_min', False)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_filters_product_category(cls, filters_category):
|
||||
return cls(
|
||||
get_all_product_category = True,
|
||||
get_inactive_product_category = not filters_category.active.data,
|
||||
ids_product_category = '',
|
||||
get_all_product = True,
|
||||
get_inactive_product = False,
|
||||
ids_product = '',
|
||||
get_all_permutation = True,
|
||||
get_inactive_permutation = False,
|
||||
ids_permutation = '',
|
||||
get_all_image = False,
|
||||
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)
|
||||
|
||||
"""
|
||||
class Parameters_Product(Get_Many_Parameters_Base):
|
||||
# id_user: str
|
||||
get_all_product_category: bool
|
||||
get_inactive_product_category: bool
|
||||
# get_first_product_category_only: bool
|
||||
ids_product_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_image: bool
|
||||
get_inactive_image: bool
|
||||
# get_first_image_only: bool
|
||||
ids_image: str
|
||||
""
|
||||
get_all_region: bool
|
||||
get_inactive_region: bool
|
||||
get_first_region_only: bool
|
||||
ids_region: str
|
||||
get_all_currency: bool
|
||||
get_inactive_currency: bool
|
||||
get_first_currency_only: bool
|
||||
ids_currency: str
|
||||
get_all_discount: bool
|
||||
get_inactive_discount: bool
|
||||
ids_discount: str
|
||||
""
|
||||
get_products_quantity_stock_below_min: bool
|
||||
|
||||
def __init__(self, a_id_user, **kwargs):
|
||||
super().__init__(a_id_user, **kwargs)
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
'a_id_user': self.a_id_user,
|
||||
'a_get_all_product_category': self.get_all_product_category,
|
||||
'a_get_inactive_product_category': self.get_inactive_product_category,
|
||||
# 'a_get_first_product_category_only': self.get_first_product_category_only,
|
||||
'a_ids_product_category': self.ids_product_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_image': self.get_all_image,
|
||||
'a_get_inactive_image': self.get_inactive_image,
|
||||
# 'a_get_first_image_only': self.get_first_image_only,
|
||||
'a_ids_image': self.ids_image,
|
||||
# 'a_get_all_delivery_region': self.get_all_region,
|
||||
# 'a_get_inactive_delivery_region': self.get_inactive_region,
|
||||
# 'a_get_first_delivery_region_only': self.get_first_region_only,
|
||||
# 'a_ids_delivery_region': self.ids_region,
|
||||
# 'a_get_all_currency': self.get_all_currency,
|
||||
# 'a_get_inactive_currency': self.get_inactive_currency,
|
||||
# 'a_get_first_currency_only': self.get_first_currency_only,
|
||||
# 'a_ids_currency': self.ids_currency,
|
||||
# 'a_get_all_discount': self.get_all_discount,
|
||||
# 'a_get_inactive_discount': self.get_inactive_discount,
|
||||
# 'a_ids_discount': self.ids_discount,
|
||||
'a_get_products_quantity_stock_below_min': self.get_products_quantity_stock_below_min
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def from_form_filters_product(form, id_user):
|
||||
# if not (form is Filters_Product_Permutation): raise ValueError(f'Invalid form type: {type(form)}')
|
||||
av.val_instance(form, 'form', 'Parameters_Product.from_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", "Parameters_Product.from_form_filters_product")
|
||||
active = av.input_bool(form.active.data, "active", "Parameters_Product.from_form_filters_product")
|
||||
return Parameters_Product(
|
||||
a_id_user = id_user,
|
||||
get_all_product_category = not has_filter_category,
|
||||
get_inactive_product_category = not active,
|
||||
# get_first_product_category_only = False,
|
||||
ids_product_category = str(form.id_category.data),
|
||||
get_all_product = True,
|
||||
get_inactive_product = not active,
|
||||
# get_first_product_only = False,
|
||||
ids_product = '',
|
||||
get_all_permutation = True,
|
||||
get_inactive_permutation = not active,
|
||||
# get_first_permutation_only = False,
|
||||
ids_permutation = '',
|
||||
get_all_image = False,
|
||||
get_inactive_image = False,
|
||||
# get_first_image_only = False,
|
||||
ids_image = '',
|
||||
# get_all_region = False,
|
||||
# get_inactive_region = False,
|
||||
# get_first_region_only = False,
|
||||
# ids_region = '',
|
||||
# get_all_currency = False,
|
||||
# get_inactive_currency = False,
|
||||
# get_first_currency_only = False,
|
||||
# ids_currency = '',
|
||||
# get_all_discount = False,
|
||||
# get_inactive_discount = False,
|
||||
# ids_discount = '',
|
||||
get_products_quantity_stock_below_min = False
|
||||
)
|
||||
@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', 'Parameters_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", "Parameters_Product.from_form")
|
||||
Helper_App.console_log(f'form question: {type(form.is_out_of_stock)}\nbool interpretted: {get_permutations_stock_below_min}\type form: {type(form)}')
|
||||
return Parameters_Product(
|
||||
get_all_product_category = not has_category_filter,
|
||||
get_inactive_product_category = False,
|
||||
# get_first_product_category_only = False,
|
||||
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 = 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,
|
||||
ids_permutation = '',
|
||||
get_all_image = False,
|
||||
get_inactive_image = False,
|
||||
# get_first_image_only = False,
|
||||
ids_image = '',
|
||||
# get_all_region = False,
|
||||
# get_inactive_region = False,
|
||||
# get_first_region_only = False,
|
||||
# ids_region = '',
|
||||
# get_all_currency = False,
|
||||
# get_inactive_currency = False,
|
||||
# get_first_currency_only = False,
|
||||
# ids_currency = '',
|
||||
# get_all_discount = False,
|
||||
# get_inactive_discount = False,
|
||||
# ids_discount = '',
|
||||
get_products_quantity_stock_below_min = get_permutations_stock_below_min
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_default(cls, id_user):
|
||||
return cls(
|
||||
a_id_user = id_user,
|
||||
get_all_product_category = True,
|
||||
get_inactive_product_category = False,
|
||||
# get_first_product_category_only = False,
|
||||
ids_product_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_image = True,
|
||||
get_inactive_image = False,
|
||||
# get_first_image_only = False,
|
||||
ids_image = '',
|
||||
# get_all_region = True,
|
||||
# et_inactive_region = False,
|
||||
# get_first_region_only = False,
|
||||
# ids_region = '',
|
||||
# get_all_currency = True,
|
||||
# get_inactive_currency = False,
|
||||
# get_first_currency_only = False,
|
||||
# ids_currency = '',
|
||||
# get_all_discount = True,
|
||||
# get_inactive_discount = False,
|
||||
# ids_discount = '',
|
||||
get_products_quantity_stock_below_min = True
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
return cls(
|
||||
get_all_product_category = json.get('a_get_all_product_category', False),
|
||||
get_inactive_product_category = json.get('a_get_inactive_product_category', False),
|
||||
# get_first_product_category_only = json.get('a_get_first_product_category_only', False),
|
||||
ids_product_category = json.get('a_ids_product_category', ''),
|
||||
get_all_product = json.get('a_get_all_product', False),
|
||||
get_inactive_product = json.get('a_get_inactive_product', False),
|
||||
# get_first_product_only = json.get('a_get_first_product_only', False),
|
||||
ids_product = json.get('a_ids_product', ''),
|
||||
get_all_permutation = json.get('a_get_all_permutation', False),
|
||||
get_inactive_permutation = json.get('a_get_inactive_permutation', False),
|
||||
# get_first_permutation_only = json.get('a_get_first_permutation_only', False),
|
||||
ids_permutation = json.get('a_ids_permutation', ''),
|
||||
get_all_image = json.get('a_get_all_image', False),
|
||||
get_inactive_image = json.get('a_get_inactive_image', False),
|
||||
# get_first_image_only = json.get('a_get_first_image_only', False),
|
||||
ids_image = json.get('a_ids_image', ''),
|
||||
# get_all_region = json.get('a_get_all_region', False),
|
||||
# get_inactive_region = json.get('a_get_inactive_region', False),
|
||||
# get_first_region_only = json.get('a_get_first_region_only', False),
|
||||
# ids_region = json.get('a_ids_region', ''),
|
||||
# get_all_currency = json.get('a_get_all_currency', False),
|
||||
# get_inactive_currency = json.get('a_get_inactive_currency', False),
|
||||
# get_first_currency_only = json.get('a_get_first_currency_only', False),
|
||||
# ids_currency = json.get('a_ids_currency', ''),
|
||||
# get_all_discount = json.get('a_get_all_discount', False),
|
||||
# get_inactive_discount = json.get('a_get_inactive_discount', False),
|
||||
# ids_discount = json.get('a_ids_discount', ''),
|
||||
get_products_quantity_stock_below_min = json.get('a_get_products_quantity_stock_below_min', False)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_filters_product_category(cls, filters_category):
|
||||
return cls(
|
||||
get_all_product_category = True,
|
||||
get_inactive_product_category = filters_category.active.data,
|
||||
ids_product_category = '',
|
||||
get_all_product = True,
|
||||
get_inactive_product = False,
|
||||
ids_product = '',
|
||||
get_all_permutation = True,
|
||||
get_inactive_permutation = False,
|
||||
ids_permutation = '',
|
||||
get_all_image = False,
|
||||
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)
|
||||
"""
|
||||
|
||||
class Product_Temp(db.Model, Store_Base):
|
||||
__tablename__ = 'Shop_Product_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_product: int = db.Column(db.Integer)
|
||||
id_category: int = db.Column(db.Integer)
|
||||
name: str = db.Column(db.String(255))
|
||||
has_variations: bool = db.Column(db.Boolean)
|
||||
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)
|
||||
def __init__(self):
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_product(cls, product):
|
||||
row = cls()
|
||||
row.id_product = product.id_product[0] if isinstance(product.id_product, tuple) else product.id_product
|
||||
row.id_category = product.id_category[0] if isinstance(product.id_category, tuple) else product.id_category
|
||||
row.name = product.name[0] if isinstance(product.name, tuple) else product.name
|
||||
row.has_variations = product.has_variations
|
||||
row.id_access_level_required = product.id_access_level_required[0] if isinstance(product.id_access_level_required, tuple) else product.id_access_level_required
|
||||
row.active = product.active
|
||||
row.display_order = product.display_order
|
||||
"""
|
||||
row.guid = product.guid
|
||||
row.created_on = product.created_on
|
||||
row.created_by = product.created_by
|
||||
"""
|
||||
return row
|
||||
def to_json(self):
|
||||
return {
|
||||
'id_product': self.id_product,
|
||||
'id_category': self.id_category,
|
||||
'name': self.name,
|
||||
'has_variations': av.input_bool(self.has_variations, self.FLAG_HAS_VARIATIONS, f'{self.__class__.__name__}.to_json'),
|
||||
'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
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''Product_Temp
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
name: {self.name}
|
||||
has_variations: {self.has_variations}
|
||||
id_access_level_required: {self.id_access_level_required}
|
||||
active: {self.active}
|
||||
display_order: {self.display_order}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
529
business_objects/store/product_category.py
Normal file
529
business_objects/store/product_category.py
Normal file
@@ -0,0 +1,529 @@
|
||||
"""
|
||||
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 category
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||
from business_objects.store.product import Product, Product_Permutation, Product_Price
|
||||
# from business_objects.store.product_variation import Product_Variation
|
||||
from business_objects.store.product_variation_type import Product_Variation_Type
|
||||
from business_objects.store.image import Image
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.store.discount import Discount
|
||||
from business_objects.store.stock_item import Stock_Item
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from pydantic import BaseModel
|
||||
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'
|
||||
id_category = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
name = db.Column(db.String(255))
|
||||
description = db.Column(db.String(4000))
|
||||
id_access_level_required = db.Column(db.Integer)
|
||||
name_access_level_required = db.Column(db.String(255))
|
||||
display_order = db.Column(db.Integer)
|
||||
active = db.Column(db.Boolean)
|
||||
can_view = db.Column(db.Boolean)
|
||||
can_edit = db.Column(db.Boolean)
|
||||
can_admin = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
created_by = db.Column(db.Integer)
|
||||
|
||||
"""
|
||||
products: list = None # []
|
||||
product_index: dict = None # {}
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.products = []
|
||||
self.product_index = {}
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.name_access_level_required = None
|
||||
@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]
|
||||
category.description = query_row[3]
|
||||
category.id_access_level_required = query_row[4]
|
||||
category.name_access_level_required = query_row[5]
|
||||
category.display_order = query_row[6]
|
||||
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):
|
||||
return f'{id_product},{"" if id_permutation is None else id_permutation}'
|
||||
def key_product_index_from_product(product):
|
||||
av.val_instance(product, 'product', 'Category.key_product_index_from_product', Product)
|
||||
return f'{product.id_product},{"" if product.id_permutation is None else product.id_permutation}'
|
||||
"""
|
||||
def get_index_product(self, product):
|
||||
return self.get_index_product_from_id(product.id_product)
|
||||
def get_index_product_from_id(self, id_product):
|
||||
try:
|
||||
return self.product_index[id_product]
|
||||
except:
|
||||
raise KeyError(f'product id: {id_product} not in product index keys: {self.product_index.keys()} with category id: {self.id_category}')
|
||||
def get_index_product_from_id_permutation(self, id_permutation):
|
||||
for product in self.products:
|
||||
try:
|
||||
index_permutation = product.get_index_permutation_from_id(id_permutation)
|
||||
return self.get_index_product(product)
|
||||
except:
|
||||
pass
|
||||
raise KeyError(f'permutation id: {id_permutation} not in category id: {self.id_category}')
|
||||
def add_product(self, product):
|
||||
_m = 'Category.add_product'
|
||||
av.val_instance(product, 'product', _m, Product)
|
||||
# self.product_index.append(len(self.products))
|
||||
# self.product_index[Category.key_product_index_from_ids_product_permutation(product.id_product, product.id_permutation)] = len(self.products)
|
||||
try:
|
||||
self.get_index_product(product)
|
||||
Helper_App.console_log(f'category: {self}')
|
||||
raise ValueError(f"{av.error_msg_str(product, 'product', _m, Product)}\nProduct already in category.")
|
||||
except KeyError:
|
||||
self.product_index[product.id_product] = len(self.products)
|
||||
self.products.append(product)
|
||||
def add_product_permutation(self, permutation):
|
||||
_m = 'Category.add_product_permutation'
|
||||
av.val_instance(permutation, 'permutation', _m, Product_Permutation)
|
||||
# self.product_index.append(len(self.products))
|
||||
# self.product_index[Category.key_product_index_from_ids_product_permutation(product.id_product, product.id_permutation)] = len(self.products)
|
||||
index_product = self.get_index_product_from_id(permutation.id_product)
|
||||
# index_product = self.product_index[permutation.id_product]
|
||||
self.products[index_product].add_product_permutation(permutation)
|
||||
"""
|
||||
def add_product_variation(self, variation):
|
||||
av.val_instance(variation, 'variation', 'Category.add_product_variation', Product_Variation)
|
||||
index_product = self.get_index_product_from_id(variation.id_product)
|
||||
self.products[index_product].add_product_variation(variation)
|
||||
"""
|
||||
def add_product_variation_type(self, variation_type):
|
||||
av.val_instance(variation_type, 'variation_type', 'Category.add_product_variation_type', Product_Variation_Type)
|
||||
variation = variation_type.variations[0]
|
||||
index_product = self.get_index_product_from_id(variation.id_product)
|
||||
self.products[index_product].add_product_variation_type(variation_type)
|
||||
def add_product_price(self, price):
|
||||
av.val_instance(price, 'price', 'Category.add_product_price', Product_Price)
|
||||
index_product = self.get_index_product_from_id(price.id_product)
|
||||
self.products[index_product].add_product_price(price)
|
||||
def add_product_image(self, image):
|
||||
av.val_instance(image, 'image', 'Category.add_product_image', Image)
|
||||
index_product = self.get_index_product_from_id(image.id_product)
|
||||
self.products[index_product].add_product_image(image)
|
||||
def add_delivery_option(self, delivery_option):
|
||||
av.val_instance(delivery_option, 'delivery_option', 'Category.add_delivery_option', Delivery_Option)
|
||||
index_product = self.get_index_product_from_id(delivery_option.id_product)
|
||||
self.products[index_product].add_delivery_option(delivery_option)
|
||||
def add_product_price_discount(self, discount):
|
||||
av.val_instance(discount, 'discount', 'Category.add_product_price_discount', Discount)
|
||||
index_product = self.get_index_product_from_id(discount.id_product)
|
||||
self.products[index_product].add_product_price_discount(discount)
|
||||
def add_stock_item(self, stock_item):
|
||||
av.val_instance(stock_item, 'stock_item', 'Category.add_stock_item', Stock_Item)
|
||||
index_product = self.get_index_product_from_id(stock_item.id_product)
|
||||
self.products[index_product].add_stock_item(stock_item)
|
||||
def get_all_product_variation_trees(self):
|
||||
for product in self.products:
|
||||
if product.has_variations:
|
||||
Helper_App.console_log(f'product with id:{product.id_product} has variations')
|
||||
product.get_variation_trees()
|
||||
"""
|
||||
def index_product_from_ids_product_permutation(self, id_product, id_permutation):
|
||||
key = Category.key_product_index_from_ids_product_permutation(id_product, id_permutation)
|
||||
Helper_App.console_log(f'product_index: {self.product_index}')
|
||||
Helper_App.console_log(f'Key Error: {key}')
|
||||
try:
|
||||
return self.product_index[key]
|
||||
except KeyError:
|
||||
pass
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_category[0] if isinstance(self.id_category, tuple) else self.id_category}
|
||||
code: {self.code[0] if isinstance(self.code, tuple) else self.code}
|
||||
name: {self.name[0] if isinstance(self.name, tuple) else self.name}
|
||||
description: {self.description[0] if isinstance(self.description, tuple) else self.description}
|
||||
access_level: {self.name_access_level_required[0] if isinstance(self.name_access_level_required, tuple) else self.name_access_level_required}
|
||||
display_order: {self.display_order}
|
||||
active: {self.active}
|
||||
products: {self.products}
|
||||
'''
|
||||
"""
|
||||
def get_permutation_first(self):
|
||||
if not (len(self.products) == 0):
|
||||
Helper_App.console_log(f'getting first permutation from product')
|
||||
return None if len(self.products) == 0 else self.products[0].get_permutation_selected()
|
||||
"""
|
||||
def is_available(self):
|
||||
if len(self.products) == 0:
|
||||
return False
|
||||
for product in self.products:
|
||||
if product.is_available():
|
||||
return True
|
||||
return False
|
||||
def to_permutation_row_list(self):
|
||||
list_rows = []
|
||||
for product in self.products:
|
||||
list_rows += product.to_permutation_row_list()
|
||||
return list_rows
|
||||
def to_product_option_list(self):
|
||||
list_products = []
|
||||
for product in self.products:
|
||||
list_products.append({'value': product.id_product, 'text': product.name})
|
||||
return list_products
|
||||
def to_json(self):
|
||||
return {
|
||||
**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,
|
||||
self.FLAG_DESCRIPTION: self.description[0] if isinstance(self.description, tuple) else self.description,
|
||||
self.ATTR_ID_ACCESS_LEVEL: self.id_access_level_required[0] if isinstance(self.id_access_level_required, tuple) else self.id_access_level_required,
|
||||
self.FLAG_ACCESS_LEVEL_REQUIRED: self.name_access_level_required[0] if isinstance(self.name_access_level_required, tuple) else self.name_access_level_required,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
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
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(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.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
category.active = 1 if av.input_bool(json[cls.FLAG_ACTIVE], cls.FLAG_ACTIVE, f'{cls.__name__}.from_json') else 0
|
||||
category.can_view = json.get(cls.FLAG_CAN_VIEW, False)
|
||||
category.can_edit = json.get(cls.FLAG_CAN_EDIT, False)
|
||||
category.can_admin = json.get(cls.FLAG_CAN_ADMIN, False)
|
||||
return category
|
||||
"""
|
||||
def to_json_str(self):
|
||||
return {
|
||||
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,
|
||||
self.FLAG_DESCRIPTION: self.description[0] if isinstance(self.description, tuple) else self.description,
|
||||
self.ATTR_ID_ACCESS_LEVEL: self.id_access_level_required[0] if isinstance(self.id_access_level_required, tuple) else self.id_access_level_required,
|
||||
self.FLAG_ACCESS_LEVEL_REQUIRED: self.name_access_level_required[0] if isinstance(self.name_access_level_required, tuple) else self.name_access_level_required,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_ACTIVE: self.output_bool(self.active),
|
||||
self.FLAG_CAN_VIEW: self.output_bool(self.can_view),
|
||||
self.FLAG_CAN_EDIT: self.output_bool(self.can_edit),
|
||||
self.FLAG_CAN_ADMIN: self.output_bool(self.can_admin)
|
||||
}
|
||||
"""
|
||||
@staticmethod
|
||||
def output_bool(value):
|
||||
return av.input_bool(value, 'Product_Category bool attribute', 'Product_Category.output_bool')
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_category,
|
||||
'text': self.name
|
||||
}
|
||||
def get_csv_ids_permutation(self):
|
||||
list_ids = []
|
||||
for product in self.products:
|
||||
list_ids += product.get_csv_ids_permutation()
|
||||
return list_ids
|
||||
"""
|
||||
class Filters_Product_Category(BaseModel, Store_Base):
|
||||
ids_product_category: str
|
||||
ids_product: str
|
||||
""
|
||||
def __new__(cls, product_ids, product_categories):
|
||||
_m = 'Parameters_Product.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
# av.val_list_instances(product_ids, 'product_ids', _m, str, v_arg_type=v_arg_type)
|
||||
# av.val_list_instances(product_categories, 'product_categories', _m, Product_Category_Enum, v_arg_type=v_arg_type)
|
||||
av.val_str(product_ids, 'product_ids', _m, v_arg_type=v_arg_type)
|
||||
av.val_str(product_categories, 'product_categories', _m, v_arg_type=v_arg_type)
|
||||
return super(Parameters_Product_Category, cls).__new__(cls)
|
||||
""
|
||||
def __init__(self, ids_product, ids_product_category):
|
||||
super().__init__(ids_product=ids_product, ids_product_category=ids_product_category)
|
||||
""
|
||||
# Constructor
|
||||
self.ids = product_ids
|
||||
self.categories = product_categories
|
||||
""
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return Filters_Product_Category(
|
||||
ids_product_category = '',
|
||||
ids_product = ''
|
||||
)
|
||||
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
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
filters = cls()
|
||||
filters.ids_product_category = json['a_ids_product_category'],
|
||||
filters.ids_product = json['a_ids_product']
|
||||
|
||||
|
||||
class Filters_Product_Category(Get_Many_Parameters_Base):
|
||||
FLAG_IS_NOT_EMPTY: ClassVar[str] = 'is_not_empty'
|
||||
is_not_empty: bool
|
||||
active: bool
|
||||
def __init__(self, is_not_empty, active):
|
||||
super().__init__(is_not_empty=is_not_empty, active=active)
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls(
|
||||
is_not_empty = False,
|
||||
active = True
|
||||
)
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.FLAG_IS_NOT_EMPTY: self.is_not_empty,
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
return cls(
|
||||
is_not_empty = json['is_not_empty'],
|
||||
active = json['active']
|
||||
)
|
||||
@classmethod
|
||||
def from_form(cls, form):
|
||||
return cls(
|
||||
is_not_empty = av.input_bool(form.is_not_empty.data, 'is_not_empty', 'Filters_Product_Category.from_form'),
|
||||
active = av.input_bool(form.active.data, 'active', 'Filters_Product_Category.from_form')
|
||||
)
|
||||
"""
|
||||
|
||||
class Product_Category_Container(Store_Base):
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = ''
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.FLAG_ROWS
|
||||
categories: list
|
||||
def __init__(self):
|
||||
self.categories = []
|
||||
def add_product_category(self, category):
|
||||
av.val_instance(category, 'category', 'Container_Product_Categories.add_product_category', Product_Category)
|
||||
self.categories.append(category)
|
||||
def get_index_category_from_id(self, id_category):
|
||||
for index_category in range(len(self.categories)):
|
||||
category = self.categories[index_category]
|
||||
if category.id_category == id_category:
|
||||
return index_category
|
||||
raise ValueError(f"{av.error_msg_str(id_category, 'id_category', 'Container_Product_Categories.get_index_category_from_id', int)}\nID not in list")
|
||||
def get_index_category_from_id_permutation(self, id_permutation):
|
||||
for index_category in range(len(self.categories)):
|
||||
category = self.categories[index_category]
|
||||
try:
|
||||
index_product = category.get_index_product_from_id_permutation(id_permutation)
|
||||
return index_category
|
||||
except:
|
||||
pass
|
||||
raise ValueError(f"{av.error_msg_str(id_permutation, 'id_permutation', 'Container_Product_Categories.get_index_category_from_id_permutation', int)}. Permutation ID not in list")
|
||||
def add_product(self, product):
|
||||
av.val_instance(product, 'product', 'Container_Product_Categories.add_product', Product)
|
||||
index_category = self.get_index_category_from_id(product.id_category)
|
||||
self.categories[index_category].add_product(product)
|
||||
def add_product_permutation(self, permutation):
|
||||
av.val_instance(permutation, 'permutation', 'Container_Product_Categories.add_product_permutation', Product_Permutation)
|
||||
index_category = self.get_index_category_from_id(permutation.id_category)
|
||||
self.categories[index_category].add_product_permutation(permutation)
|
||||
"""
|
||||
def add_product_variation(self, variation):
|
||||
av.val_instance(variation, 'variation', 'Container_Product_Categories.add_product_variation', Product_Variation)
|
||||
index_category = self.get_index_category_from_id(variation.id_category)
|
||||
self.categories[index_category].add_product_variation(variation)
|
||||
"""
|
||||
def add_product_variation_type(self, variation_type):
|
||||
av.val_instance(variation_type, 'variation_type', 'Container_Product_Categories.add_product_variation_type', Product_Variation_Type)
|
||||
variation = variation_type.variations[0]
|
||||
index_category = self.get_index_category_from_id(variation.id_category)
|
||||
self.categories[index_category].add_product_variation_type(variation_type)
|
||||
def add_product_price(self, price):
|
||||
av.val_instance(price, 'price', 'Container_Product_Categories.add_product_price', Product_Price)
|
||||
index_category = self.get_index_category_from_id(price.id_category)
|
||||
self.categories[index_category].add_product_price(price)
|
||||
def add_product_image(self, image):
|
||||
av.val_instance(image, 'image', 'Container_Product_Categories.add_product_image', Image)
|
||||
index_category = self.get_index_category_from_id(image.id_category)
|
||||
self.categories[index_category].add_product_image(image)
|
||||
def add_delivery_option(self, delivery_option):
|
||||
av.val_instance(delivery_option, 'delivery_option', 'Container_Product_Categories.add_delivery_option', Delivery_Option)
|
||||
index_category = self.get_index_category_from_id(delivery_option.id_category)
|
||||
self.categories[index_category].add_delivery_option(delivery_option)
|
||||
def add_product_price_discount(self, discount):
|
||||
av.val_instance(discount, 'discount', 'Container_Product_Categories.add_product_price_discount', Discount)
|
||||
index_category = self.get_index_category_from_id(discount.id_category)
|
||||
self.categories[index_category].add_product_price_discount(discount)
|
||||
def add_stock_item(self, stock_item):
|
||||
av.val_instance(stock_item, 'stock_item', 'Container_Product_Categories.add_stock_item', Stock_Item)
|
||||
index_category = self.get_index_category_from_id(stock_item.id_category)
|
||||
self.categories[index_category].add_stock_item(stock_item)
|
||||
def get_all_product_variation_trees(self):
|
||||
for category in self.categories:
|
||||
category.get_all_product_variation_trees()
|
||||
def __repr__(self):
|
||||
return f'categories: {self.categories}'
|
||||
"""
|
||||
def get_permutation_first(self):
|
||||
Helper_App.console_log(f'getting first permutation from category list')
|
||||
if not (len(self.categories) == 0):
|
||||
Helper_App.console_log(f'getting first permutation from category')
|
||||
return None if len(self.categories) == 0 else self.categories[0].get_permutation_first()
|
||||
"""
|
||||
def get_category_count(self):
|
||||
return len(self.categories)
|
||||
def to_permutation_row_list(self):
|
||||
list_rows = []
|
||||
for category in self.categories:
|
||||
list_rows += category.to_permutation_row_list()
|
||||
return list_rows
|
||||
def to_category_option_list(self):
|
||||
list_categories = []
|
||||
for category in self.categories:
|
||||
list_categories.append({'value': category.id_category, 'text': category.name})
|
||||
return list_categories
|
||||
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:
|
||||
dict_lists_products[category.id_category] = category.to_product_option_list()
|
||||
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]
|
||||
}
|
||||
"""
|
||||
def to_json_str(self):
|
||||
return {
|
||||
f'{self.FLAG_ROWS}': [category.to_json_str() for category in self.categories]
|
||||
}
|
||||
"""
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
return None
|
||||
def to_json_option(self):
|
||||
return None
|
||||
def to_temporary_record(self):
|
||||
excluded_attributes = {
|
||||
column.name: getattr(self, column.name)
|
||||
for column in self.__table__.columns
|
||||
if column.name not in ['created_on', 'created_by']
|
||||
}
|
||||
return self.to_object_with_missing_attributes(excluded_attributes)
|
||||
def get_csv_ids_permutation(self):
|
||||
list_ids = []
|
||||
for category in self.categories:
|
||||
list_ids += category.get_csv_ids_permutation()
|
||||
return ','.join(list_ids)
|
||||
|
||||
|
||||
"""
|
||||
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, Store_Base):
|
||||
__tablename__ = 'Shop_Product_Category_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_category: int = db.Column(db.Integer)
|
||||
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.String(36))
|
||||
# created_on: datetime = db.Column(db.DateTime)
|
||||
# created_by: int = db.Column(db.Integer)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@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
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.__dict__)
|
||||
617
business_objects/store/product_permutation.py
Normal file
617
business_objects/store/product_permutation.py
Normal file
@@ -0,0 +1,617 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Permutation Business Object
|
||||
|
||||
Description:
|
||||
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
|
||||
from business_objects.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
|
||||
from business_objects.store.product_price import Product_Price
|
||||
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
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from datetime import datetime, timedelta
|
||||
import locale
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
class Product_Permutation(db.Model, Store_Base):
|
||||
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_PROFIT_LOCAL_MIN = 'profit_local_min'
|
||||
FLAG_HAS_VARIATIONS = 'has_variations'
|
||||
FLAG_LATENCY_MANUFACTURE = 'latency_manufacture'
|
||||
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_permutation = db.Column(db.Integer, primary_key=True)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
csv_id_pairs_variation = db.Column(db.String(4000))
|
||||
# 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_VAT_excl = db.Column(db.Float)
|
||||
cost_local_VAT_incl = db.Column(db.Float)
|
||||
profit_local_min = db.Column(db.Float)
|
||||
has_variations = db.Column(db.Boolean)
|
||||
latency_manufacture = 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_stock = db.Column(db.Float)
|
||||
is_subscription = db.Column(db.Boolean)
|
||||
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)
|
||||
can_view = db.Column(db.Boolean)
|
||||
can_edit = db.Column(db.Boolean)
|
||||
can_admin = db.Column(db.Boolean)
|
||||
# form_basket_add: Form_Basket_Add
|
||||
# form_basket_edit: Form_Basket_Edit
|
||||
# is_unavailable_in_currency_or_region: bool
|
||||
# is_available: bool
|
||||
# variation_tree
|
||||
|
||||
def __init__(self):
|
||||
self.prices = []
|
||||
self.price_index = {}
|
||||
self.images = []
|
||||
self.image_index = {}
|
||||
self.delivery_options = []
|
||||
self.delivery_option_index = {}
|
||||
self.discounts = []
|
||||
self.discount_index = {}
|
||||
self.stock_items = []
|
||||
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
|
||||
# self.variations = []
|
||||
@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'
|
||||
Helper_App.console_log(f'query_row: {query_row}')
|
||||
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_VAT_excl = query_row[4]
|
||||
permutation.cost_local_VAT_incl = query_row[5]
|
||||
permutation.currency_cost = Currency.from_DB_get_many_product_catalogue_product_permutation(query_row)
|
||||
permutation.profit_local_min = query_row[9]
|
||||
permutation.latency_manufacture = query_row[10]
|
||||
permutation.id_unit_measurement_quantity = query_row[11]
|
||||
permutation.symbol_unit_measurement_quantity = query_row[12]
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_quantity = av.input_bool(query_row[13], 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[14]
|
||||
permutation.name_plural_unit_measurement_quantity = query_row[15]
|
||||
permutation.count_unit_measurement_per_quantity_step = query_row[16]
|
||||
permutation.quantity_min = query_row[17]
|
||||
permutation.quantity_max = query_row[18]
|
||||
permutation.quantity_stock = query_row[19]
|
||||
permutation.is_subscription = av.input_bool(query_row[20], "is_subscription", _m, v_arg_type=v_arg_type)
|
||||
permutation.id_unit_measurement_interval_recurrence = query_row[21]
|
||||
permutation.symbol_unit_measurement_interval_recurrence = query_row[22]
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_recurrence = av.input_bool(query_row[23], 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[24]
|
||||
permutation.name_plural_unit_measurement_interval_recurrence = query_row[25]
|
||||
permutation.count_interval_recurrence = query_row[26]
|
||||
permutation.id_stripe_product = query_row[27]
|
||||
permutation.does_expire_faster_once_unsealed = av.input_bool(query_row[28], "does_expire_faster_once_unsealed", _m, v_arg_type=v_arg_type)
|
||||
permutation.id_unit_measurement_interval_expiration_unsealed = query_row[29]
|
||||
permutation.symbol_unit_measurement_interval_expiration_unsealed = query_row[30]
|
||||
permutation.symbol_is_suffix_not_prefix_unit_measurement_interval_expiration_unsealed = av.input_bool(query_row[31], 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[32]
|
||||
permutation.name_plural_unit_measurement_interval_expiration_unsealed = query_row[33]
|
||||
permutation.count_interval_expiration_unsealed = query_row[34]
|
||||
permutation.has_variations = av.input_bool(query_row[35], cls.FLAG_HAS_VARIATIONS, _m, v_arg_type=v_arg_type)
|
||||
permutation.active = av.input_bool(query_row[36], cls.FLAG_ACTIVE, _m, v_arg_type=v_arg_type)
|
||||
# permutation.display_order = query_row[27]
|
||||
permutation.can_view = av.input_bool(query_row[37], "can_view", _m, v_arg_type=v_arg_type)
|
||||
permutation.can_edit = av.input_bool(query_row[38], "can_edit", _m, v_arg_type=v_arg_type)
|
||||
permutation.can_admin = av.input_bool(query_row[39], "can_admin", _m, v_arg_type=v_arg_type)
|
||||
return permutation
|
||||
|
||||
def from_DB_Stripe_product(query_row):
|
||||
_m = 'Product_Permutation.from_DB_Stripe_product'
|
||||
v_arg_type = 'class attribute'
|
||||
permutation = Product_Permutation()
|
||||
permutation.id_product = query_row[0]
|
||||
# permutation.name = query_row[1]
|
||||
permutation.description = query_row[2]
|
||||
return permutation
|
||||
|
||||
def from_DB_Stripe_price(query_row):
|
||||
_m = 'Product_Permutation.from_DB_Stripe_price'
|
||||
v_arg_type = 'class attribute'
|
||||
permutation = Product_Permutation()
|
||||
permutation.id_product = query_row[0]
|
||||
# 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_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):
|
||||
_m = 'Product_Permutation.from_json'
|
||||
v_arg_type = 'class attribute'
|
||||
permutation = Product_Permutation()
|
||||
permutation.id_product = json_basket_item[key_id_product]
|
||||
permutation.id_permutation = json_basket_item[key_id_permutation]
|
||||
return permutation
|
||||
"""
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = f'{cls.__name__}.from_json'
|
||||
permutation = cls()
|
||||
permutation.id_permutation = json[cls.ATTR_ID_PRODUCT_PERMUTATION]
|
||||
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_VAT_excl = json.get(cls.FLAG_COST_UNIT_LOCAL_VAT_EXCL, None)
|
||||
permutation.cost_local_VAT_incl = json.get(cls.FLAG_COST_UNIT_LOCAL_VAT_INCL, None)
|
||||
permutation.currency_cost = Currency.from_json(json, '_cost')
|
||||
permutation.profit_local_min = json[cls.FLAG_PROFIT_LOCAL_MIN]
|
||||
permutation.latency_manufacture = json[cls.FLAG_LATENCY_MANUFACTURE]
|
||||
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.csv_id_pairs_variation = json[cls.FLAG_PRODUCT_VARIATIONS]
|
||||
permutation.variation_tree = Product_Variation_Tree.from_json_str(permutation.csv_id_pairs_variation)
|
||||
"""
|
||||
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 {
|
||||
**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_UNIT_LOCAL_VAT_EXCL: self.cost_local_VAT_excl,
|
||||
self.FLAG_COST_UNIT_LOCAL_VAT_INCL: self.cost_local_VAT_incl,
|
||||
self.FLAG_CURRENCY_COST: self.currency_cost.to_json(),
|
||||
self.FLAG_PROFIT_LOCAL_MIN: self.profit_local_min,
|
||||
self.FLAG_LATENCY_MANUFACTURE: self.latency_manufacture,
|
||||
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_VARIATIONS: [] if self.variation_tree is None else [variation_type.to_json() for variation_type in self.variation_tree.get_product_variation_types()],
|
||||
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):
|
||||
return len(self.prices) > 0
|
||||
def get_price(self):
|
||||
return self.prices[0]
|
||||
|
||||
def output_delivery_date(self):
|
||||
return (datetime.now() + timedelta(days=self.latency_manufacture)).strftime('%A, %d %B %Y')
|
||||
|
||||
"""
|
||||
def output_lead_time(self):
|
||||
return '1 day' if self.latency_manufacture == 1 else f'{self.latency_manufacture} days'
|
||||
|
||||
def output_price(self, is_included_VAT):
|
||||
if self.is_unavailable_in_currency_or_region:
|
||||
return 'Not available in currency and region'
|
||||
if not self.is_available:
|
||||
return 'Not available'
|
||||
price = self.get_price()
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
if is_included_VAT:
|
||||
return f'{price.symbol_currency} {locale.format_string("%d", price.value_local_VAT_incl, grouping=True)}'
|
||||
else:
|
||||
return f'{price.symbol_currency} {locale.format_string("%d", price.value_local_VAT_excl, grouping=True)}'
|
||||
def output_variations(self):
|
||||
if not self.has_variations: return ''
|
||||
return '\n'.join([f'{variation.name_variation_type}: {variation.name_variation}' for variation in self.variations])
|
||||
def output_variations_jsonify(self):
|
||||
if not self.has_variations: return ''
|
||||
return ','.join([f'{variation.id_type}: {variation.id_variation}' for variation in self.variations])
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return f'''Product_Permutation
|
||||
id_permutation: {self.id_permutation}
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
description: {self.description}
|
||||
cost_local_VAT_excl: {self.cost_local_VAT_excl}
|
||||
cost_local_VAT_incl: {self.cost_local_VAT_incl}
|
||||
currency_cost: {self.currency_cost}
|
||||
latency_manufacture: {self.latency_manufacture}
|
||||
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_stock: {self.quantity_stock}
|
||||
is_subscription: {self.is_subscription}
|
||||
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}
|
||||
csv_id_pairs_variation: {self.csv_id_pairs_variation}
|
||||
can_view: {self.can_view}
|
||||
can_edit: {self.can_edit}
|
||||
can_admin: {self.can_admin}
|
||||
variation tree: {self.variation_tree}
|
||||
images: {self.images}
|
||||
delivery_options: {self.delivery_options}
|
||||
prices: {self.prices}
|
||||
'''
|
||||
"""
|
||||
price_GBP_full: {self.price_GBP_full}
|
||||
price_GBP_min: {self.price_GBP_min}
|
||||
"""
|
||||
"""
|
||||
def add_product_variation(self, variation):
|
||||
_m = 'Product_Permutation.add_product_variation'
|
||||
""
|
||||
av.val_instance(variation, 'variation', _m, Product_Variation)
|
||||
try:
|
||||
self.variation_index[variation.id_variation]
|
||||
raise ValueError(f"{av.error_msg_str(variation, 'variation', _m, Product_Variation)}\nProduct_Variation already in product.")
|
||||
except KeyError:
|
||||
self.variation_index[variation.id_variation] = len(self.variations)
|
||||
self.variations.append(variation)
|
||||
""
|
||||
if self.variation_tree is None:
|
||||
self.variation_tree = Product_Variation_Tree.from_product_variation(variation)
|
||||
else:
|
||||
self.variation_tree.add_product_variation(variation)
|
||||
"""
|
||||
def add_product_variation_type(self, variation_type):
|
||||
_m = 'Product_Permutation.add_product_variation_type'
|
||||
if self.variation_tree is None:
|
||||
self.variation_tree = Product_Variation_Tree.from_product_variation_type(variation_type)
|
||||
else:
|
||||
self.variation_tree.add_product_variation_type(variation_type)
|
||||
def add_product_price(self, price):
|
||||
_m = 'Product_Permutation.add_product_price'
|
||||
av.val_instance(price, 'price', _m, Product_Price)
|
||||
try:
|
||||
self.price_index[price.display_order]
|
||||
raise ValueError(f"{av.error_msg_str(price, 'price', _m, Product_Price)}\nPrice already in product.")
|
||||
except KeyError:
|
||||
self.price_index[price.display_order] = len(self.prices)
|
||||
self.prices.append(price)
|
||||
def add_product_image(self, image):
|
||||
_m = 'Product_Permutation.add_product_image'
|
||||
av.val_instance(image, 'image', _m, Image)
|
||||
try:
|
||||
self.image_index[image.id_image]
|
||||
raise ValueError(f"{av.error_msg_str(image, 'image', _m, Image)}\nImage already in product.")
|
||||
except KeyError:
|
||||
self.image_index[image.id_image] = len(self.images)
|
||||
self.images.append(image)
|
||||
def add_delivery_option(self, delivery_option):
|
||||
_m = 'Product_Permutation.add_delivery_option'
|
||||
av.val_instance(delivery_option, 'delivery_option', _m, Delivery_Option)
|
||||
try:
|
||||
self.delivery_option_index[delivery_option.id_option]
|
||||
raise ValueError(f"{av.error_msg_str(delivery_option, 'delivery_option', _m, Delivery_Option)}\nDelivery_Option already in product.")
|
||||
except KeyError:
|
||||
self.delivery_option_index[delivery_option.id_option] = len(self.delivery_options)
|
||||
self.delivery_options.append(delivery_option)
|
||||
def add_product_price_discount(self, discount):
|
||||
_m = 'Product_Permutation.add_product_price_discount'
|
||||
av.val_instance(discount, 'discount', _m, Discount)
|
||||
try:
|
||||
self.discount_index[discount.display_order]
|
||||
raise ValueError(f"{av.error_msg_str(discount, 'discount', _m, Discount)}\nDiscount already in product.")
|
||||
except KeyError:
|
||||
self.discount_index[discount.display_order] = len(self.discounts)
|
||||
self.discounts.append(discount)
|
||||
|
||||
def add_stock_item(self, stock_item):
|
||||
av.val_instance(stock_item, 'stock_item', 'Product_Permutation.add_stock_item', Stock_Item)
|
||||
self.stock_items.append(stock_item)
|
||||
|
||||
def get_image_from_index(self, index_image):
|
||||
try:
|
||||
return self.images[index_image]
|
||||
except:
|
||||
raise IndexError(f"Invalid image index: {index_image}")
|
||||
|
||||
def get_price_from_code_currency(self, code_currency):
|
||||
for price in self.prices:
|
||||
if price.code_currency == code_currency:
|
||||
return price
|
||||
|
||||
def to_row_permutation(self):
|
||||
a = {
|
||||
Product_Permutation.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
|
||||
Product_Permutation.ATTR_ID_PRODUCT: self.id_product,
|
||||
Product_Permutation.ATTR_ID_PRODUCT_VARIATION: self.output_variations(),
|
||||
Product_Permutation.FLAG_QUANTITY_STOCK: self.quantity_stock,
|
||||
Product_Permutation.FLAG_QUANTITY_MIN: self.quantity_min,
|
||||
Product_Permutation.FLAG_QUANTITY_MAX: self.quantity_max,
|
||||
Product_Permutation.FLAG_COST_UNIT_LOCAL_VAT_EXCL: f"<strong>{self.symbol_currency_cost}</strong>{self.cost_local_VAT_excl}"
|
||||
}
|
||||
Helper_App.console_log('permutation row: ', a)
|
||||
return a
|
||||
|
||||
|
||||
"""
|
||||
class Permutation_Product_Variation_Link(db.Model):
|
||||
id_permutation = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
id_variation = db.Column(db.Integer)
|
||||
|
||||
def from_DB_get_many_product_catalogue(query_row):
|
||||
_m = 'Permutation_Product_Variation_Link.from_DB_get_many_product_catalogue'
|
||||
v_arg_type = 'class attribute'
|
||||
link = Permutation_Product_Variation_Link()
|
||||
link.id_permutation = query_row[0]
|
||||
link.id_product = query_row[1]
|
||||
link.id_category = query_row[2]
|
||||
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_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_permutation: int = db.Column(db.Integer)
|
||||
id_product: int = db.Column(db.Integer)
|
||||
csv_id_pairs_variation: str = db.Column(db.String(4000))
|
||||
description: str = db.Column(db.String(4000))
|
||||
cost_local_VAT_excl: float = db.Column(db.Float)
|
||||
cost_local_VAT_incl: float = db.Column(db.Float)
|
||||
id_currency_cost: int = db.Column(db.Integer)
|
||||
profit_local_min: float = db.Column(db.Float)
|
||||
latency_manufacture: 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))
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_product_permutation(cls, product_permutation):
|
||||
Helper_App.console_log(f'Product_Permutation_Temp.from_product_permutation: {product_permutation}\ntype(cost local): {str(type(product_permutation.cost_local_VAT_excl))}')
|
||||
row = cls()
|
||||
row.id_permutation = product_permutation.id_permutation
|
||||
row.id_product = product_permutation.id_product
|
||||
row.csv_id_pairs_variation = product_permutation.csv_id_pairs_variation
|
||||
row.description = product_permutation.description
|
||||
row.cost_local_VAT_excl = product_permutation.cost_local_VAT_excl if product_permutation.cost_local_VAT_excl != 'None' else None
|
||||
row.cost_local_VAT_incl = product_permutation.cost_local_VAT_incl if product_permutation.cost_local_VAT_incl != 'None' else None
|
||||
row.id_currency_cost = product_permutation.currency_cost.id_currency
|
||||
row.profit_local_min = product_permutation.profit_local_min if product_permutation.profit_local_min != 'None' else None
|
||||
row.latency_manufacture = product_permutation.latency_manufacture
|
||||
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}
|
||||
csv_id_pairs_variation: {self.csv_id_pairs_variation}
|
||||
description: {self.description}
|
||||
cost_local_VAT_excl: {self.cost_local_VAT_excl}
|
||||
cost_local_VAT_incl: {self.cost_local_VAT_incl}
|
||||
id_currency_cost: {self.id_currency_cost}
|
||||
profit_local_min: {self.profit_local_min}
|
||||
latency_manufacture: {self.latency_manufacture}
|
||||
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: int(self.latency_manufacture),
|
||||
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
|
||||
}
|
||||
"""
|
||||
|
||||
106
business_objects/store/product_price.py
Normal file
106
business_objects/store/product_price.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Price Business Object
|
||||
|
||||
Description:
|
||||
Business object for product price
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.currency import Currency
|
||||
from business_objects.region import Region
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
class Product_Price(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_PRODUCT_PRICE
|
||||
NAME_ATTR_OPTION_TEXT = Store_Base.FLAG_TEXT
|
||||
|
||||
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)
|
||||
display_order = db.Column(db.Float)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
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 = 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]
|
||||
price.display_order = query_row[11]
|
||||
return price
|
||||
|
||||
def __repr__(self):
|
||||
return f'''Product_Price
|
||||
id: {self.id_price}
|
||||
id_permutation: {self.id_permutation}
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
currency: {self.currency}
|
||||
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.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(),
|
||||
# Region.ATTR_ID_REGION_DELIVERY: 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
|
||||
def from_json(cls, json):
|
||||
price = cls()
|
||||
price.id_price = json[cls.ATTR_ID_PRODUCT_PRICE]
|
||||
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.currency = Currency.from_json(json)
|
||||
# price.id_region = json[Region.ATTR_ID_REGION_DELIVERY]
|
||||
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]
|
||||
return price
|
||||
217
business_objects/store/product_variation.py
Normal file
217
business_objects/store/product_variation.py
Normal file
@@ -0,0 +1,217 @@
|
||||
"""
|
||||
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.db_base import Get_Many_Parameters_Base
|
||||
from business_objects.store.store_base import Store_Base
|
||||
# from business_objects.store.product_variation_type import Product_Variation_Type
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
from pydantic import BaseModel
|
||||
from itertools import filterfalse
|
||||
from operator import attrgetter
|
||||
|
||||
|
||||
class Product_Variation(db.Model, Store_Base):
|
||||
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)
|
||||
id_type = 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__()
|
||||
self.variation_type = None
|
||||
|
||||
@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
|
||||
|
||||
@classmethod
|
||||
def from_DB_get_many_product_variation(cls, query_row):
|
||||
variation = cls()
|
||||
variation.id_variation = query_row[0]
|
||||
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_PRODUCT_VARIATION]
|
||||
variation.id_type = json[cls.ATTR_ID_PRODUCT_VARIATION_TYPE]
|
||||
variation.code = json[cls.FLAG_CODE]
|
||||
variation.name = json[cls.FLAG_NAME]
|
||||
variation.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
variation.active = 1 if av.input_bool(json[cls.FLAG_ACTIVE], cls.FLAG_ACTIVE, f'{cls.__name__}.from_json') else 0
|
||||
variation.id_permutation = json.get(cls.ATTR_ID_PRODUCT_PERMUTATION, None)
|
||||
variation.id_product = json.get(cls.ATTR_ID_PRODUCT, None)
|
||||
variation.id_category = json.get(cls.ATTR_ID_PRODUCT_CATEGORY, None)
|
||||
return variation
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{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}
|
||||
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,
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_variation,
|
||||
'text': self.name
|
||||
}
|
||||
|
||||
class Parameters_Product_Variation(Get_Many_Parameters_Base):
|
||||
a_get_all_variation_type: bool
|
||||
a_get_inactive_variation_type: bool
|
||||
a_ids_variation_type: str
|
||||
a_get_all_variation: bool
|
||||
a_get_inactive_variation: bool
|
||||
a_ids_variation: str
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls(
|
||||
a_get_all_variation_type = True,
|
||||
a_get_inactive_variation_type = False,
|
||||
a_ids_variation_type = '',
|
||||
a_get_all_variation = True,
|
||||
a_get_inactive_variation = False,
|
||||
a_ids_variation = ''
|
||||
)
|
||||
@classmethod
|
||||
def from_filters_product_variation(cls, form):
|
||||
parameters = cls.get_default()
|
||||
get_inactive = not form.active.data
|
||||
parameters.a_get_inactive_variation_type = get_inactive
|
||||
parameters.a_get_inactive_variation = get_inactive
|
||||
return parameters
|
||||
|
||||
"""
|
||||
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())
|
||||
Helper_App.console_log(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
|
||||
"""
|
||||
|
||||
class Product_Variation_Temp(db.Model, Store_Base):
|
||||
__tablename__ = 'Shop_Variation_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_variation: int = db.Column(db.Integer) # , primary_key=True)
|
||||
id_type: int = db.Column(db.Integer, nullable=False)
|
||||
code: str = db.Column(db.String(50))
|
||||
name: str = db.Column(db.String(255))
|
||||
active: bool = db.Column(db.Boolean)
|
||||
display_order: int = db.Column(db.Integer)
|
||||
guid: str = db.Column(db.String(36))
|
||||
|
||||
def __repr__(self):
|
||||
attrs = '\n'.join(f'{k}={v!r}' for k, v in self.__dict__.items())
|
||||
return f'<{self.__class__.__name__}(\n{attrs}\n)>'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_product_variation(cls, product_variation):
|
||||
row = cls()
|
||||
row.id_variation = product_variation.id_variation
|
||||
row.id_type = product_variation.id_type
|
||||
row.code = product_variation.code
|
||||
row.name = product_variation.name
|
||||
row.active = 1 if av.input_bool(product_variation.active, cls.FLAG_ACTIVE, f'{cls.__name__}.to_json') else 0
|
||||
row.display_order = product_variation.display_order
|
||||
return row
|
||||
def to_json(self):
|
||||
return {
|
||||
'id_variation': self.id_variation,
|
||||
'id_type': self.id_type,
|
||||
'code': self.code,
|
||||
'name': self.name,
|
||||
'active': self.active,
|
||||
'display_order': self.display_order,
|
||||
'guid': self.guid,
|
||||
}
|
||||
161
business_objects/store/product_variation_tree.py
Normal file
161
business_objects/store/product_variation_tree.py
Normal file
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Product Business Object
|
||||
|
||||
Description:
|
||||
Business object for product
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.product_variation import Product_Variation
|
||||
from business_objects.store.product_variation_type import Product_Variation_Type
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
|
||||
|
||||
class Product_Variation_Tree_Node():
|
||||
variation_type: Product_Variation_Type
|
||||
node_parent: None
|
||||
nodes_child: list
|
||||
def __init__(self):
|
||||
self.nodes_child = []
|
||||
def from_variation_type_and_node_parent(variation_type, node_parent):
|
||||
node = Product_Variation_Tree_Node()
|
||||
node.variation_type = variation_type
|
||||
node.node_parent = node_parent
|
||||
return node
|
||||
def from_node_parent(node_parent):
|
||||
node = Product_Variation_Tree_Node()
|
||||
node.node_parent = node_parent
|
||||
return node
|
||||
def add_child(self, node_child):
|
||||
self.nodes_child.append(node_child)
|
||||
def is_leaf(self):
|
||||
return (len(self.nodes_child) == 0)
|
||||
|
||||
class Product_Variation_Tree():
|
||||
node_root: Product_Variation_Tree_Node
|
||||
@classmethod
|
||||
def from_node_root(cls, node_root):
|
||||
tree = cls()
|
||||
tree.node_root = node_root
|
||||
return tree
|
||||
@classmethod
|
||||
def from_variation_type_root(cls, variation_type_root):
|
||||
node_root = Product_Variation_Tree_Node.from_variation_type_and_node_parent(variation_type_root, None)
|
||||
return cls.from_node_root(node_root)
|
||||
def is_equal(self, tree):
|
||||
my_type_list = self.get_product_variation_types()
|
||||
sz_me = len(my_type_list)
|
||||
other_type_list = tree.get_product_variation_types()
|
||||
sz_other = len(other_type_list)
|
||||
is_equal = (sz_me == sz_other)
|
||||
if is_equal:
|
||||
for index_type in range(sz_me):
|
||||
my_variation_type = my_type_list[index_type]
|
||||
other_variation_type = other_type_list[index_type]
|
||||
if my_variation_type.id_type != other_variation_type.id_type:
|
||||
is_equal = False
|
||||
break
|
||||
my_variation = my_variation_type.variations[0]
|
||||
other_variation = other_variation_type.variations[0]
|
||||
if my_variation.id_variation != other_variation.id_variation:
|
||||
is_equal = False
|
||||
break
|
||||
return is_equal
|
||||
@classmethod
|
||||
def from_product_permutation(cls, product_permutation):
|
||||
depth_max = len(product_permutation.variation_types)
|
||||
node_root = Product_Variation_Tree_Node.from_variation_type_and_node_parent(product_permutation.variation_types[0], None)
|
||||
node = node_root
|
||||
for depth in range(depth_max - 1):
|
||||
node = Product_Variation_Tree_Node.from_variation_type_and_node_parent(product_permutation.variation_types[depth + 1], node)
|
||||
return cls.from_node_root(node_root)
|
||||
@classmethod
|
||||
def from_product_variation_type(cls, product_variation_type):
|
||||
node_root = Product_Variation_Tree_Node.from_variation_type_and_node_parent(product_variation_type, None)
|
||||
return cls.from_node_root(node_root)
|
||||
@classmethod
|
||||
def from_product_variation_types(cls, product_variation_types):
|
||||
node_root = Product_Variation_Tree_Node.from_variation_type_and_node_parent(product_variation_types[0], None)
|
||||
tree = cls.from_node_root(node_root)
|
||||
if len(product_variation_types) > 1:
|
||||
for variation_type in product_variation_types[1:]:
|
||||
tree.add_product_variation_type(variation_type)
|
||||
return tree
|
||||
@classmethod
|
||||
def from_json_str(cls, json_str):
|
||||
variation_types = []
|
||||
if json_str is None or json_str == '': return None
|
||||
for json_variation_type in json_str.split(','):
|
||||
parts = json_variation_type.split(':')
|
||||
if len(parts) != 2: continue
|
||||
variation_type = Product_Variation_Type()
|
||||
variation_type.id_type = parts[0]
|
||||
variation = Product_Variation()
|
||||
variation_type.id_variation = parts[1]
|
||||
variation_type.variations = [variation]
|
||||
variation_types.append(variation_type)
|
||||
return cls.from_product_variation_types(variation_types)
|
||||
def get_node_leaf(self):
|
||||
node = self.node_root
|
||||
at_leaf_node = node.is_leaf()
|
||||
while not at_leaf_node:
|
||||
node = node.nodes_child[0]
|
||||
at_leaf_node = node.is_leaf()
|
||||
return node
|
||||
def add_product_variation_type(self, variation_type):
|
||||
node_leaf = self.get_node_leaf()
|
||||
node_new = Product_Variation_Tree_Node.from_variation_type_and_node_parent(variation_type, node_leaf)
|
||||
node_leaf.add_child(node_new)
|
||||
def get_product_variation_types(self):
|
||||
types = []
|
||||
node = self.node_root
|
||||
at_leaf_node = node.is_leaf()
|
||||
while not at_leaf_node:
|
||||
types.append(node.variation_type)
|
||||
node = node.nodes_child[0]
|
||||
at_leaf_node = node.is_leaf()
|
||||
types.append(node.variation_type)
|
||||
return types
|
||||
"""
|
||||
def get_product_variations(self):
|
||||
variations = []
|
||||
node = self.node_root
|
||||
at_leaf_node = node.is_leaf()
|
||||
variations.append(node.variation)
|
||||
while not at_leaf_node:
|
||||
node = node.nodes_child[0]
|
||||
at_leaf_node = node.is_leaf()
|
||||
variations.append(node.variation)
|
||||
return variations
|
||||
"""
|
||||
def to_preview_str(self):
|
||||
Helper_App.console_log(f'Product_Variation_Tree.to_preview_str')
|
||||
variation_types = self.get_product_variation_types()
|
||||
Helper_App.console_log(f'variation_types: {variation_types}')
|
||||
preview_str = ''
|
||||
for variation_type in variation_types:
|
||||
is_first = (preview_str == '')
|
||||
preview_str += f'{variation_type.name_singular}: {variation_type.variations[0].name}'
|
||||
if is_first:
|
||||
preview_str += '\n'
|
||||
Helper_App.console_log(f'preview_str: {preview_str}')
|
||||
return preview_str
|
||||
def to_json(self):
|
||||
variation_types = self.get_product_variation_types()
|
||||
json_variation_types = []
|
||||
for variation_type in variation_types:
|
||||
json_variation_types.append(variation_type.to_json())
|
||||
return json_variation_types
|
||||
def to_variation_id_pairs_str(self):
|
||||
variation_types = self.get_product_variation_types()
|
||||
pairs_str = ''
|
||||
for variation_type in variation_types:
|
||||
pairs_str += f'{variation_type.id_type}:{variation_type.variations[0].id_variation},'
|
||||
return pairs_str
|
||||
169
business_objects/store/product_variation_type.py
Normal file
169
business_objects/store/product_variation_type.py
Normal file
@@ -0,0 +1,169 @@
|
||||
"""
|
||||
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.product_variation import Product_Variation
|
||||
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
|
||||
|
||||
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__()
|
||||
self.variations = []
|
||||
|
||||
@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')
|
||||
variation_type.variations = [Product_Variation.from_DB_get_many_product_catalogue(query_row)]
|
||||
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.get(cls.FLAG_NAME_SINGULAR, json.get(cls.FLAG_NAME, ''))
|
||||
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]
|
||||
variations = json.get(cls.FLAG_PRODUCT_VARIATIONS, [])
|
||||
if variations is not None and len(variations) > 0:
|
||||
variation_type.variations = [Product_Variation.from_json(variation) for variation in variations]
|
||||
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: self.name_singular,
|
||||
self.FLAG_NAME_PLURAL: self.name_plural,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
self.FLAG_PRODUCT_VARIATIONS: [variation.to_json() for variation in self.variations]
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_type,
|
||||
'text': self.name_singular
|
||||
}
|
||||
"""
|
||||
def get_preview_variations(self):
|
||||
preview = ''
|
||||
if len(self.variations) > 0:
|
||||
# preview = '\n'.join([variation.name for variation in self.variations])
|
||||
preview = '<p>' + '</p><p>'.join([variation.name for variation in self.variations]) + '</p>'
|
||||
return preview
|
||||
def get_str_list_ids_variation(self):
|
||||
if self.variations is None or len(self.variations) == 0:
|
||||
return ''
|
||||
return ','.join([str(variation.id_variation) for variation in self.variations])
|
||||
"""
|
||||
|
||||
class Product_Variation_Type_Temp(db.Model, Store_Base):
|
||||
__tablename__ = 'Shop_Variation_Type_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_type: int = db.Column(db.Integer)
|
||||
code: str = db.Column(db.String(50))
|
||||
name: str = db.Column(db.String(255))
|
||||
name_plural: str = db.Column(db.String(256))
|
||||
active: bool = db.Column(db.Boolean)
|
||||
display_order: int = db.Column(db.Integer)
|
||||
guid: str = db.Column(db.String(36))
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_product_variation_type(cls, product_variation_type):
|
||||
row = cls()
|
||||
row.id_type = product_variation_type.id_type
|
||||
row.code = product_variation_type.code
|
||||
row.name = product_variation_type.name_singular
|
||||
row.name_plural = product_variation_type.name_plural
|
||||
row.active = 1 if av.input_bool(product_variation_type.active, cls.FLAG_ACTIVE, f'{cls.__name__}.from_product_variation_type') else 0
|
||||
row.display_order = product_variation_type.display_order
|
||||
return row
|
||||
def to_json(self):
|
||||
return {
|
||||
'id_type': self.id_type,
|
||||
'code': self.code,
|
||||
'name': self.name,
|
||||
'name_plural': self.name_plural,
|
||||
'active': self.active,
|
||||
'display_order': self.display_order,
|
||||
'guid': self.guid,
|
||||
}
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.__class__.__name__}
|
||||
id_temp: {self.id_temp}
|
||||
id_type: {self.id_type}
|
||||
code: {self.code}
|
||||
name: {self.name}
|
||||
name_plural: {self.name_plural}
|
||||
active: {self.active}
|
||||
display_order: {self.display_order}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
303
business_objects/store/stock_item.py
Normal file
303
business_objects/store/stock_item.py
Normal file
@@ -0,0 +1,303 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Stock Item Business Object
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from lib import data_types
|
||||
from forms.store.stock_item import Filters_Stock_Item
|
||||
from business_objects.db_base import Get_Many_Parameters_Base
|
||||
from business_objects.currency import Currency
|
||||
# from business_objects.discount import Discount
|
||||
from business_objects.store.product_variation_tree import Product_Variation_Tree
|
||||
from business_objects.store.storage_location import Storage_Location
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar, Optional
|
||||
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'
|
||||
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'
|
||||
|
||||
id_stock = 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_location_storage = db.Column(db.Integer)
|
||||
id_plant = db.Column(db.Integer)
|
||||
id_region = db.Column(db.Integer)
|
||||
id_currency_cost = db.Column(db.Integer)
|
||||
cost_local_VAT_excl = db.Column(db.Float)
|
||||
cost_local_VAT_incl = db.Column(db.Float)
|
||||
date_purchased = db.Column(db.DateTime)
|
||||
date_received = db.Column(db.DateTime)
|
||||
is_sealed = db.Column(db.Boolean)
|
||||
date_unsealed = db.Column(db.DateTime)
|
||||
date_expiration = db.Column(db.DateTime)
|
||||
is_consumed = db.Column(db.Boolean)
|
||||
date_consumed = db.Column(db.DateTime)
|
||||
active = db.Column(db.Boolean)
|
||||
"""
|
||||
can_view = db.Column(db.Boolean)
|
||||
can_edit = db.Column(db.Boolean)
|
||||
can_admin = db.Column(db.Boolean)
|
||||
"""
|
||||
# variation_tree: Product_Variation_Tree = None
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.currency_cost = None
|
||||
self.storage_location = None
|
||||
self.variation_tree = None
|
||||
self.has_variations = False
|
||||
|
||||
def from_DB_stock_item(query_row):
|
||||
_m = 'Product.from_DB_stock_item'
|
||||
v_arg_type = 'class attribute'
|
||||
stock_item = Stock_Item()
|
||||
stock_item.id_stock = query_row[0]
|
||||
stock_item.id_permutation = query_row[1]
|
||||
stock_item.id_product = query_row[2]
|
||||
stock_item.id_category = query_row[3]
|
||||
stock_item.id_location_storage = query_row[4]
|
||||
stock_item.storage_location = Storage_Location.from_DB_stock_item(query_row)
|
||||
stock_item.id_currency_cost = query_row[12]
|
||||
stock_item.currency_cost = Currency.from_DB_stock_item(query_row)
|
||||
stock_item.cost_local_VAT_excl = query_row[15]
|
||||
stock_item.cost_local_VAT_incl = query_row[16]
|
||||
stock_item.date_purchased = query_row[17]
|
||||
stock_item.date_received = query_row[18]
|
||||
stock_item.is_sealed = av.input_bool(query_row[19], "is_sealed", _m, v_arg_type=v_arg_type)
|
||||
stock_item.date_unsealed = query_row[20]
|
||||
stock_item.date_expiration = query_row[21]
|
||||
stock_item.is_consumed = av.input_bool(query_row[22], "is_consumed", _m, v_arg_type=v_arg_type)
|
||||
stock_item.date_consumed = query_row[23]
|
||||
stock_item.active = av.input_bool(query_row[24], "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)
|
||||
stock_item.can_admin = av.input_bool(query_row[26], "can_admin", _m, v_arg_type=v_arg_type)
|
||||
"""
|
||||
return stock_item
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
stock_item = cls()
|
||||
stock_item.id_stock = json[cls.ATTR_ID_STOCK_ITEM]
|
||||
stock_item.id_permutation = json.get(cls.ATTR_ID_PRODUCT_PERMUTATION, 0)
|
||||
stock_item.id_product = json[cls.ATTR_ID_PRODUCT]
|
||||
stock_item.id_category = json[cls.ATTR_ID_PRODUCT_CATEGORY]
|
||||
Helper_App.console_log(f'json: {json}\nhalf stock item: {stock_item}')
|
||||
stock_item.variation_tree = Product_Variation_Tree.from_json_str(json[cls.FLAG_PRODUCT_VARIATIONS])
|
||||
stock_item.date_purchased = json[cls.FLAG_DATE_PURCHASED]
|
||||
stock_item.date_received = json[cls.FLAG_DATE_RECEIVED]
|
||||
stock_item.id_location_storage = json[cls.ATTR_ID_STORAGE_LOCATION]
|
||||
stock_item.id_currency_cost = json[cls.ATTR_ID_CURRENCY_COST]
|
||||
stock_item.cost_local_VAT_excl = json[cls.FLAG_COST_UNIT_LOCAL_VAT_EXCL]
|
||||
stock_item.cost_local_VAT_incl = json[cls.FLAG_COST_UNIT_LOCAL_VAT_INCL]
|
||||
stock_item.is_sealed = json[cls.FLAG_IS_SEALED]
|
||||
stock_item.date_unsealed = json[cls.FLAG_DATE_UNSEALED]
|
||||
stock_item.date_expiration = json[cls.FLAG_DATE_EXPIRATION]
|
||||
stock_item.is_consumed = json[cls.FLAG_IS_CONSUMED]
|
||||
stock_item.date_consumed = json[cls.FLAG_DATE_CONSUMED]
|
||||
stock_item.active = json[cls.FLAG_ACTIVE]
|
||||
return stock_item
|
||||
def __repr__(self):
|
||||
return f'''Stock Item
|
||||
id_stock: {self.id_stock}
|
||||
id_permutation: {self.id_permutation}
|
||||
id_product: {self.id_product}
|
||||
id_category: {self.id_category}
|
||||
variations: {self.variation_tree.to_preview_str() if self.variation_tree is not None else 'None'}
|
||||
storage_location: {self.storage_location}
|
||||
currency: {self.currency_cost}
|
||||
cost_local_VAT_excl: {self.cost_local_VAT_excl}
|
||||
cost_local_VAT_incl: {self.cost_local_VAT_incl}
|
||||
date_purchased: {self.date_purchased}
|
||||
date_received: {self.date_received}
|
||||
is_sealed: {self.is_sealed}
|
||||
date_unsealed: {self.date_unsealed}
|
||||
date_expiration: {self.date_expiration}
|
||||
is_consumed: {self.is_consumed}
|
||||
date_consumed: {self.date_consumed}
|
||||
active: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_STOCK_ITEM: self.id_stock,
|
||||
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_STORAGE_LOCATION: self.storage_location.to_json(),
|
||||
self.FLAG_CURRENCY_COST: self.currency_cost.to_json(),
|
||||
self.FLAG_COST_UNIT_LOCAL_VAT_EXCL: self.cost_local_VAT_excl,
|
||||
self.FLAG_COST_UNIT_LOCAL_VAT_INCL: self.cost_local_VAT_incl,
|
||||
}
|
||||
def has_permutations(self):
|
||||
return len(self.permutations) > 0
|
||||
def is_available(self):
|
||||
if len(self.permutations) == 0:
|
||||
return False
|
||||
for permutation in self.permutations:
|
||||
if permutation.is_available():
|
||||
return True
|
||||
return False
|
||||
"""
|
||||
def to_permutation_row_list(self):
|
||||
list_rows = []
|
||||
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
|
||||
}
|
||||
"""
|
||||
|
||||
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_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: Optional[datetime] = None
|
||||
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
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls(
|
||||
# a_id_user = id_user,
|
||||
a_get_all_product_permutation = False,
|
||||
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
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_form_stock_item(cls, form):
|
||||
return cls.get_default()
|
||||
|
||||
|
||||
class Stock_Item_Temp(db.Model, Store_Base):
|
||||
__tablename__: ClassVar[str] = 'Shop_Stock_Item_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_stock: int = db.Column(db.Integer, primary_key=True)
|
||||
# id_category: int = db.Column(db.Integer)
|
||||
id_product: int = db.Column(db.Integer)
|
||||
# has_variations: bool = db.Column(db.Boolean)
|
||||
id_permutation: int = db.Column(db.Integer)
|
||||
id_pairs_variations: str = db.Column(db.String(4000))
|
||||
date_purchased: datetime = db.Column(db.DateTime)
|
||||
date_received: datetime = db.Column(db.DateTime, nullable=True)
|
||||
id_location_storage: int = db.Column(db.Integer)
|
||||
id_currency_cost: int = db.Column(db.Integer)
|
||||
cost_local_VAT_excl: float = db.Column(db.Float)
|
||||
cost_local_VAT_incl: float = db.Column(db.Float)
|
||||
is_sealed: bool = db.Column(db.Boolean)
|
||||
date_unsealed: datetime = db.Column(db.DateTime, nullable=True)
|
||||
date_expiration: datetime = db.Column(db.DateTime, nullable=True)
|
||||
is_consumed: bool = db.Column(db.Boolean)
|
||||
date_consumed: datetime = db.Column(db.DateTime, nullable=True)
|
||||
active: bool = db.Column(db.Boolean)
|
||||
guid: str = db.Column(db.String(36))
|
||||
|
||||
@classmethod
|
||||
def from_stock_item(cls, stock_item):
|
||||
row = cls()
|
||||
row.id_stock = stock_item.id_stock
|
||||
# row.id_category = stock_item.id_category
|
||||
row.id_product = stock_item.id_product
|
||||
row.id_permutation = stock_item.id_permutation
|
||||
# row.has_variations = stock_item.has_variations
|
||||
row.id_pairs_variations = stock_item.variation_tree.to_json_str() if stock_item.variation_tree is not None else ''
|
||||
row.date_purchased = stock_item.date_purchased
|
||||
row.date_received = stock_item.date_received if stock_item.date_received else None
|
||||
row.id_location_storage = stock_item.id_location_storage
|
||||
row.id_currency_cost = stock_item.id_currency_cost
|
||||
row.cost_local_VAT_excl = stock_item.cost_local_VAT_excl
|
||||
row.cost_local_VAT_incl = stock_item.cost_local_VAT_incl
|
||||
row.is_sealed = 1 if stock_item.is_sealed else 0
|
||||
row.date_unsealed = stock_item.date_unsealed if stock_item.date_unsealed else None
|
||||
row.date_expiration = stock_item.date_expiration if stock_item.date_expiration else None
|
||||
row.is_consumed = 1 if stock_item.is_consumed else 0
|
||||
row.date_consumed = stock_item.date_consumed if stock_item.date_consumed else None
|
||||
row.active = 1 if stock_item.active else 0
|
||||
return row
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_stock: {self.id_stock}
|
||||
id_product: {self.id_product}
|
||||
id_permutation: {self.id_permutation}
|
||||
id_pairs_variations: {self.id_pairs_variations}
|
||||
date_purchased: {self.date_purchased}
|
||||
date_received: {self.date_received}
|
||||
id_location_storage: {self.id_location_storage}
|
||||
id_currency_cost: {self.id_currency_cost}
|
||||
cost_local_VAT_excl: {self.cost_local_VAT_excl}
|
||||
cost_local_VAT_incl: {self.cost_local_VAT_incl}
|
||||
is_sealed: {self.is_sealed}
|
||||
date_unsealed: {self.date_unsealed}
|
||||
date_expiration: {self.date_expiration}
|
||||
is_consumed: {self.is_consumed}
|
||||
date_consumed: {self.date_consumed}
|
||||
active: {self.active}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
88
business_objects/store/storage_location.py
Normal file
88
business_objects/store/storage_location.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
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.plant import Plant
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# 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)
|
||||
|
||||
# plant = None
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.plant = None
|
||||
|
||||
@classmethod
|
||||
def from_DB_storage_location(cls, query_row):
|
||||
location = cls()
|
||||
location.id_location = query_row[0]
|
||||
location.id_plant = query_row[1]
|
||||
location.plant = Plant.from_DB_storage_location(query_row)
|
||||
location.code = query_row[4]
|
||||
location.name = query_row[5]
|
||||
location.active = query_row[6]
|
||||
return location
|
||||
@classmethod
|
||||
def from_DB_stock_item(cls, query_row):
|
||||
location = cls()
|
||||
location.id_location = query_row[4]
|
||||
location.id_plant = query_row[5]
|
||||
location.code = query_row[8]
|
||||
location.name = query_row[9]
|
||||
location.plant = Plant.from_DB_stock_item(query_row)
|
||||
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):
|
||||
Helper_App.console_log(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
|
||||
|
||||
def get_full_name(self):
|
||||
return f'{self.plant.name} - {self.name}'
|
||||
129
business_objects/store/store_base.py
Normal file
129
business_objects/store/store_base.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Base Store Business Object
|
||||
|
||||
Description:
|
||||
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
|
||||
from typing import ClassVar
|
||||
|
||||
"""
|
||||
class I_Store_Base():
|
||||
@abstractmethod
|
||||
def __repr__(self):
|
||||
pass
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
@abstractmethod
|
||||
def to_json(self):
|
||||
pass
|
||||
@abstractmethod
|
||||
def to_json_option(self):
|
||||
pass
|
||||
@abstractmethod
|
||||
def test_69 (self):
|
||||
pass
|
||||
""
|
||||
def __init_subclass__(cls, **kwargs):
|
||||
super().__init_subclass__(**kwargs)
|
||||
for name, value in vars(Store_Base).items():
|
||||
if getattr(value, "__isabstractmethod__", False):
|
||||
if name not in cls.__dict__:
|
||||
raise TypeError(f"Can't instantiate class {cls.__name__} "
|
||||
f"without implementation of abstract method {name}")
|
||||
subclass_value = cls.__dict__[name]
|
||||
if (isinstance(value, (staticmethod, classmethod)) and
|
||||
not isinstance(subclass_value, type(value))):
|
||||
raise TypeError(f"Abstract {type(value).__name__} {name} in {cls.__name__} "
|
||||
f"must be implemented as a {type(value).__name__}")
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls is Store_Base:
|
||||
raise TypeError("Can't instantiate abstract class Store_Base directly")
|
||||
return super().__new__(cls)
|
||||
""
|
||||
"""
|
||||
|
||||
class Store_Base(Base):
|
||||
# ATTR_ID_CURRENCY_COST: ClassVar[str] = 'id_currency_cost'
|
||||
ATTR_ID_CUSTOMER: ClassVar[str] = 'id_customer'
|
||||
ATTR_ID_CUSTOMER_ADDRESS: ClassVar[str] = 'id_address'
|
||||
ATTR_ID_CUSTOMER_SALES_ORDER: ClassVar[str] = 'id_customer_sales_order'
|
||||
ATTR_ID_DELIVERY_OPTION: ClassVar[str] = 'id_delivery_option'
|
||||
ATTR_ID_DISCOUNT: ClassVar[str] = 'id_discount'
|
||||
ATTR_ID_IMAGE: ClassVar[str] = 'id_image'
|
||||
ATTR_ID_MANUFACTURING_PURCHASE_ORDER: ClassVar[str] = 'id_order'
|
||||
ATTR_ID_MANUFACTURING_PURCHASE_ORDER_PRODUCT_LINK: ClassVar[str] = 'id_link'
|
||||
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'
|
||||
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_type'
|
||||
ATTR_ID_STOCK_ITEM: ClassVar[str] = 'id_stock_item'
|
||||
ATTR_ID_STORAGE_LOCATION: ClassVar[str] = 'id_location'
|
||||
ATTR_ID_SUPPLIER: ClassVar[str] = 'id_supplier'
|
||||
ATTR_ID_SUPPLIER_ADDRESS: ClassVar[str] = 'id_address'
|
||||
ATTR_ID_SUPPLIER_PURCHASE_ORDER: ClassVar[str] = 'id_order'
|
||||
ATTR_ID_SUPPLIER_PURCHASE_ORDER_PRODUCT_LINK: ClassVar[str] = 'id_link'
|
||||
ATTR_ID_UNIT_MEASUREMENT_LATENCY_MANUFACTURE: ClassVar[str] = 'id_unit_latency_manufacture'
|
||||
ATTR_ID_UNIT_MEASUREMENT_QUANTITY: ClassVar[str] = 'id_unit_quantity'
|
||||
# FLAG_COST_LOCAL: ClassVar[str] = 'cost_local'
|
||||
FLAG_COST_TOTAL_LOCAL_VAT_EXCL: ClassVar[str] = 'cost_total_local_vat_excl'
|
||||
FLAG_COST_TOTAL_LOCAL_VAT_INCL: ClassVar[str] = 'cost_total_local_vat_incl'
|
||||
FLAG_COST_UNIT_LOCAL_VAT_EXCL: ClassVar[str] = 'cost_unit_local_vat_excl'
|
||||
FLAG_COST_UNIT_LOCAL_VAT_INCL: ClassVar[str] = 'cost_unit_local_vat_incl'
|
||||
FLAG_CUSTOMER: ClassVar[str] = 'customer'
|
||||
FLAG_CUSTOMER_ADDRESS: ClassVar[str] = 'customer_address'
|
||||
FLAG_CUSTOMER_SALES_ORDER: ClassVar[str] = 'customer_sales_order'
|
||||
FLAG_DELIVERY_OPTION: ClassVar[str] = 'delivery_option'
|
||||
FLAG_DISCOUNT: ClassVar[str] = 'discount'
|
||||
FLAG_HAS_VARIATIONS: ClassVar[str] = 'has_variations'
|
||||
FLAG_IS_OUT_OF_STOCK: ClassVar[str] = 'is_out_of_stock'
|
||||
FLAG_LATENCY_DELIVERY_DAYS: ClassVar[str] = 'latency_delivery_days'
|
||||
FLAG_LATENCY_MANUFACTURE: ClassVar[str] = 'latency_manufacture'
|
||||
FLAG_MANUFACTURING_PURCHASE_ORDER: ClassVar[str] = 'manufacturing_purchase_order'
|
||||
FLAG_ORDER_ITEMS: ClassVar[str] = 'order_items'
|
||||
FLAG_PLANT: ClassVar[str] = 'plant'
|
||||
FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL: ClassVar[str] = 'price_total_local_vat_excl'
|
||||
FLAG_PRICE_TOTAL_LOCAL_VAT_INCL: ClassVar[str] = 'price_total_local_vat_incl'
|
||||
FLAG_PRICE_UNIT_LOCAL_VAT_EXCL: ClassVar[str] = 'price_unit_local_vat_excl'
|
||||
FLAG_PRICE_UNIT_LOCAL_VAT_INCL: ClassVar[str] = 'price_unit_local_vat_incl'
|
||||
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_QUANTITY_ORDERED: ClassVar[str] = 'quantity_ordered'
|
||||
FLAG_QUANTITY_RECEIVED: ClassVar[str] = 'quantity_received'
|
||||
FLAG_STOCK_ITEM: ClassVar[str] = 'stock_item'
|
||||
FLAG_STORAGE_LOCATION: ClassVar[str] = 'storage_location'
|
||||
FLAG_SUPPLIER: ClassVar[str] = 'supplier'
|
||||
FLAG_SUPPLIER_ADDRESS: ClassVar[str] = 'supplier_address'
|
||||
FLAG_SUPPLIER_PURCHASE_ORDER: ClassVar[str] = 'supplier_purchase_order'
|
||||
FLAG_TEXT: ClassVar[str] = 'text'
|
||||
FLAG_UNIT_MEASUREMENT_LATENCY_MANUFACTURE: ClassVar[str] = 'unit_measurement_latency_manufacture'
|
||||
FLAG_UNIT_MEASUREMENT_QUANTITY: ClassVar[str] = 'unit_measurement_quantity'
|
||||
FLAG_VALUE_TEXT: ClassVar[str] = 'value_text'
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.__dict__)
|
||||
161
business_objects/store/stripe.py
Normal file
161
business_objects/store/stripe.py
Normal file
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Stripe Business Object
|
||||
|
||||
Description:
|
||||
Business objects for Stripe
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from lib import data_types
|
||||
from forms.forms import Form_Basket_Add, Form_Basket_Edit # Form_Product
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from datetime import datetime, timedelta
|
||||
import locale
|
||||
|
||||
class Stripe_Product(db.Model):
|
||||
id_product = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(255))
|
||||
description = db.Column(db.String(4000))
|
||||
price_GBP_full = db.Column(db.Float)
|
||||
id_category = db.Column(db.Integer)
|
||||
lead_time_manuf = 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(255))
|
||||
id_stripe_price = db.Column(db.String(255))
|
||||
is_subscription = db.Column(db.Boolean)
|
||||
name_recurring_interval = db.Column(db.String(255))
|
||||
name_plural_recurring_interval = db.Column(db.String(256))
|
||||
count_recurring_interval = 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)
|
||||
# form_basket_add: Form_Basket_Add
|
||||
# form_basket_edit: Form_Basket_Edit
|
||||
|
||||
def __new__(cls, id, name, description, price_GBP_full, id_category, lead_time_manuf, quantity_min, quantity_max, quantity_step, quantity_stock, id_stripe_product, id_stripe_price,
|
||||
is_subscription, name_recurring_interval, name_plural_recurring_interval, count_recurring_interval, display_order, can_view, can_edit, can_admin):
|
||||
_m = 'Product.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
av.val_int(id, 'id', _m, 0, v_arg_type=v_arg_type)
|
||||
av.val_str(name, 'name', _m, max_len=256, v_arg_type=v_arg_type)
|
||||
av.val_str(description, 'description', _m, max_len=4000, v_arg_type=v_arg_type)
|
||||
av.full_val_float(price_GBP_full, 'price_GBP_full', _m, 0., v_arg_type=v_arg_type)
|
||||
av.val_int(id_category, 'id_category', _m, 0, v_arg_type=v_arg_type)
|
||||
av.val_int(lead_time_manuf, 'lead_time_manuf', _m, 0, v_arg_type=v_arg_type)
|
||||
av.full_val_float(quantity_step, 'quantity_step', _m, 0., v_arg_type=v_arg_type)
|
||||
av.full_val_float(quantity_min, 'quantity_min', _m, quantity_step, v_arg_type=v_arg_type)
|
||||
av.full_val_float(quantity_max, 'quantity_max', _m, quantity_min, v_arg_type=v_arg_type)
|
||||
av.full_val_float(quantity_stock, 'quantity_stock', _m, 0, v_arg_type=v_arg_type)
|
||||
av.val_str(id_stripe_product, 'id_stripe_product', _m, max_len=100, v_arg_type=v_arg_type)
|
||||
av.val_str(id_stripe_price, 'id_stripe_price', _m, max_len=100, v_arg_type=v_arg_type)
|
||||
av.full_val_bool(is_subscription, 'is_subscription', _m, v_arg_type=v_arg_type)
|
||||
Helper_App.console_log(f'is_subscription: {is_subscription}, {av.input_bool(is_subscription, "is_subscription", _m, v_arg_type=v_arg_type)}')
|
||||
is_subscription = av.input_bool(is_subscription, "is_subscription", _m, v_arg_type=v_arg_type)
|
||||
if is_subscription:
|
||||
av.val_str(name_recurring_interval, 'name_recurring_interval', _m, max_len=255, v_arg_type=v_arg_type)
|
||||
av.val_str(name_plural_recurring_interval, 'name_plural_recurring_interval', _m, max_len=256, v_arg_type=v_arg_type)
|
||||
av.val_int(count_recurring_interval, 'count_recurring_interval', _m, 0, v_arg_type=v_arg_type)
|
||||
av.val_int(display_order, 'display_order', _m, v_arg_type=v_arg_type)
|
||||
av.full_val_bool(can_view, 'can_view', _m, v_arg_type=v_arg_type)
|
||||
# can_view = av.input_bool(can_view, "can_view", _m, v_arg_type=v_arg_type)
|
||||
av.full_val_bool(can_edit, 'can_edit', _m, v_arg_type=v_arg_type)
|
||||
# can_edit = av.input_bool(can_edit, "can_edit", _m, v_arg_type=v_arg_type)
|
||||
av.full_val_bool(can_admin, 'can_admin', _m, v_arg_type=v_arg_type)
|
||||
# can_admin = av.input_bool(can_admin, "can_admin", _m, v_arg_type=v_arg_type)
|
||||
return super(Product, cls).__new__(cls) # , id, name, description, price_GBP, id_category, lead_time_manuf, quantity_min, quantity_max, quantity_step, quantity_stock, id_stripe_product, id_stripe_price,
|
||||
# is_subscription, name_recurring_interval, name_plural_recurring_interval, count_recurring_interval, can_view, can_edit, can_admin)
|
||||
|
||||
def __init__(self, id, name, description, price_GBP_full, id_category, lead_time_manuf, quantity_min, quantity_max, quantity_step, quantity_stock, id_stripe_product, id_stripe_price,
|
||||
is_subscription, name_recurring_interval, name_plural_recurring_interval, count_recurring_interval, display_order, can_view, can_edit, can_admin):
|
||||
_m = 'Product.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
self.id_product = id
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.price_GBP_full = price_GBP_full
|
||||
self.id_category = id_category
|
||||
self.lead_time_manuf = lead_time_manuf
|
||||
self.quantity_min = quantity_min
|
||||
self.quantity_max = quantity_max
|
||||
self.quantity_step = quantity_step
|
||||
self.quantity_stock = quantity_stock
|
||||
self.id_stripe_product = id_stripe_product
|
||||
self.id_stripe_price = id_stripe_price
|
||||
self.is_subscription = av.input_bool(is_subscription, "is_subscription", _m, v_arg_type=v_arg_type)
|
||||
self.name_recurring_interval = name_recurring_interval
|
||||
self.name_plural_recurring_interval = name_plural_recurring_interval
|
||||
self.count_recurring_interval = count_recurring_interval
|
||||
self.display_order = display_order
|
||||
self.can_view = av.input_bool(can_view, "can_view", _m, v_arg_type=v_arg_type)
|
||||
self.can_edit = av.input_bool(can_edit, "can_edit", _m, v_arg_type=v_arg_type)
|
||||
self.can_admin = av.input_bool(can_admin, "can_admin", _m, v_arg_type=v_arg_type)
|
||||
self.variations = []
|
||||
self.images = []
|
||||
self.delivery_options = []
|
||||
self.discounts = []
|
||||
self.discount_index = {}
|
||||
super().__init__()
|
||||
self.form_basket_add = Form_Basket_Add()
|
||||
self.form_basket_edit = Form_Basket_Edit()
|
||||
|
||||
def output_lead_time(self):
|
||||
return '1 day' if self.lead_time_manuf == 1 else f'{self.lead_time_manuf} days'
|
||||
|
||||
def output_delivery_date(self):
|
||||
return (datetime.now() + timedelta(days=self.lead_time_manuf)).strftime('%A, %d %B %Y')
|
||||
|
||||
def output_price(self):
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
return locale.format_string("%d", self.price_GBP_full, grouping=True)
|
||||
"""
|
||||
def add_form_basket_add(self):
|
||||
self.form_basket_add = None
|
||||
|
||||
def add_form_basket_edit(self):
|
||||
self.form_basket_edit = None
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''Product
|
||||
id: {self.id_product}
|
||||
name: {self.name}
|
||||
description: {self.description}
|
||||
price_GBP_full: {self.price_GBP_full}
|
||||
id_category: {self.id_category}
|
||||
lead_time_manuf: {self.lead_time_manuf}
|
||||
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}
|
||||
id_stripe_price: {self.id_stripe_price}
|
||||
is_subscription: {self.is_subscription}
|
||||
name_recurring_interval: {self.name_recurring_interval}
|
||||
name_plural_recurring_interval: {self.name_plural_recurring_interval}
|
||||
count_recurring_interval: {self.count_recurring_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}
|
||||
'''
|
||||
|
||||
def add_product_price_discount(self, discount):
|
||||
_m = 'Category.add_product'
|
||||
av.val_instance(discount, 'discount', _m, Discount)
|
||||
# self.product_index.append(len(self.products))
|
||||
self.discount_index[discount.id_discount] = len(self.discounts)
|
||||
self.discounts.append(discount)
|
||||
200
business_objects/store/supplier.py
Normal file
200
business_objects/store/supplier.py
Normal file
@@ -0,0 +1,200 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Supplier Business Object
|
||||
|
||||
Description:
|
||||
Business object for supplier
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.supplier_address import Supplier_Address
|
||||
from business_objects.currency import Currency
|
||||
from business_objects.db_base import Get_Many_Parameters_Base
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Supplier(db.Model, Store_Base):
|
||||
FLAG_DEPARTMENT_CONTACT: ClassVar[str] = 'department_contact'
|
||||
FLAG_NAME_COMPANY: ClassVar[str] = 'name_company'
|
||||
FLAG_NAME_CONTACT: ClassVar[str] = 'name_contact'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_SUPPLIER
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = FLAG_NAME_COMPANY
|
||||
__tablename__ = 'Shop_Supplier'
|
||||
id_supplier = db.Column(db.Integer, primary_key=True)
|
||||
# id_address = db.Column(db.Integer)
|
||||
id_currency = db.Column(db.Integer)
|
||||
name_company = db.Column(db.String(255))
|
||||
name_contact = db.Column(db.String(255))
|
||||
department_contact = db.Column(db.String(255))
|
||||
phone_number = db.Column(db.String(50))
|
||||
fax = db.Column(db.String(50))
|
||||
email = db.Column(db.String(255))
|
||||
website = db.Column(db.String(255))
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
created_by = db.Column(db.Integer)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.addresses = []
|
||||
self.currency = None
|
||||
@classmethod
|
||||
def from_DB_supplier(cls, query_row):
|
||||
supplier = cls()
|
||||
supplier.id_supplier = query_row[0]
|
||||
# supplier.id_address = query_row[1]
|
||||
# supplier.address = Supplier_Address.from_DB_supplier(query_row)
|
||||
supplier.id_currency = query_row[1]
|
||||
supplier.currency = Currency.from_DB_supplier(query_row)
|
||||
supplier.name_company = query_row[4]
|
||||
supplier.name_contact = query_row[5]
|
||||
supplier.department_contact = query_row[6]
|
||||
supplier.phone_number = query_row[7]
|
||||
supplier.fax = query_row[8]
|
||||
supplier.email = query_row[9]
|
||||
supplier.website = query_row[10]
|
||||
supplier.active = av.input_bool(query_row[11], 'active', f'{cls.__name__}.from_DB_supplier')
|
||||
return supplier
|
||||
@classmethod
|
||||
def from_DB_supplier_purchase_order(cls, query_row):
|
||||
supplier = cls()
|
||||
supplier.id_supplier = query_row[1]
|
||||
supplier.name_company = query_row[2]
|
||||
return supplier
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_supplier},
|
||||
id_currency: {self.id_currency},
|
||||
name_company: {self.name_company},
|
||||
name_contact: {self.name_contact},
|
||||
department_contact: {self.department_contact},
|
||||
phone_number: {self.phone_number},
|
||||
fax: {self.fax},
|
||||
email: {self.email},
|
||||
website: {self.website},
|
||||
active: {self.active},
|
||||
addresses: {self.addresses}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_SUPPLIER: self.id_supplier,
|
||||
# self.ATTR_ID_ADDRESS: self.id_address,
|
||||
self.ATTR_ID_CURRENCY: self.id_currency,
|
||||
self.FLAG_NAME_COMPANY: self.name_company,
|
||||
self.FLAG_NAME_CONTACT: self.name_contact,
|
||||
self.FLAG_DEPARTMENT_CONTACT: self.department_contact,
|
||||
self.FLAG_PHONE_NUMBER: self.phone_number,
|
||||
self.FLAG_FAX: self.fax,
|
||||
self.FLAG_EMAIL: self.email,
|
||||
self.FLAG_WEBSITE: self.website,
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json')
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_supplier,
|
||||
'text': self.name_company
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
||||
supplier = cls()
|
||||
supplier.id_supplier = json[cls.ATTR_ID_SUPPLIER]
|
||||
supplier.id_currency = json[cls.ATTR_ID_CURRENCY]
|
||||
supplier.name_company = json[cls.FLAG_NAME_COMPANY]
|
||||
supplier.name_contact = json[cls.FLAG_NAME_CONTACT]
|
||||
supplier.department_contact = json[cls.FLAG_DEPARTMENT_CONTACT]
|
||||
supplier.phone_number = json[cls.FLAG_PHONE_NUMBER]
|
||||
supplier.fax = json[cls.FLAG_FAX]
|
||||
supplier.email = json[cls.FLAG_EMAIL]
|
||||
supplier.website = json[cls.FLAG_WEBSITE]
|
||||
supplier.active = json[cls.FLAG_ACTIVE]
|
||||
addresses = json.get(cls.FLAG_SUPPLIER_ADDRESS, [])
|
||||
supplier.addresses = [Supplier_Address.from_json(address) for address in addresses]
|
||||
return supplier
|
||||
def get_address_active(self):
|
||||
for address in self.addresses:
|
||||
if address.active:
|
||||
return address
|
||||
return Supplier_Address()
|
||||
address = Supplier_Address()
|
||||
address.postcode = ''
|
||||
return address
|
||||
|
||||
class Parameters_Supplier(Get_Many_Parameters_Base):
|
||||
a_get_all_supplier: bool
|
||||
a_get_inactive_supplier: bool
|
||||
a_ids_supplier: str
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls(
|
||||
a_get_all_supplier = True,
|
||||
a_get_inactive_supplier = False,
|
||||
a_ids_supplier = '',
|
||||
)
|
||||
@classmethod
|
||||
def from_filters_supplier(cls, form):
|
||||
parameters = cls.get_default()
|
||||
parameters.a_get_inactive_supplier = form.active.data
|
||||
return parameters
|
||||
|
||||
class Supplier_Temp(db.Model, Store_Base):
|
||||
__tablename__: ClassVar[str] = 'Shop_Supplier_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_supplier: int = db.Column(db.Integer)
|
||||
id_currency: int = db.Column(db.Integer)
|
||||
# id_address: int = db.Column(db.Integer)
|
||||
name_company: str = db.Column(db.String(255))
|
||||
name_contact: str = db.Column(db.String(255))
|
||||
department_contact: str = db.Column(db.String(255))
|
||||
phone_number: str = db.Column(db.String(50))
|
||||
fax: str = db.Column(db.String(50))
|
||||
email: str = db.Column(db.String(255))
|
||||
website: str = db.Column(db.String(255))
|
||||
active: bool = db.Column(db.Boolean)
|
||||
guid: str = db.Column(db.String(36))
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_supplier(cls, supplier):
|
||||
row = cls()
|
||||
row.id_supplier = supplier.id_supplier
|
||||
row.id_currency = supplier.id_currency
|
||||
# row.id_address = supplier.id_address
|
||||
row.name_company = supplier.name_company
|
||||
row.name_contact = supplier.name_contact
|
||||
row.department_contact = supplier.department_contact
|
||||
row.phone_number = supplier.phone_number
|
||||
row.fax = supplier.fax
|
||||
row.email = supplier.email
|
||||
row.website = supplier.website
|
||||
row.active = 1 if supplier.active else 0
|
||||
return row
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_supplier: {self.id_supplier}
|
||||
id_currency: {self.id_currency}
|
||||
name_company: {self.name_company}
|
||||
name_contact: {self.name_contact}
|
||||
department_contact: {self.department_contact}
|
||||
phone_number: {self.phone_number}
|
||||
fax: {self.fax}
|
||||
email: {self.email}
|
||||
website: {self.website}
|
||||
active: {self.active}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
146
business_objects/store/supplier_address.py
Normal file
146
business_objects/store/supplier_address.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Supplier Address Business Object
|
||||
|
||||
Description:
|
||||
Business object for supplier address
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from business_objects.region import Region
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from typing import ClassVar
|
||||
from flask import jsonify
|
||||
|
||||
class Supplier_Address(db.Model, Store_Base):
|
||||
FLAG_ADDRESS_LINE_1: ClassVar[str] = 'address_line_1'
|
||||
FLAG_ADDRESS_LINE_2: ClassVar[str] = 'address_line_2'
|
||||
FLAG_CITY: ClassVar[str] = 'city'
|
||||
FLAG_COUNTY: ClassVar[str] = 'county'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_ADDRESS
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_POSTCODE
|
||||
__tablename__ = 'Shop_Supplier_Address'
|
||||
id_address = db.Column(db.Integer, primary_key=True)
|
||||
id_supplier = db.Column(db.Integer)
|
||||
id_region = db.Column(db.Integer)
|
||||
postcode = db.Column(db.String(20))
|
||||
address_line_1 = db.Column(db.String(256))
|
||||
address_line_2 = db.Column(db.String(256))
|
||||
city = db.Column(db.String(256))
|
||||
county = db.Column(db.String(256))
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
# region = None
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.region = Region()
|
||||
@classmethod
|
||||
def from_DB_supplier(cls, query_row):
|
||||
address = cls()
|
||||
address.id_supplier = query_row[0]
|
||||
address.id_address = query_row[1]
|
||||
address.id_region = query_row[2]
|
||||
address.region = Region.from_DB_supplier(query_row)
|
||||
address.postcode = query_row[4]
|
||||
address.address_line_1 = query_row[5]
|
||||
address.address_line_2 = query_row[6]
|
||||
address.city = query_row[7]
|
||||
address.county = query_row[8]
|
||||
address.active = av.input_bool(query_row[9], 'active', f'{cls.__name__}.from_DB_supplier')
|
||||
|
||||
return address
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_ADDRESS}: {self.id_address}
|
||||
{self.ATTR_ID_SUPPLIER}: {self.id_supplier}
|
||||
{self.FLAG_REGION}: {self.region}
|
||||
{self.FLAG_POSTCODE}: {self.postcode}
|
||||
{self.FLAG_ADDRESS_LINE_1}: {self.address_line_1}
|
||||
{self.FLAG_ADDRESS_LINE_2}: {self.address_line_2}
|
||||
{self.FLAG_CITY}: {self.city}
|
||||
{self.FLAG_COUNTY}: {self.county}
|
||||
{self.FLAG_ACTIVE}: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
Helper_App.console_log(f'{self.__class__.__name__}.to_json\n{self.__dict__}\n{self}')
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_ADDRESS: self.id_address,
|
||||
self.ATTR_ID_SUPPLIER: self.id_supplier,
|
||||
self.FLAG_REGION: self.region.to_json(),
|
||||
self.FLAG_POSTCODE: self.postcode,
|
||||
self.FLAG_ADDRESS_LINE_1: self.address_line_1,
|
||||
self.FLAG_ADDRESS_LINE_2: self.address_line_2,
|
||||
self.FLAG_CITY: self.city,
|
||||
self.FLAG_COUNTY: self.county,
|
||||
self.FLAG_ACTIVE: 1 if av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json') else 0
|
||||
}
|
||||
def to_json_str(self):
|
||||
return jsonify(self.to_json())
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
||||
address = cls()
|
||||
address.id_address = json[cls.ATTR_ID_ADDRESS]
|
||||
address.id_supplier = json[cls.ATTR_ID_SUPPLIER]
|
||||
address.id_region = json[cls.ATTR_ID_REGION]
|
||||
address.region = Region()
|
||||
address.region.id_region = json[cls.ATTR_ID_REGION]
|
||||
address.postcode = json[cls.FLAG_POSTCODE]
|
||||
address.address_line_1 = json[cls.FLAG_ADDRESS_LINE_1]
|
||||
address.address_line_2 = json.get(cls.FLAG_ADDRESS_LINE_2, '')
|
||||
address.city = json[cls.FLAG_CITY]
|
||||
address.county = json[cls.FLAG_COUNTY]
|
||||
address.active = json[cls.FLAG_ACTIVE]
|
||||
return address
|
||||
|
||||
|
||||
class Supplier_Address_Temp(db.Model, Store_Base):
|
||||
__tablename__: ClassVar[str] = 'Shop_Supplier_Address_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_address: int = db.Column(db.Integer, primary_key=True)
|
||||
id_supplier: int = db.Column(db.Integer)
|
||||
id_region: int = db.Column(db.Integer)
|
||||
postcode: str = db.Column(db.String(20))
|
||||
address_line_1: str = db.Column(db.String(256))
|
||||
address_line_2: str = db.Column(db.String(256))
|
||||
city: str = db.Column(db.String(256))
|
||||
county: str = db.Column(db.String(256))
|
||||
active: bool = db.Column(db.Boolean)
|
||||
guid: str = db.Column(db.String(36))
|
||||
@classmethod
|
||||
def from_supplier_address(cls, address):
|
||||
row = cls()
|
||||
row.id_address = address.id_address
|
||||
row.id_supplier = address.id_supplier
|
||||
row.id_region = address.id_region
|
||||
row.postcode = address.postcode
|
||||
row.address_line_1 = address.address_line_1
|
||||
row.address_line_2 = address.address_line_2
|
||||
row.city = address.city
|
||||
row.county = address.county
|
||||
row.active = 1 if address.active else 0
|
||||
return row
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_address: {self.id_address}
|
||||
id_supplier: {self.id_supplier}
|
||||
id_region: {self.id_region}
|
||||
postcode: {self.postcode}
|
||||
address_line_1: {self.address_line_1}
|
||||
address_line_2: {self.address_line_2}
|
||||
city: {self.city}
|
||||
county: {self.county}
|
||||
active: {self.active}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
343
business_objects/store/supplier_purchase_order.py
Normal file
343
business_objects/store/supplier_purchase_order.py
Normal file
@@ -0,0 +1,343 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Supplier_Purchase_Order Business Object
|
||||
|
||||
Description:
|
||||
Business object for supplier_purchase_order
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.currency import Currency
|
||||
from business_objects.db_base import Get_Many_Parameters_Base
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from business_objects.store.supplier import Supplier
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar, Optional
|
||||
from datetime import datetime
|
||||
|
||||
class Supplier_Purchase_Order(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_SUPPLIER_PURCHASE_ORDER
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
__tablename__ = 'Shop_Supplier_Purchase_Order'
|
||||
id_order = db.Column(db.Integer, primary_key=True)
|
||||
id_supplier = db.Column(db.Integer)
|
||||
id_currency = db.Column(db.Integer)
|
||||
cost_total_local_VAT_excl = db.Column(db.Float)
|
||||
cost_total_local_VAT_incl = db.Column(db.Float)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
created_by = db.Column(db.Integer)
|
||||
name = db.Column(db.String(255))
|
||||
# items: list = None
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
self.currency = None
|
||||
self.items = []
|
||||
self.supplier = None
|
||||
@classmethod
|
||||
def from_DB_supplier_purchase_order(cls, query_row):
|
||||
supplier_purchase_order = cls()
|
||||
supplier_purchase_order.id_order = query_row[0]
|
||||
supplier_purchase_order.id_supplier = query_row[1]
|
||||
supplier_purchase_order.supplier = Supplier.from_DB_supplier_purchase_order(query_row)
|
||||
supplier_purchase_order.id_currency = query_row[3]
|
||||
supplier_purchase_order.currency = Currency.from_DB_supplier_purchase_order(query_row)
|
||||
supplier_purchase_order.cost_total_local_VAT_excl = query_row[6]
|
||||
supplier_purchase_order.cost_total_local_VAT_incl = query_row[7]
|
||||
supplier_purchase_order.active = av.input_bool(query_row[8], 'active', f'{cls.__name__}.from_DB_supplier_purchase_order')
|
||||
supplier_purchase_order.created_on = query_row[9]
|
||||
supplier_purchase_order.name = query_row[10]
|
||||
return supplier_purchase_order
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_SUPPLIER_PURCHASE_ORDER}: {self.id_order},
|
||||
{self.ATTR_ID_SUPPLIER}: {self.id_supplier},
|
||||
{self.FLAG_SUPPLIER}: {self.supplier},
|
||||
{self.ATTR_ID_CURRENCY}: {self.id_currency},
|
||||
{self.FLAG_CURRENCY}: {self.currency},
|
||||
{self.FLAG_COST_TOTAL_LOCAL_VAT_EXCL}: {self.cost_total_local_VAT_excl},
|
||||
{self.FLAG_COST_TOTAL_LOCAL_VAT_INCL}: {self.cost_total_local_VAT_incl},
|
||||
{self.FLAG_ACTIVE}: {self.active},
|
||||
{self.FLAG_CREATED_ON}: {self.created_on},
|
||||
{self.FLAG_NAME}: {self.name}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_SUPPLIER_PURCHASE_ORDER: self.id_order,
|
||||
self.ATTR_ID_SUPPLIER: self.id_supplier,
|
||||
self.FLAG_SUPPLIER: self.supplier.to_json(),
|
||||
self.ATTR_ID_CURRENCY: self.id_currency,
|
||||
self.FLAG_CURRENCY: self.currency.to_json(),
|
||||
self.FLAG_COST_TOTAL_LOCAL_VAT_EXCL: self.cost_total_local_VAT_excl,
|
||||
self.FLAG_COST_TOTAL_LOCAL_VAT_INCL: self.cost_total_local_VAT_incl,
|
||||
self.FLAG_ORDER_ITEMS: [item.to_json() for item in self.items],
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
self.FLAG_CREATED_ON: self.created_on,
|
||||
self.FLAG_NAME: self.name,
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_order,
|
||||
'text': self.name,
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
||||
supplier_purchase_order = cls()
|
||||
supplier_purchase_order.id_order = json[cls.ATTR_ID_SUPPLIER_PURCHASE_ORDER]
|
||||
supplier_purchase_order.id_supplier = json[cls.ATTR_ID_SUPPLIER]
|
||||
supplier_purchase_order.id_currency = json[cls.ATTR_ID_CURRENCY]
|
||||
supplier_purchase_order.cost_total_local_VAT_excl = json[cls.FLAG_COST_TOTAL_LOCAL_VAT_EXCL]
|
||||
supplier_purchase_order.cost_total_local_VAT_incl = json[cls.FLAG_COST_TOTAL_LOCAL_VAT_INCL]
|
||||
supplier_purchase_order.items = [Supplier_Purchase_Order_Product_Link.from_json(item) for item in json[cls.FLAG_ORDER_ITEMS]]
|
||||
supplier_purchase_order.active = json[cls.FLAG_ACTIVE]
|
||||
supplier_purchase_order.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||
supplier_purchase_order.created_by = json.get(cls.FLAG_CREATED_BY, None)
|
||||
supplier_purchase_order.name = json.get(cls.FLAG_NAME, None)
|
||||
return supplier_purchase_order
|
||||
|
||||
class Supplier_Purchase_Order_Product_Link(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_SUPPLIER_PURCHASE_ORDER_PRODUCT_LINK
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
__tablename__ = 'Shop_Supplier_Purchase_Order_Product_Link'
|
||||
id_link = db.Column(db.Integer, primary_key=True)
|
||||
id_order = db.Column(db.Integer)
|
||||
id_category = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
csv_id_pairs_variation = db.Column(db.String)
|
||||
id_unit_quantity = db.Column(db.Integer)
|
||||
name_permutation = db.Column(db.String(255))
|
||||
quantity_ordered = db.Column(db.Float)
|
||||
quantity_received = db.Column(db.Float)
|
||||
latency_delivery_days = db.Column(db.Integer)
|
||||
display_order = db.Column(db.Integer)
|
||||
cost_total_local_VAT_excl = db.Column(db.Float)
|
||||
cost_total_local_VAT_incl = db.Column(db.Float)
|
||||
cost_unit_local_VAT_excl = db.Column(db.Float)
|
||||
cost_unit_local_VAT_incl = db.Column(db.Float)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
created_by = db.Column(db.Integer)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Store_Base.__init__(self)
|
||||
# self.unit_quantity = None
|
||||
@classmethod
|
||||
def from_DB_supplier_purchase_order(cls, query_row):
|
||||
link = cls()
|
||||
link.id_link = query_row[0]
|
||||
link.id_order = query_row[1]
|
||||
link.id_category = query_row[2]
|
||||
link.id_product = query_row[3]
|
||||
link.id_permutation = query_row[4]
|
||||
link.name_permutation = query_row[5]
|
||||
link.csv_id_pairs_variation = query_row[6]
|
||||
link.id_unit_quantity = query_row[7]
|
||||
link.quantity_ordered = query_row[8]
|
||||
link.quantity_received = query_row[9]
|
||||
link.latency_delivery_days = query_row[10]
|
||||
link.display_order = query_row[11]
|
||||
link.cost_total_local_VAT_excl = query_row[12]
|
||||
link.cost_total_local_VAT_incl = query_row[13]
|
||||
link.cost_unit_local_VAT_excl = query_row[14]
|
||||
link.cost_unit_local_VAT_incl = query_row[15]
|
||||
link.active = query_row[16]
|
||||
return link
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_SUPPLIER_PURCHASE_ORDER_PRODUCT_LINK}: {self.id_link},
|
||||
{self.ATTR_ID_SUPPLIER_PURCHASE_ORDER}: {self.id_order},
|
||||
{self.ATTR_ID_PRODUCT_CATEGORY}: {self.id_category},
|
||||
{self.ATTR_ID_PRODUCT}: {self.id_product},
|
||||
{self.ATTR_ID_PRODUCT_PERMUTATION}: {self.id_permutation},
|
||||
{self.FLAG_NAME}: {self.name_permutation},
|
||||
{self.FLAG_PRODUCT_VARIATIONS}: {self.csv_id_pairs_variation},
|
||||
{self.ATTR_ID_UNIT_MEASUREMENT_QUANTITY}: {self.id_unit_quantity},
|
||||
{self.FLAG_QUANTITY_ORDERED}: {self.quantity_ordered},
|
||||
{self.FLAG_QUANTITY_RECEIVED}: {self.quantity_received},
|
||||
{self.FLAG_LATENCY_DELIVERY_DAYS}: {self.latency_delivery_days},
|
||||
{self.FLAG_DISPLAY_ORDER}: {self.display_order},
|
||||
{self.FLAG_COST_TOTAL_LOCAL_VAT_EXCL}: {self.cost_total_local_VAT_excl},
|
||||
{self.FLAG_COST_TOTAL_LOCAL_VAT_INCL}: {self.cost_total_local_VAT_incl},
|
||||
{self.FLAG_COST_UNIT_LOCAL_VAT_EXCL}: {self.cost_unit_local_VAT_excl},
|
||||
{self.FLAG_COST_UNIT_LOCAL_VAT_INCL}: {self.cost_unit_local_VAT_incl},
|
||||
{self.FLAG_ACTIVE}: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_SUPPLIER_PURCHASE_ORDER_PRODUCT_LINK: self.id_link,
|
||||
self.ATTR_ID_SUPPLIER_PURCHASE_ORDER: self.id_order,
|
||||
self.ATTR_ID_PRODUCT_CATEGORY: self.id_category,
|
||||
self.ATTR_ID_PRODUCT: self.id_product,
|
||||
self.ATTR_ID_PRODUCT_PERMUTATION: self.id_permutation,
|
||||
self.FLAG_NAME: self.name_permutation,
|
||||
self.FLAG_PRODUCT_VARIATIONS: self.csv_id_pairs_variation,
|
||||
self.ATTR_ID_UNIT_MEASUREMENT_QUANTITY: self.id_unit_quantity,
|
||||
self.FLAG_QUANTITY_ORDERED: self.quantity_ordered,
|
||||
self.FLAG_QUANTITY_RECEIVED: self.quantity_received,
|
||||
self.FLAG_LATENCY_DELIVERY_DAYS: self.latency_delivery_days,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_COST_TOTAL_LOCAL_VAT_EXCL: self.cost_total_local_VAT_excl,
|
||||
self.FLAG_COST_TOTAL_LOCAL_VAT_INCL: self.cost_total_local_VAT_incl,
|
||||
self.FLAG_COST_UNIT_LOCAL_VAT_EXCL: self.cost_unit_local_VAT_excl,
|
||||
self.FLAG_COST_UNIT_LOCAL_VAT_INCL: self.cost_unit_local_VAT_incl,
|
||||
self.FLAG_ACTIVE: av.input_bool(self.active, self.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
}
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_order,
|
||||
'text': self.name_permutation,
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
||||
link = cls()
|
||||
link.id_link = json[cls.ATTR_ID_SUPPLIER_PURCHASE_ORDER_PRODUCT_LINK]
|
||||
link.id_order = json[cls.ATTR_ID_SUPPLIER_PURCHASE_ORDER]
|
||||
link.id_category = json.get(cls.ATTR_ID_PRODUCT_CATEGORY, None)
|
||||
link.id_product = json.get(cls.ATTR_ID_PRODUCT, None)
|
||||
link.id_permutation = json.get(cls.ATTR_ID_PRODUCT_PERMUTATION, None)
|
||||
link.name_permutation = json.get(cls.FLAG_NAME, None)
|
||||
link.csv_id_pairs_variation = json.get(cls.FLAG_PRODUCT_VARIATIONS, '')
|
||||
link.id_unit_quantity = json[cls.ATTR_ID_UNIT_MEASUREMENT_QUANTITY]
|
||||
link.quantity_ordered = json[cls.FLAG_QUANTITY_ORDERED]
|
||||
link.quantity_received = json[cls.FLAG_QUANTITY_RECEIVED]
|
||||
link.latency_delivery_days = json[cls.FLAG_LATENCY_DELIVERY_DAYS]
|
||||
link.display_order = json[cls.FLAG_DISPLAY_ORDER]
|
||||
link.cost_total_local_VAT_excl = json[cls.FLAG_COST_TOTAL_LOCAL_VAT_EXCL]
|
||||
link.cost_total_local_VAT_incl = json[cls.FLAG_COST_TOTAL_LOCAL_VAT_INCL]
|
||||
link.cost_unit_local_VAT_excl = json.get(cls.FLAG_COST_UNIT_LOCAL_VAT_EXCL, None)
|
||||
link.cost_unit_local_VAT_incl = json.get(cls.FLAG_COST_UNIT_LOCAL_VAT_INCL, None)
|
||||
link.active = json[cls.FLAG_ACTIVE]
|
||||
return link
|
||||
|
||||
class Parameters_Supplier_Purchase_Order(Get_Many_Parameters_Base):
|
||||
a_get_all_supplier: bool
|
||||
a_get_inactive_supplier: bool
|
||||
a_ids_supplier: str
|
||||
a_get_all_order: bool
|
||||
a_get_inactive_order: bool
|
||||
a_ids_order: str
|
||||
a_ids_permutation: str
|
||||
a_date_from: Optional[datetime]
|
||||
a_date_to: Optional[datetime]
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls(
|
||||
a_get_all_supplier = True,
|
||||
a_get_inactive_supplier = False,
|
||||
a_ids_supplier = '',
|
||||
a_get_all_order = True,
|
||||
a_get_inactive_order = False,
|
||||
a_ids_order = '',
|
||||
a_ids_permutation = '',
|
||||
a_date_from = None,
|
||||
a_date_to = None
|
||||
)
|
||||
@classmethod
|
||||
def from_filters_supplier_purchase_order(cls, form):
|
||||
parameters = cls.get_default()
|
||||
parameters.a_get_inactive_order = form.active.data
|
||||
parameters.a_date_from = None if form.date_from.data == '' else form.date_from.data
|
||||
parameters.a_date_to = None if form.date_to.data == '' else form.date_to.data
|
||||
return parameters
|
||||
|
||||
class Supplier_Purchase_Order_Temp(db.Model, Store_Base):
|
||||
__tablename__: ClassVar[str] = 'Shop_Supplier_Purchase_Order_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_order: int = db.Column(db.Integer)
|
||||
id_supplier_ordered: int = db.Column(db.Integer)
|
||||
id_currency_cost: int = db.Column(db.Integer)
|
||||
active: bool = db.Column(db.Boolean)
|
||||
guid: str = db.Column(db.String(36))
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_supplier_purchase_order(cls, supplier_purchase_order):
|
||||
row = cls()
|
||||
row.id_order = supplier_purchase_order.id_order
|
||||
row.id_supplier_ordered = supplier_purchase_order.id_supplier
|
||||
row.id_currency_cost = supplier_purchase_order.id_currency
|
||||
row.active = 1 if supplier_purchase_order.active else 0
|
||||
return row
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_order: {self.id_order}
|
||||
id_supplier_ordered: {self.id_supplier_ordered}
|
||||
id_currency_cost: {self.id_currency_cost}
|
||||
active: {self.active}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
|
||||
class Supplier_Purchase_Order_Product_Link_Temp(db.Model, Store_Base):
|
||||
__tablename__: ClassVar[str] = 'Shop_Supplier_Purchase_Order_Product_Link_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp: int = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||
id_link = db.Column(db.Integer)
|
||||
id_order = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
id_permutation = db.Column(db.Integer)
|
||||
csv_list_variations = db.Column(db.String)
|
||||
id_unit_quantity = db.Column(db.Integer)
|
||||
quantity_ordered = db.Column(db.Float)
|
||||
quantity_received = db.Column(db.Float)
|
||||
latency_delivery_days = db.Column(db.Integer)
|
||||
display_order = db.Column(db.Integer)
|
||||
cost_total_local_VAT_excl = db.Column(db.Float)
|
||||
cost_total_local_VAT_incl = db.Column(db.Float)
|
||||
active = db.Column(db.Boolean)
|
||||
guid = db.Column(db.String(36))
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.id_temp = None
|
||||
@classmethod
|
||||
def from_supplier_purchase_order_product_link(cls, supplier_purchase_order_product_link):
|
||||
row = cls()
|
||||
row.id_link = supplier_purchase_order_product_link.id_link
|
||||
row.id_order = supplier_purchase_order_product_link.id_order
|
||||
row.id_product = supplier_purchase_order_product_link.id_product
|
||||
row.id_permutation = supplier_purchase_order_product_link.id_permutation
|
||||
row.csv_list_variations = supplier_purchase_order_product_link.csv_id_pairs_variation
|
||||
row.id_unit_quantity = supplier_purchase_order_product_link.id_unit_quantity
|
||||
row.quantity_ordered = supplier_purchase_order_product_link.quantity_ordered
|
||||
row.quantity_received = supplier_purchase_order_product_link.quantity_received
|
||||
row.latency_delivery_days = supplier_purchase_order_product_link.latency_delivery_days
|
||||
row.display_order = supplier_purchase_order_product_link.display_order
|
||||
row.cost_total_local_VAT_excl = supplier_purchase_order_product_link.cost_total_local_VAT_excl
|
||||
row.cost_total_local_VAT_incl = supplier_purchase_order_product_link.cost_total_local_VAT_incl
|
||||
row.active = 1 if supplier_purchase_order_product_link.active else 0
|
||||
return row
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_link: {self.id_link}
|
||||
id_order: {self.id_order}
|
||||
id_product: {self.id_product}
|
||||
id_permutation: {self.id_permutation}
|
||||
csv_list_variations: {self.csv_list_variations}
|
||||
id_unit_quantity: {self.id_unit_quantity}
|
||||
quantity_ordered: {self.quantity_ordered}
|
||||
quantity_received: {self.quantity_received}
|
||||
latency_delivery_days: {self.latency_delivery_days}
|
||||
display_order: {self.display_order}
|
||||
cost_total_local_VAT_excl: {self.cost_total_local_VAT_excl}
|
||||
cost_total_local_VAT_incl: {self.cost_total_local_VAT_incl}
|
||||
active: {self.active}
|
||||
guid: {self.guid}
|
||||
'''
|
||||
@@ -13,9 +13,11 @@ Initializes the Flask application, sets the configuration based on the environme
|
||||
# IMPORTS
|
||||
# internal
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
from forms.contact import Form_Contact
|
||||
from forms.forms import Form_Contact
|
||||
from models.model_view_admin_home import Model_View_Admin_Home
|
||||
from models.model_view_contact import Model_View_Contact
|
||||
from models.model_view_home import Model_View_Home
|
||||
from models.model_view_services import Model_View_Services
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
@@ -42,7 +44,10 @@ def home():
|
||||
@routes_core.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['GET'])
|
||||
def contact():
|
||||
try:
|
||||
user = DataStore_Base.get_user_session()
|
||||
form = Form_Contact()
|
||||
form.email.data = user.email
|
||||
form.name.data = (user.firstname if user.firstname else '') + (' ' if user.firstname and user.surname else '') + (user.surname if user.surname else '')
|
||||
model = Model_View_Contact(form)
|
||||
html_body = render_template('pages/core/_contact.html', model = model)
|
||||
except Exception as e:
|
||||
@@ -57,17 +62,37 @@ def contact_post():
|
||||
# Handle form submission
|
||||
email = form.email.data
|
||||
CC = form.CC.data # not in use
|
||||
contact_name = form.contact_name.data
|
||||
company_name = form.company_name.data
|
||||
name = form.name.data
|
||||
message = form.message.data
|
||||
receive_marketing = form.receive_marketing.data
|
||||
receive_marketing_text = "I would like to receive marketing emails." if receive_marketing else ""
|
||||
# send email
|
||||
mailItem = Message("PARTS Website Contact Us Message", recipients=[current_app.config['MAIL_CONTACT_PUBLIC']])
|
||||
mailItem.body = f"Dear Lord Edward Middleton-Smith,\n\n{message}\n{receive_marketing_text}\nKind regards,\n{contact_name}\n{company_name}\n{email}"
|
||||
mailItem.body = f"Dear Lord Edward Middleton-Smith,\n\n{message}\n\nKind regards,\n{name}\n{email}"
|
||||
mail.send(mailItem)
|
||||
return "Submitted."
|
||||
return "Invalid. Failed to submit."
|
||||
# html_body = render_template('pages/core/_contact.html', model = model)
|
||||
except Exception as e:
|
||||
return jsonify(error=str(e)), 403
|
||||
|
||||
@routes_core.route(Model_View_Services.HASH_PAGE_SERVICES, methods=['GET', 'POST'])
|
||||
def services():
|
||||
try:
|
||||
model = Model_View_Services()
|
||||
html_body = render_template('pages/core/_services.html', model = model)
|
||||
except Exception as e:
|
||||
return jsonify(error=str(e)), 403
|
||||
return html_body
|
||||
|
||||
@routes_core.route(Model_View_Admin_Home.HASH_PAGE_ADMIN_HOME, methods=['GET', 'POST'])
|
||||
def admin_home():
|
||||
try:
|
||||
model = Model_View_Admin_Home()
|
||||
if not model.is_user_logged_in:
|
||||
# return redirect(url_for('routes_user.login', callback = Model_View_Admin_Home.HASH_PAGE_ADMIN_HOME))
|
||||
return redirect(url_for('routes_core.home'))
|
||||
if not (model.user.can_admin_store or model.user.can_admin_user):
|
||||
return redirect(url_for('routes_core.home'))
|
||||
html_body = render_template('pages/core/_admin_home.html', model = model)
|
||||
except Exception as e:
|
||||
return jsonify(error=str(e)), 403
|
||||
return html_body
|
||||
|
||||
0
controllers/store/__init__.py
Normal file
0
controllers/store/__init__.py
Normal file
BIN
controllers/store/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
controllers/store/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
controllers/store/__pycache__/product.cpython-312.pyc
Normal file
BIN
controllers/store/__pycache__/product.cpython-312.pyc
Normal file
Binary file not shown.
BIN
controllers/store/__pycache__/product_category.cpython-312.pyc
Normal file
BIN
controllers/store/__pycache__/product_category.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
controllers/store/__pycache__/stock_item.cpython-312.pyc
Normal file
BIN
controllers/store/__pycache__/stock_item.cpython-312.pyc
Normal file
Binary file not shown.
BIN
controllers/store/__pycache__/store.cpython-312.pyc
Normal file
BIN
controllers/store/__pycache__/store.cpython-312.pyc
Normal file
Binary file not shown.
BIN
controllers/store/__pycache__/supplier.cpython-312.pyc
Normal file
BIN
controllers/store/__pycache__/supplier.cpython-312.pyc
Normal file
Binary file not shown.
82
controllers/store/manufacturing_purchase_order.py
Normal file
82
controllers/store/manufacturing_purchase_order.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Manufacturing_Purchase_Order Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.manufacturing_purchase_order import Manufacturing_Purchase_Order
|
||||
from forms.store.manufacturing_purchase_order import Filters_Manufacturing_Purchase_Order
|
||||
from models.model_view_store_manufacturing_purchase_order import Model_View_Store_Manufacturing_Purchase_Order
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from datetime import datetime
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
import requests
|
||||
|
||||
routes_store_manufacturing_purchase_order = Blueprint('routes_store_manufacturing_purchase_order', __name__)
|
||||
|
||||
@routes_store_manufacturing_purchase_order.route(Model_View_Store_Manufacturing_Purchase_Order.HASH_PAGE_STORE_MANUFACTURING_PURCHASE_ORDERS, methods=['GET'])
|
||||
def manufacturing_purchase_orders():
|
||||
Helper_App.console_log('manufacturing_purchase_orders')
|
||||
try:
|
||||
form_filters = Filters_Manufacturing_Purchase_Order.from_json(request.args)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error: {e}')
|
||||
form_filters = Filters_Manufacturing_Purchase_Order()
|
||||
Helper_App.console_log(f'form_filters={form_filters}')
|
||||
model = Model_View_Store_Manufacturing_Purchase_Order(form_filters)
|
||||
if not model.is_user_logged_in:
|
||||
return redirect(url_for('routes_core.home'))
|
||||
return render_template('pages/store/_manufacturing_purchase_orders.html', model = model, datetime = datetime)
|
||||
|
||||
|
||||
@routes_store_manufacturing_purchase_order.route(Model_View_Store_Manufacturing_Purchase_Order.HASH_SAVE_STORE_MANUFACTURING_PURCHASE_ORDER, methods=['POST'])
|
||||
def save_manufacturing_purchase_order():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Manufacturing_Purchase_Order.from_json(data[Model_View_Store_Manufacturing_Purchase_Order.FLAG_FORM_FILTERS])
|
||||
Helper_App.console_log(f'form_filters: {form_filters}')
|
||||
|
||||
manufacturing_purchase_orders = data[Model_View_Store_Manufacturing_Purchase_Order.FLAG_MANUFACTURING_PURCHASE_ORDER]
|
||||
if len(manufacturing_purchase_orders) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Manufacturing_Purchase_Order.FLAG_STATUS: Model_View_Store_Manufacturing_Purchase_Order.FLAG_FAILURE,
|
||||
Model_View_Store_Manufacturing_Purchase_Order.FLAG_MESSAGE: f'No stock items.'
|
||||
})
|
||||
Helper_App.console_log(f'manufacturing_purchase_orders={manufacturing_purchase_orders}')
|
||||
objs_manufacturing_purchase_order = []
|
||||
for manufacturing_purchase_order in manufacturing_purchase_orders:
|
||||
objs_manufacturing_purchase_order.append(Manufacturing_Purchase_Order.from_json(manufacturing_purchase_order))
|
||||
Helper_App.console_log(f'objs_manufacturing_purchase_order={objs_manufacturing_purchase_order}')
|
||||
save_errors = Model_View_Store_Manufacturing_Purchase_Order.save_manufacturing_purchase_orders(data.get('comment', 'No comment'), objs_manufacturing_purchase_order)
|
||||
if len(save_errors) > 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Manufacturing_Purchase_Order.FLAG_STATUS: Model_View_Store_Manufacturing_Purchase_Order.FLAG_FAILURE,
|
||||
Model_View_Store_Manufacturing_Purchase_Order.FLAG_MESSAGE: f'Save errors: {save_errors}'
|
||||
})
|
||||
model_return = Model_View_Store_Manufacturing_Purchase_Order(form_filters_old = form_filters)
|
||||
if not model_return.is_user_logged_in:
|
||||
raise Exception('User not logged in.')
|
||||
return jsonify({
|
||||
Model_View_Store_Manufacturing_Purchase_Order.FLAG_STATUS: Model_View_Store_Manufacturing_Purchase_Order.FLAG_SUCCESS,
|
||||
Model_View_Store_Manufacturing_Purchase_Order.FLAG_DATA: model_return.convert_list_objects_to_json(model_return.manufacturing_purchase_orders)
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Manufacturing_Purchase_Order.FLAG_STATUS: Model_View_Store_Manufacturing_Purchase_Order.FLAG_FAILURE,
|
||||
Model_View_Store_Manufacturing_Purchase_Order.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
@@ -1,25 +1,57 @@
|
||||
#! /usr/bin/env python3.6
|
||||
|
||||
"""
|
||||
server.py
|
||||
Stripe Sample.
|
||||
Python 3.6 or newer required.
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App General
|
||||
Feature: App
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
from helpers.helper_app import Helper_App
|
||||
import os
|
||||
import stripe
|
||||
import json
|
||||
import os
|
||||
|
||||
from flask import Flask, render_template, jsonify, request, send_from_directory, redirect
|
||||
from flask import Flask, render_template, render_template_string, jsonify, request, send_from_directory, redirect
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
|
||||
# Setup Stripe python client library.
|
||||
load_dotenv(find_dotenv())
|
||||
|
||||
# VARIABLE INSTANTIATION
|
||||
key_secret = os.environ.get("KEY_SECRET_STRIPE")
|
||||
key_public = os.environ.get("KEY_PUBLIC_STRIPE") # 'pk_test_51OGrxlL7BuLKjoMpfpfw7bSmZZK1MhqMoQ5VhW2jUj7YtoEejO4vqnxKPiqTHHuh9U4qqkywbPCSI9TpFKtr4SYH007KHMWs68'
|
||||
|
||||
# METHODS
|
||||
def create_product_price():
|
||||
Helper_App.console_log(f'stripe.api_key = {stripe.api_key}')
|
||||
starter_subscription = stripe.Product.create(
|
||||
name="Starter Subscription",
|
||||
description="$12/Month subscription",
|
||||
)
|
||||
|
||||
starter_subscription_price = stripe.Price.create(
|
||||
unit_amount=1200,
|
||||
currency="usd",
|
||||
recurring={"interval": "month"},
|
||||
product=starter_subscription['id'],
|
||||
)
|
||||
|
||||
# Save these identifiers
|
||||
Helper_App.console_log(f"Success! Here is your starter subscription product id: {starter_subscription.id}")
|
||||
Helper_App.console_log(f"Success! Here is your starter subscription price id: {starter_subscription_price.id}")
|
||||
|
||||
return starter_subscription_price.id
|
||||
|
||||
def get_file_str(f_address):
|
||||
f = open(f_address)
|
||||
return f.read()
|
||||
|
||||
# Ensure environment variables are set.
|
||||
price = os.getenv('PRICE')
|
||||
if price is None or price == 'price_12345' or price == '':
|
||||
print('You must set a Price ID in .env. Please see the README.')
|
||||
Helper_App.console_log('You must set a Price ID in .env. Please see the README.')
|
||||
exit(0)
|
||||
|
||||
# For sample support and debugging, not required for production:
|
||||
@@ -28,25 +60,29 @@ stripe.set_app_info(
|
||||
version='0.0.1',
|
||||
url='https://github.com/stripe-samples/checkout-one-time-payments')
|
||||
|
||||
stripe.api_version = '2020-08-27'
|
||||
stripe.api_key = os.getenv('STRIPE_KEY_SECRET')
|
||||
# stripe.api_version = '2020-08-27'
|
||||
stripe.api_key = key_secret # os.getenv('KEY_SECRET_STRIPE')
|
||||
|
||||
app_dir = str(os.path.abspath(os.path.join(
|
||||
__file__, "..", "..")))
|
||||
static_dir = str(os.path.abspath(os.path.join(
|
||||
__file__, "..", os.getenv("STATIC_DIR"))))
|
||||
app_dir, os.getenv("STATIC_DIR"))))
|
||||
app = Flask(__name__, static_folder=static_dir,
|
||||
static_url_path="", template_folder=static_dir)
|
||||
|
||||
|
||||
@app.route('/', methods=['GET'])
|
||||
def get_example():
|
||||
return render_template('index.html')
|
||||
# return render_template(f'{app_dir}\\templates\\_home.html') # f'{app_dir}\\templates\\layout.html')
|
||||
# return render_template_string(get_file_str(f'{app_dir}\\templates\\_home.html')) # f'{app_dir}\\templates\\layout.html')
|
||||
return render_template('../templates/_home.html')
|
||||
|
||||
|
||||
@app.route('/config', methods=['GET'])
|
||||
def get_publishable_key():
|
||||
price = stripe.Price.retrieve(os.getenv('PRICE'))
|
||||
return jsonify({
|
||||
'publicKey': os.getenv('STRIPE_PUBLISHABLE_KEY'),
|
||||
'publicKey': key_public, # os.getenv('KEY_PUBLIC_STRIPE'),
|
||||
'unitAmount': price['unit_amount'],
|
||||
'currency': price['currency']
|
||||
})
|
||||
@@ -113,12 +149,19 @@ def webhook_received():
|
||||
event_type = request_data['type']
|
||||
data_object = data['object']
|
||||
|
||||
print('event ' + event_type)
|
||||
Helper_App.console_log('event ' + event_type)
|
||||
|
||||
if event_type == 'checkout.session.completed':
|
||||
print('🔔 Payment succeeded!')
|
||||
Helper_App.console_log('🔔 Payment succeeded!')
|
||||
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_SUCCESS})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# stripe.api_key = key_secret
|
||||
|
||||
# create_product_price()
|
||||
|
||||
# Setup Stripe python client library.
|
||||
load_dotenv(find_dotenv())
|
||||
app.run(port=4242, debug=True)
|
||||
86
controllers/store/product.py
Normal file
86
controllers/store/product.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Product Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.product import Product, Parameters_Product
|
||||
from datastores.datastore_store_product import DataStore_Store_Product
|
||||
from forms.store.product import Filters_Product
|
||||
from models.model_view_store_product import Model_View_Store_Product
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
|
||||
|
||||
routes_store_product = Blueprint('routes_store_product', __name__)
|
||||
|
||||
@routes_store_product.route(Model_View_Store_Product.HASH_PAGE_STORE_PRODUCTS, methods=['GET'])
|
||||
def products():
|
||||
Helper_App.console_log('products')
|
||||
try:
|
||||
form_filters = Filters_Product.from_json(request.args)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error: {e}')
|
||||
form_filters = Filters_Product()
|
||||
Helper_App.console_log(f'form_filters={form_filters}')
|
||||
model = Model_View_Store_Product(form_filters)
|
||||
if not model.is_user_logged_in:
|
||||
# return redirect(url_for('routes_user.login', data = jsonify({ Model_View_Store_Product.FLAG_CALLBACK: Model_View_Store_Product.HASH_PAGE_STORE_PRODUCTS })))
|
||||
return redirect(url_for('routes_core.home'))
|
||||
return render_template('pages/store/_products.html', model = model)
|
||||
|
||||
|
||||
@routes_store_product.route(Model_View_Store_Product.HASH_SAVE_STORE_PRODUCT, methods=['POST'])
|
||||
def save_product():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Product.from_json(data[Model_View_Store_Product.FLAG_FORM_FILTERS])
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({
|
||||
Model_View_Store_Product.FLAG_STATUS: Model_View_Store_Product.FLAG_FAILURE,
|
||||
Model_View_Store_Product.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
# filters_form = Filters_Product.from_form(form_filters)
|
||||
Helper_App.console_log(f'form_filters: {form_filters}')
|
||||
|
||||
products = data[Model_View_Store_Product.FLAG_PRODUCT]
|
||||
if len(products) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Product.FLAG_STATUS: Model_View_Store_Product.FLAG_FAILURE,
|
||||
Model_View_Store_Product.FLAG_MESSAGE: f'No products.'
|
||||
})
|
||||
objsProduct = []
|
||||
for product in products:
|
||||
objsProduct.append(Product.from_json(product))
|
||||
# model_save = Model_View_Store_Product() # filters_product=filters_form)
|
||||
Helper_App.console_log(f'objsProduct={objsProduct}')
|
||||
save_errors = Model_View_Store_Product.save_products(data.get('comment', 'No comment'), objsProduct)
|
||||
|
||||
model_return = Model_View_Store_Product(form_filters_old=form_filters)
|
||||
if not model_return.is_user_logged_in:
|
||||
raise Exception('User not logged in')
|
||||
Helper_App.console_log('nips')
|
||||
return jsonify({
|
||||
Model_View_Store_Product.FLAG_STATUS: Model_View_Store_Product.FLAG_SUCCESS,
|
||||
Model_View_Store_Product.FLAG_DATA: model_return.category_list.to_json()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Product.FLAG_STATUS: Model_View_Store_Product.FLAG_FAILURE,
|
||||
Model_View_Store_Product.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
104
controllers/store/product_category.py
Normal file
104
controllers/store/product_category.py
Normal file
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Product Category Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.product_category import Product_Category #, Filters_Product_Category
|
||||
from forms.store.product_category import Filters_Product_Category
|
||||
from models.model_view_store_product_category import Model_View_Store_Product_Category
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
|
||||
|
||||
routes_store_product_category = Blueprint('routes_store_product_category', __name__)
|
||||
|
||||
|
||||
@routes_store_product_category.route(Model_View_Store_Product_Category.HASH_PAGE_STORE_PRODUCT_CATEGORIES, methods=['GET'])
|
||||
def categories():
|
||||
Helper_App.console_log('categories')
|
||||
# data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Product_Category.from_json(request.args)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error: {e}')
|
||||
form_filters = Filters_Product_Category()
|
||||
Helper_App.console_log(f'form_filters={form_filters}')
|
||||
"""
|
||||
filters = Filters_Product_Category.get_default()
|
||||
have_changed_filters = False
|
||||
arg_filter_is_not_empty = request.args.get(Model_View_Store_Product_Category.FLAG_IS_NOT_EMPTY, None)
|
||||
have_changed_filters = have_changed_filters or arg_filter_is_not_empty is None
|
||||
Helper_App.console_log(f'arg_filter_is_not_empty={arg_filter_is_not_empty}')
|
||||
filters.is_not_empty = filters.is_not_empty if arg_filter_is_not_empty is None else av.input_bool(arg_filter_is_not_empty, 'is_not_empty', 'filter_category')
|
||||
arg_filter_active = request.args.get(Model_View_Store_Product_Category.FLAG_ACTIVE, None)
|
||||
have_changed_filters = have_changed_filters or arg_filter_active is None
|
||||
Helper_App.console_log(f'arg_filter_active={arg_filter_active}')
|
||||
filters.active = filters.active if arg_filter_active is None else av.input_bool(arg_filter_active, 'active', 'filter_category')
|
||||
if have_changed_filters:
|
||||
Helper_App.console_log('redirecting')
|
||||
return redirect(url_for('routes_store_product_category.categories', **filters.to_json()))
|
||||
"""
|
||||
model = Model_View_Store_Product_Category(form_filters)
|
||||
if not model.is_user_logged_in:
|
||||
# return redirect(url_for('routes_user.login', data = jsonify({ Model_View_Store_Product_Category.FLAG_CALLBACK: Model_View_Store_Product_Category.HASH_PAGE_STORE_PRODUCT_CATEGORIES })))
|
||||
return redirect(url_for('routes_core.home'))
|
||||
return render_template('pages/store/_product_categories.html', model = model)
|
||||
|
||||
@routes_store_product_category.route(Model_View_Store_Product_Category.HASH_SAVE_STORE_PRODUCT_CATEGORY, methods=['POST'])
|
||||
def save_category():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Product_Category.from_json(data[Model_View_Store_Product_Category.FLAG_FORM_FILTERS])
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
# filters_form = Filters_Product_Category.from_form(form_filters)
|
||||
|
||||
categories = data[Model_View_Store_Product_Category.FLAG_PRODUCT_CATEGORY]
|
||||
if len(categories) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'No categories.'
|
||||
})
|
||||
objsCategory = []
|
||||
for category in categories:
|
||||
objsCategory.append(Product_Category.from_json(category))
|
||||
# model_save = Model_View_Store_Product_Category() # filters_product=filters_form)
|
||||
Helper_App.console_log(f'objsCategory={objsCategory}')
|
||||
errors = Model_View_Store_Product_Category.save_categories(data.get('comment', 'No comment'), objsCategory)
|
||||
|
||||
model_return = Model_View_Store_Product_Category(form_filters_old=form_filters)
|
||||
if not model_return.is_user_logged_in:
|
||||
raise Exception('User not logged in')
|
||||
if (len(errors) > 0):
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'Error saving categories.\n{model_return.convert_list_objects_to_json(errors)}'
|
||||
})
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Category.FLAG_DATA: model_return.category_list.to_json()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Category.FLAG_STATUS: Model_View_Store_Product_Category.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Category.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
90
controllers/store/product_permutation.py
Normal file
90
controllers/store/product_permutation.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Product Permutation Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
|
||||
# internal
|
||||
from business_objects.store.product import Parameters_Product, Product_Permutation
|
||||
from forms.store.product_permutation import Filters_Product_Permutation
|
||||
from models.model_view_base import Model_View_Base
|
||||
from models.model_view_store import Model_View_Store
|
||||
from models.model_view_store_product_permutation import Model_View_Store_Product_Permutation
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
|
||||
|
||||
routes_store_product_permutation = Blueprint('routes_store_product_permutation', __name__)
|
||||
|
||||
@routes_store_product_permutation.route(Model_View_Store_Product_Permutation.HASH_PAGE_STORE_PRODUCT_PERMUTATIONS, methods=['GET'])
|
||||
def permutations():
|
||||
Helper_App.console_log('permutations')
|
||||
data = request.args
|
||||
# Helper_App.console_log(f'data={data}\nrequest.args={request.args}\nrequest.form={request.form}\nrequest.data={request.data}\nrequest.values={request.values}\nrequest.headers={request.headers}')
|
||||
try:
|
||||
form_filters = Filters_Product_Permutation.from_json(data)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error: {e}')
|
||||
form_filters = Filters_Product_Permutation()
|
||||
Helper_App.console_log(f'form_filters={form_filters}')
|
||||
model = Model_View_Store_Product_Permutation(form_filters)
|
||||
if not model.is_user_logged_in:
|
||||
# return redirect(url_for('routes_user.login', data = jsonify({ Model_View_Store_Product_Permutation.FLAG_CALLBACK: Model_View_Store_Product_Permutation.HASH_PAGE_STORE_PRODUCT_PERMUTATIONS })))
|
||||
return redirect(url_for('routes_core.home'))
|
||||
return render_template('pages/store/_product_permutations.html', model = model)
|
||||
|
||||
|
||||
@routes_store_product_permutation.route(Model_View_Store_Product_Permutation.HASH_SAVE_STORE_PRODUCT_PERMUTATION, methods=['POST'])
|
||||
def save_permutation():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Product_Permutation.from_json(data[Model_View_Store_Product_Permutation.FLAG_FORM_FILTERS])
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Permutation.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
# filters_form = Filters_Product_Permutation.from_form(form_filters)
|
||||
Helper_App.console_log(f'form_filters: {form_filters}')
|
||||
|
||||
permutations = data[Model_View_Store_Product_Permutation.FLAG_PRODUCT_PERMUTATION]
|
||||
if len(permutations) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Permutation.FLAG_MESSAGE: f'No permutations.'
|
||||
})
|
||||
objsPermutation = []
|
||||
for permutation in permutations:
|
||||
objsPermutation.append(Product_Permutation.from_json(permutation))
|
||||
# model_save = Model_View_Store_Product_Permutation() # filters_product=filters_form)
|
||||
Helper_App.console_log(f'objsPermutation={objsPermutation}')
|
||||
Model_View_Store_Product_Permutation.save_permutations(data.get('comment', 'No comment'), objsPermutation)
|
||||
|
||||
model_return = Model_View_Store_Product_Permutation(form_filters_old=form_filters)
|
||||
if not model_return.is_user_logged_in:
|
||||
raise Exception('User not logged in')
|
||||
Helper_App.console_log('nips')
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Permutation.FLAG_DATA: model_return.category_list.to_json()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Permutation.FLAG_STATUS: Model_View_Store_Product_Permutation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Permutation.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
87
controllers/store/product_variation.py
Normal file
87
controllers/store/product_variation.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Product Variation Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.product_variation import Product_Variation, Parameters_Product_Variation
|
||||
from business_objects.store.product_variation_type import Product_Variation_Type
|
||||
from datastores.datastore_store_product_variation import DataStore_Store_Product_Variation
|
||||
from forms.store.product_variation import Filters_Product_Variation
|
||||
from models.model_view_store_product_variation import Model_View_Store_Product_Variation
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
|
||||
|
||||
routes_store_product_variation = Blueprint('routes_store_product_variation', __name__)
|
||||
|
||||
|
||||
@routes_store_product_variation.route(Model_View_Store_Product_Variation.HASH_PAGE_STORE_PRODUCT_VARIATIONS, methods=['GET'])
|
||||
def product_variations():
|
||||
Helper_App.console_log('product_variations')
|
||||
try:
|
||||
form_filters = Filters_Product_Variation.from_json(request.args)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error: {e}')
|
||||
form_filters = Filters_Product_Variation()
|
||||
Helper_App.console_log(f'form_filters={form_filters}')
|
||||
model = Model_View_Store_Product_Variation(form_filters)
|
||||
if not model.is_user_logged_in:
|
||||
return redirect(url_for('routes_core.home'))
|
||||
return render_template('pages/store/_product_variations.html', model = model)
|
||||
|
||||
|
||||
@routes_store_product_variation.route(Model_View_Store_Product_Variation.HASH_SAVE_STORE_PRODUCT_VARIATION, methods=['POST'])
|
||||
def save_product_variation():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Product_Variation.from_json(data[Model_View_Store_Product_Variation.FLAG_FORM_FILTERS])
|
||||
if not form_filters.validate_on_submit():
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Variation.FLAG_STATUS: Model_View_Store_Product_Variation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Variation.FLAG_MESSAGE: f'Filters form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
# filters_form = Filters_Product_Variation.from_form(form_filters)
|
||||
Helper_App.console_log(f'form_filters: {form_filters}')
|
||||
|
||||
product_variation_types = data[Model_View_Store_Product_Variation.FLAG_PRODUCT_VARIATION_TYPE]
|
||||
if len(product_variation_types) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Variation.FLAG_STATUS: Model_View_Store_Product_Variation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Variation.FLAG_MESSAGE: f'No Product Variations.'
|
||||
})
|
||||
objs_product_variation_type = []
|
||||
for product_variation_type in product_variation_types:
|
||||
objs_product_variation_type.append(Product_Variation_Type.from_json(product_variation_type))
|
||||
# model_save = Model_View_Store_Product_Variation() # filters_product_variation=filters_form)
|
||||
Helper_App.console_log(f'objs_product_variation_type={objs_product_variation_type}')
|
||||
save_errors = Model_View_Store_Product_Variation.save_product_variations(data.get('comment', 'No comment'), objs_product_variation_type)
|
||||
|
||||
model_return = Model_View_Store_Product_Variation(form_filters_old = form_filters)
|
||||
if not model_return.is_user_logged_in:
|
||||
raise Exception('User not logged in')
|
||||
Helper_App.console_log('nips')
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Variation.FLAG_STATUS: Model_View_Store_Product_Variation.FLAG_SUCCESS,
|
||||
Model_View_Store_Product_Variation.FLAG_DATA: model_return.convert_list_objects_to_json(model_return.variation_types)
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Product_Variation.FLAG_STATUS: Model_View_Store_Product_Variation.FLAG_FAILURE,
|
||||
Model_View_Store_Product_Variation.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
107
controllers/store/stock_item.py
Normal file
107
controllers/store/stock_item.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Stock Item Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.stock_item import Stock_Item
|
||||
from forms.store.stock_item import Filters_Stock_Item
|
||||
from models.model_view_store_stock_item import Model_View_Store_Stock_Item
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from datetime import datetime
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
import requests
|
||||
|
||||
routes_store_stock_item = Blueprint('routes_store_stock_item', __name__)
|
||||
|
||||
@routes_store_stock_item.route(Model_View_Store_Stock_Item.HASH_PAGE_STORE_STOCK_ITEMS, methods=['GET'])
|
||||
def stock_items():
|
||||
Helper_App.console_log('stock_items')
|
||||
try:
|
||||
form_filters = Filters_Stock_Item.from_json(request.args)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error: {e}')
|
||||
form_filters = Filters_Stock_Item()
|
||||
Helper_App.console_log(f'form_filters={form_filters}')
|
||||
model = Model_View_Store_Stock_Item(form_filters)
|
||||
if not model.is_user_logged_in:
|
||||
# return redirect(url_for('routes_user.login', data = jsonify({ Model_View_Store_Stock_Item.FLAG_CALLBACK: Model_View_Store_Stock_Item.HASH_PAGE_STORE_STOCK_ITEMS })))
|
||||
# return requests.post(f"{current_app.config['URL_HOST']}{url_for('routes_user.login')}", json={ Model_View_Store_Stock_Item.FLAG_CALLBACK: Model_View_Store_Stock_Item.HASH_PAGE_STORE_STOCK_ITEMS })
|
||||
return redirect(url_for('routes_core.home'))
|
||||
return render_template('pages/store/_stock_items.html', model = model, datetime = datetime)
|
||||
|
||||
|
||||
@routes_store_stock_item.route(Model_View_Store_Stock_Item.HASH_SAVE_STORE_STOCK_ITEM, methods=['POST'])
|
||||
def save_stock_item():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Stock_Item.from_json(data[Model_View_Store_Stock_Item.FLAG_FORM_FILTERS])
|
||||
"""
|
||||
if not form_filters.validate_on_submit():
|
||||
error_keys = list(form_filters.errors.keys())
|
||||
try:
|
||||
error_keys.remove(Stock_Item.ATTR_ID_PRODUCT_CATEGORY)
|
||||
""
|
||||
if not av.val_int(form_filters.id_product_category.data):
|
||||
form_filters.errors[Stock_Item.ATTR_ID_PRODUCT_CATEGORY] = ['Invalid category.']
|
||||
""
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
error_keys.remove(Stock_Item.ATTR_ID_PRODUCT)
|
||||
except:
|
||||
pass
|
||||
if error_keys:
|
||||
return jsonify({
|
||||
Model_View_Store_Stock_Item.FLAG_STATUS: Model_View_Store_Stock_Item.FLAG_FAILURE,
|
||||
Model_View_Store_Stock_Item.FLAG_MESSAGE: f'Form invalid.\n{form_filters.errors}'
|
||||
})
|
||||
"""
|
||||
# filters_form = Filters_Stock_Item.from_form(form_filters)
|
||||
Helper_App.console_log(f'form_filters: {form_filters}')
|
||||
|
||||
stock_items = data[Model_View_Store_Stock_Item.FLAG_STOCK_ITEM]
|
||||
if len(stock_items) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Stock_Item.FLAG_STATUS: Model_View_Store_Stock_Item.FLAG_FAILURE,
|
||||
Model_View_Store_Stock_Item.FLAG_MESSAGE: f'No stock items.'
|
||||
})
|
||||
Helper_App.console_log(f'stock_items={stock_items}')
|
||||
objs_stock_item = []
|
||||
for stock_item in stock_items:
|
||||
objs_stock_item.append(Stock_Item.from_json(stock_item))
|
||||
# model_save = Model_View_Store_Stock_Item() # filters_product=filters_form)
|
||||
Helper_App.console_log(f'objs_stock_item={objs_stock_item}')
|
||||
save_errors = Model_View_Store_Stock_Item.save_stock_items(data.get('comment', 'No comment'), objs_stock_item)
|
||||
if len(save_errors) > 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Stock_Item.FLAG_STATUS: Model_View_Store_Stock_Item.FLAG_FAILURE,
|
||||
Model_View_Store_Stock_Item.FLAG_MESSAGE: f'Save errors: {save_errors}'
|
||||
})
|
||||
model_return = Model_View_Store_Stock_Item(filters_stock_item=form_filters)
|
||||
if not model_return.is_user_logged_in:
|
||||
raise Exception('User not logged in.')
|
||||
return jsonify({
|
||||
Model_View_Store_Stock_Item.FLAG_STATUS: Model_View_Store_Stock_Item.FLAG_SUCCESS,
|
||||
Model_View_Store_Stock_Item.FLAG_DATA: model_return.category_list.to_json()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Stock_Item.FLAG_STATUS: Model_View_Store_Stock_Item.FLAG_FAILURE,
|
||||
Model_View_Store_Stock_Item.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
83
controllers/store/supplier.py
Normal file
83
controllers/store/supplier.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Supplier Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.supplier import Supplier
|
||||
from forms.store.supplier import Filters_Supplier
|
||||
from models.model_view_store_supplier import Model_View_Store_Supplier
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from datetime import datetime
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
import requests
|
||||
|
||||
routes_store_supplier = Blueprint('routes_store_supplier', __name__)
|
||||
|
||||
@routes_store_supplier.route(Model_View_Store_Supplier.HASH_PAGE_STORE_SUPPLIERS, methods=['GET'])
|
||||
def suppliers():
|
||||
Helper_App.console_log('suppliers')
|
||||
try:
|
||||
form_filters = Filters_Supplier.from_json(request.args)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error: {e}')
|
||||
form_filters = Filters_Supplier()
|
||||
Helper_App.console_log(f'form_filters={form_filters}')
|
||||
model = Model_View_Store_Supplier(form_filters)
|
||||
if not model.is_user_logged_in:
|
||||
return redirect(url_for('routes_core.home'))
|
||||
return render_template('pages/store/_suppliers.html', model = model, datetime = datetime)
|
||||
|
||||
|
||||
@routes_store_supplier.route(Model_View_Store_Supplier.HASH_SAVE_STORE_SUPPLIER, methods=['POST'])
|
||||
def save_supplier():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Supplier.from_json(data[Model_View_Store_Supplier.FLAG_FORM_FILTERS])
|
||||
Helper_App.console_log(f'form_filters: {form_filters}')
|
||||
|
||||
suppliers = data[Model_View_Store_Supplier.FLAG_SUPPLIER]
|
||||
if len(suppliers) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Supplier.FLAG_STATUS: Model_View_Store_Supplier.FLAG_FAILURE,
|
||||
Model_View_Store_Supplier.FLAG_MESSAGE: f'No stock items.'
|
||||
})
|
||||
Helper_App.console_log(f'suppliers={suppliers}')
|
||||
objs_supplier = []
|
||||
for supplier in suppliers:
|
||||
objs_supplier.append(Supplier.from_json(supplier))
|
||||
Helper_App.console_log(f'objs_supplier={objs_supplier}')
|
||||
|
||||
save_errors = Model_View_Store_Supplier.save_suppliers(data.get('comment', 'No comment'), objs_supplier)
|
||||
if len(save_errors) > 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Supplier.FLAG_STATUS: Model_View_Store_Supplier.FLAG_FAILURE,
|
||||
Model_View_Store_Supplier.FLAG_MESSAGE: f'Save errors: {save_errors}'
|
||||
})
|
||||
model_return = Model_View_Store_Supplier(form_filters_old = form_filters)
|
||||
if not model_return.is_user_logged_in:
|
||||
raise Exception('User not logged in.')
|
||||
return jsonify({
|
||||
Model_View_Store_Supplier.FLAG_STATUS: Model_View_Store_Supplier.FLAG_SUCCESS,
|
||||
Model_View_Store_Supplier.FLAG_DATA: {supplier.id_supplier: supplier.to_json() for supplier in model_return.suppliers}
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Supplier.FLAG_STATUS: Model_View_Store_Supplier.FLAG_FAILURE,
|
||||
Model_View_Store_Supplier.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
82
controllers/store/supplier_purchase_order.py
Normal file
82
controllers/store/supplier_purchase_order.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store Supplier_Purchase_Order Routes
|
||||
|
||||
Description:
|
||||
Initializes the Flask application, sets the configuration based on the environment, and defines two routes (/ and /about) that render templates with the specified titles.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.supplier_purchase_order import Supplier_Purchase_Order
|
||||
from forms.store.supplier_purchase_order import Filters_Supplier_Purchase_Order
|
||||
from models.model_view_store_supplier_purchase_order import Model_View_Store_Supplier_Purchase_Order
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from datetime import datetime
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app
|
||||
from extensions import db, oauth
|
||||
from urllib.parse import quote_plus, urlencode
|
||||
from authlib.integrations.flask_client import OAuth
|
||||
from authlib.integrations.base_client import OAuthError
|
||||
from urllib.parse import quote, urlparse, parse_qs
|
||||
import requests
|
||||
|
||||
routes_store_supplier_purchase_order = Blueprint('routes_store_supplier_purchase_order', __name__)
|
||||
|
||||
@routes_store_supplier_purchase_order.route(Model_View_Store_Supplier_Purchase_Order.HASH_PAGE_STORE_SUPPLIER_PURCHASE_ORDERS, methods=['GET'])
|
||||
def supplier_purchase_orders():
|
||||
Helper_App.console_log('supplier_purchase_orders')
|
||||
try:
|
||||
form_filters = Filters_Supplier_Purchase_Order.from_json(request.args)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error: {e}')
|
||||
form_filters = Filters_Supplier_Purchase_Order()
|
||||
Helper_App.console_log(f'form_filters={form_filters}')
|
||||
model = Model_View_Store_Supplier_Purchase_Order(form_filters)
|
||||
if not model.is_user_logged_in:
|
||||
return redirect(url_for('routes_core.home'))
|
||||
return render_template('pages/store/_supplier_purchase_orders.html', model = model, datetime = datetime)
|
||||
|
||||
|
||||
@routes_store_supplier_purchase_order.route(Model_View_Store_Supplier_Purchase_Order.HASH_SAVE_STORE_SUPPLIER_PURCHASE_ORDER, methods=['POST'])
|
||||
def save_supplier_purchase_order():
|
||||
data = Helper_App.get_request_data(request)
|
||||
try:
|
||||
form_filters = Filters_Supplier_Purchase_Order.from_json(data[Model_View_Store_Supplier_Purchase_Order.FLAG_FORM_FILTERS])
|
||||
Helper_App.console_log(f'form_filters: {form_filters}')
|
||||
|
||||
supplier_purchase_orders = data[Model_View_Store_Supplier_Purchase_Order.FLAG_SUPPLIER_PURCHASE_ORDER]
|
||||
if len(supplier_purchase_orders) == 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Supplier_Purchase_Order.FLAG_STATUS: Model_View_Store_Supplier_Purchase_Order.FLAG_FAILURE,
|
||||
Model_View_Store_Supplier_Purchase_Order.FLAG_MESSAGE: f'No stock items.'
|
||||
})
|
||||
Helper_App.console_log(f'supplier_purchase_orders={supplier_purchase_orders}')
|
||||
objs_supplier_purchase_order = []
|
||||
for supplier_purchase_order in supplier_purchase_orders:
|
||||
objs_supplier_purchase_order.append(Supplier_Purchase_Order.from_json(supplier_purchase_order))
|
||||
Helper_App.console_log(f'objs_supplier_purchase_order={objs_supplier_purchase_order}')
|
||||
save_errors, save_warnings = Model_View_Store_Supplier_Purchase_Order.save_supplier_purchase_orders(data.get('comment', 'No comment'), objs_supplier_purchase_order)
|
||||
if len(save_errors) > 0:
|
||||
return jsonify({
|
||||
Model_View_Store_Supplier_Purchase_Order.FLAG_STATUS: Model_View_Store_Supplier_Purchase_Order.FLAG_FAILURE,
|
||||
Model_View_Store_Supplier_Purchase_Order.FLAG_MESSAGE: f'Save errors: {save_errors}'
|
||||
})
|
||||
model_return = Model_View_Store_Supplier_Purchase_Order(form_filters_old = form_filters)
|
||||
if not model_return.is_user_logged_in:
|
||||
raise Exception('User not logged in.')
|
||||
return jsonify({
|
||||
Model_View_Store_Supplier_Purchase_Order.FLAG_STATUS: Model_View_Store_Supplier_Purchase_Order.FLAG_SUCCESS,
|
||||
Model_View_Store_Supplier_Purchase_Order.FLAG_DATA: model_return.convert_list_objects_to_json(model_return.supplier_purchase_orders)
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
Model_View_Store_Supplier_Purchase_Order.FLAG_STATUS: Model_View_Store_Supplier_Purchase_Order.FLAG_FAILURE,
|
||||
Model_View_Store_Supplier_Purchase_Order.FLAG_MESSAGE: f'Bad data received by controller.\n{e}'
|
||||
})
|
||||
|
||||
@@ -13,9 +13,20 @@ Datastore for Store
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.access_level import Access_Level
|
||||
from business_objects.store.access_level import Access_Level
|
||||
"""
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category
|
||||
from business_objects.store.currency import Currency
|
||||
from business_objects.store.image import Image
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.store.discount import Discount
|
||||
from business_objects.store.order import Order
|
||||
from business_objects.store.product import Product, Product_Permutation, Product_Price, Parameters_Product # Permutation_Variation_Link
|
||||
"""
|
||||
from business_objects.region import Region
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item
|
||||
from business_objects.unit_measurement import Unit_Measurement
|
||||
from business_objects.user import User, Parameters_User, User_Permission_Evaluation
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
|
||||
143
datastores/datastore_store_basket.py
Normal file
143
datastores/datastore_store_basket.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Basket DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Baskets
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
# from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
# db = SQLAlchemy()
|
||||
|
||||
|
||||
class DataStore_Store_Basket(DataStore_Store_Base):
|
||||
# Global constants
|
||||
KEY_BASKET: ClassVar[str] = Basket.KEY_BASKET
|
||||
# Attributes
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def get_metadata_basket(json_request):
|
||||
try:
|
||||
basket = json_request[DataStore_Store_Basket.KEY_BASKET]
|
||||
except KeyError:
|
||||
basket = {DataStore_Store_Basket.KEY_IS_INCLUDED_VAT: True, DataStore_Store_Basket.KEY_ID_CURRENCY: 1, DataStore_Store_Basket.KEY_ID_REGION_DELIVERY: 1}
|
||||
is_included_VAT = basket[DataStore_Store_Basket.KEY_IS_INCLUDED_VAT]
|
||||
id_currency = basket[DataStore_Store_Basket.KEY_ID_CURRENCY]
|
||||
id_region_delivery = basket[DataStore_Store_Basket.KEY_ID_REGION_DELIVERY]
|
||||
return id_currency, id_region_delivery, is_included_VAT
|
||||
|
||||
def edit_basket(self, ids_permutation_basket, quantities_permutation_basket, id_permutation_edit, quantity_permutation_edit, sum_not_edit, id_currency, id_region_delivery, is_included_VAT):
|
||||
# redundant argument validation?
|
||||
_m = 'DataStore_Store_Base.edit_basket'
|
||||
Helper_App.console_log(f'{_m}\nstarting...')
|
||||
# av.val_instance(filters, 'filters', _m, Parameters_Product_Category)
|
||||
# av.val_str(ids_product_basket, 'ids_product_basket', _m)
|
||||
av.val_str(ids_permutation_basket, 'ids_permutation_basket', _m)
|
||||
# av.val_str(quantities_product_basket, 'quantities_product_basket', _m)
|
||||
av.val_str(quantities_permutation_basket, 'quantities_permutation_basket', _m)
|
||||
"""
|
||||
if id_product_edit == 'None':
|
||||
id_product_edit = None
|
||||
else:
|
||||
Helper_App.console_log(f'id_product_edit: {id_product_edit}')
|
||||
av.val_int(id_product_edit, 'id_product_edit', _m)
|
||||
"""
|
||||
if id_permutation_edit == 'None' or str(type(id_permutation_edit)) =="<class 'NoneType'>":
|
||||
id_permutation_edit = None
|
||||
else:
|
||||
Helper_App.console_log(f'id_permutation_edit: {id_permutation_edit}')
|
||||
Helper_App.console_log(str(type(id_permutation_edit)))
|
||||
av.val_int(id_permutation_edit, 'id_permutation_edit', _m)
|
||||
if quantity_permutation_edit == 'None' or str(type(quantity_permutation_edit)) =="<class 'NoneType'>":
|
||||
quantity_permutation_edit = None
|
||||
else:
|
||||
Helper_App.console_log(f'quantity_permutation_edit: {quantity_permutation_edit}')
|
||||
av.val_int(quantity_permutation_edit, 'quantity_permutation_edit', _m)
|
||||
if sum_not_edit == 'None':
|
||||
sum_not_edit = None
|
||||
else:
|
||||
Helper_App.console_log(f'sum_not_edit: {sum_not_edit}')
|
||||
av.val_bool(sum_not_edit, 'sum_not_edit', _m)
|
||||
|
||||
argument_dict_list = {
|
||||
'a_id_user': self.info_user.get('sub'),
|
||||
# 'a_ids_product_basket': ids_product_basket,
|
||||
'a_ids_permutation_basket': ids_permutation_basket,
|
||||
# 'a_quantities_product_basket': quantities_product_basket,
|
||||
'a_quantities_permutation_basket': quantities_permutation_basket,
|
||||
# 'a_id_product_edit': id_product_edit if id_permutation_edit is None else None,
|
||||
'a_id_permutation_edit': id_permutation_edit,
|
||||
'a_quantity_permutation_edit': quantity_permutation_edit,
|
||||
'a_sum_not_edit': 1 if sum_not_edit else 0,
|
||||
'a_id_currency': id_currency,
|
||||
'a_id_region_purchase': id_region_delivery
|
||||
}
|
||||
|
||||
result = self.db_procedure_execute('p_shop_edit_user_basket', argument_dict_list)
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
cursor = result.cursor
|
||||
|
||||
# categories, category_index = DataStore_Store_Base.input_many_product(cursor)
|
||||
category_list, errors = DataStore_Store_Base.input_many_product(cursor)
|
||||
|
||||
Helper_App.console_log(f'cursor: {str(cursor)}')
|
||||
|
||||
# Basket
|
||||
if not cursor.nextset():
|
||||
raise Exception("No more query results! Cannot open basket contents")
|
||||
result_set = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw basket: {result_set}')
|
||||
# Helper_App.console_log(f'variations: {result_set_3}')
|
||||
# variations = [Product_Variation(**row) for row in result_set_3]
|
||||
basket = Basket(is_included_VAT, id_currency, id_region_delivery)
|
||||
for row in result_set:
|
||||
index_category = category_list.get_index_category_from_id(row[0])
|
||||
category = category_list.categories[index_category]
|
||||
index_product = category.get_index_product_from_id(row[1])
|
||||
product = category.products[index_product]
|
||||
basket_item = Basket_Item.from_product_and_quantity_and_VAT_included(product, row[7], self.app.is_included_VAT)
|
||||
Helper_App.console_log(f'adding basket item: {row}')
|
||||
Helper_App.console_log(f'basket item: {basket_item}')
|
||||
basket.add_item(basket_item) # basket.append(basket_item) # Basket_Item(category.name, product, row[4]))
|
||||
|
||||
Helper_App.console_log(f'basket: {basket}')
|
||||
|
||||
# Errors
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # [SQL_Error(row[0], row[1]) for row in result_set_2]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Base.db_cursor_clear(cursor)
|
||||
|
||||
return basket
|
||||
137
datastores/datastore_store_manufacturing_purchase_order.py
Normal file
137
datastores/datastore_store_manufacturing_purchase_order.py
Normal file
@@ -0,0 +1,137 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Manufacturing Purchase Order Purchase Order DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Manufacturing Purchase Order Purchase Orders
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.manufacturing_purchase_order import Manufacturing_Purchase_Order, Manufacturing_Purchase_Order_Product_Link, Parameters_Manufacturing_Purchase_Order, Manufacturing_Purchase_Order_Temp, Manufacturing_Purchase_Order_Product_Link_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
from extensions import db
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class DataStore_Store_Manufacturing_Purchase_Order(DataStore_Store_Base):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_many_manufacturing_purchase_order(self, parameters_manufacturing_purchase_order):
|
||||
_m = 'DataStore_Store_Manufacturing_Purchase_Order.get_many_manufacturing_purchase_order'
|
||||
av.val_instance(parameters_manufacturing_purchase_order, 'parameters_manufacturing_purchase_order', _m, Parameters_Manufacturing_Purchase_Order)
|
||||
argument_dict = parameters_manufacturing_purchase_order.to_json()
|
||||
user = self.get_user_session()
|
||||
argument_dict = {
|
||||
'a_id_user': user.id_user
|
||||
, **argument_dict
|
||||
, 'a_debug': 0
|
||||
}
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
Helper_App.console_log('executing p_shop_get_many_manufacturing_purchase_order')
|
||||
result = self.db_procedure_execute('p_shop_get_many_manufacturing_purchase_order', argument_dict)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# Manufacturing_Purchase_Orders
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw manufacturing_purchase_orders: {result_set_1}')
|
||||
manufacturing_purchase_orders = []
|
||||
indices_manufacturing_purchase_order = {}
|
||||
for row in result_set_1:
|
||||
new_manufacturing_purchase_order = Manufacturing_Purchase_Order.from_DB_manufacturing_purchase_order(row)
|
||||
indices_manufacturing_purchase_order[new_manufacturing_purchase_order.id_order] = len(manufacturing_purchase_orders)
|
||||
manufacturing_purchase_orders.append(new_manufacturing_purchase_order)
|
||||
|
||||
# Manufacturing_Purchase_Orders Items
|
||||
cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw manufacturing_purchase_order_product_links: {result_set_1}')
|
||||
order_product_links = []
|
||||
for row in result_set_1:
|
||||
new_link = Manufacturing_Purchase_Order_Product_Link.from_DB_manufacturing_purchase_order(row)
|
||||
order_product_links.append(new_link)
|
||||
manufacturing_purchase_orders[indices_manufacturing_purchase_order[new_link.id_order]].items.append(new_link)
|
||||
|
||||
# Errors
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Manufacturing_Purchase_Order.db_cursor_clear(cursor)
|
||||
|
||||
return manufacturing_purchase_orders, errors
|
||||
|
||||
@classmethod
|
||||
def save_manufacturing_purchase_orders(cls, comment, manufacturing_purchase_orders):
|
||||
_m = 'DataStore_Store_Manufacturing_Purchase_Order.save_manufacturing_purchase_orders'
|
||||
av.val_str(comment, 'comment', _m)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
now = datetime.now()
|
||||
user = cls.get_user_session()
|
||||
rows_order = []
|
||||
for manufacturing_purchase_order in manufacturing_purchase_orders:
|
||||
row = Manufacturing_Purchase_Order_Temp.from_manufacturing_purchase_order(manufacturing_purchase_order)
|
||||
row.guid = guid
|
||||
rows_order.append(row)
|
||||
Helper_App.console_log(f'order rows: {rows_order}')
|
||||
DataStore_Store_Base.upload_bulk(Manufacturing_Purchase_Order_Temp.__tablename__, rows_order, 1000)
|
||||
Helper_App.console_log('bulk uploaded orders')
|
||||
|
||||
rows_link = []
|
||||
for manufacturing_purchase_order in manufacturing_purchase_orders:
|
||||
for link in manufacturing_purchase_order.items:
|
||||
row = Manufacturing_Purchase_Order_Product_Link_Temp.from_manufacturing_purchase_order_product_link(link)
|
||||
row.guid = guid
|
||||
rows_link.append(row)
|
||||
Helper_App.console_log(f'link rows: {rows_link}')
|
||||
DataStore_Store_Base.upload_bulk(Manufacturing_Purchase_Order_Product_Link_Temp.__tablename__, rows_link, 1000)
|
||||
Helper_App.console_log('bulk uploaded links')
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0
|
||||
}
|
||||
result = cls.db_procedure_execute('p_shop_save_manufacturing_purchase_order', argument_dict_list)
|
||||
Helper_App.console_log('saved manufacturing purchase orders')
|
||||
|
||||
# Errors
|
||||
cursor = result.cursor
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Manufacturing_Purchase_Order.db_cursor_clear(cursor)
|
||||
return errors
|
||||
139
datastores/datastore_store_product.py
Normal file
139
datastores/datastore_store_product.py
Normal file
@@ -0,0 +1,139 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Product DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Products
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.product import Product, Product_Permutation, Product_Price, Parameters_Product, Product_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
# db = SQLAlchemy()
|
||||
|
||||
"""
|
||||
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 Row_Shop_Product_Temp(db.Model):
|
||||
__tablename__ = 'Shop_Product_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_product: int = db.Column(db.Integer, primary_key=True)
|
||||
id_category: int = db.Column(db.Integer)
|
||||
name: str = db.Column(db.String(50))
|
||||
has_variations: str = db.Column(db.String(255))
|
||||
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))
|
||||
|
||||
@classmethod
|
||||
def from_product(cls, product):
|
||||
row = cls()
|
||||
row.id_product = product.id_product[0] if isinstance(product.id_product, tuple) else product.id_product
|
||||
row.id_category = product.id_category[0] if isinstance(product.id_category, tuple) else product.id_category
|
||||
row.name = product.name[0] if isinstance(product.name, tuple) else product.name
|
||||
row.id_access_level_required = product.id_access_level_required[0] if isinstance(product.id_access_level_required, tuple) else product.id_access_level_required
|
||||
row.active = product.active
|
||||
row.display_order = product.display_order
|
||||
return row
|
||||
def to_json(self):
|
||||
return {
|
||||
'id_product': self.id_product,
|
||||
'id_category': self.id_category,
|
||||
'name': self.name,
|
||||
'has_variations': self.has_variations,
|
||||
'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,
|
||||
}
|
||||
"""
|
||||
|
||||
class DataStore_Store_Product(DataStore_Store_Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@classmethod
|
||||
def save_products(cls, comment, products):
|
||||
_m = 'DataStore_Store_Product.save_products'
|
||||
Helper_App.console_log(f'{_m}\nstarting...')
|
||||
Helper_App.console_log(f'comment: {comment}\nproducts: {products}')
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid()
|
||||
user = cls.get_user_session()
|
||||
rows = []
|
||||
id_product_new = 0
|
||||
for product in products:
|
||||
row = Product_Temp.from_product(product)
|
||||
if row.id_product == '':
|
||||
id_product_new -= 1
|
||||
row.id_product = id_product_new
|
||||
else:
|
||||
Helper_App.console_log(f'row.id_product: {row.id_product}')
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
|
||||
Helper_App.console_log(f'rows: {rows}')
|
||||
DataStore_Store_Base.upload_bulk(Product_Temp.__tablename__, rows, 1000)
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0,
|
||||
}
|
||||
save_result = cls.db_procedure_execute('p_shop_save_product', argument_dict_list)
|
||||
|
||||
cursor = save_result # .cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# Errors
|
||||
# cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
try:
|
||||
DataStore_Store_Base.db_cursor_clear(cursor)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error clearing cursor: {e}')
|
||||
cursor.close()
|
||||
|
||||
save_result.close()
|
||||
Helper_App.console_log('save procedure executed')
|
||||
return errors
|
||||
|
||||
82
datastores/datastore_store_product_category.py
Normal file
82
datastores/datastore_store_product_category.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Product Category DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Product Categories
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category, Product_Category_Temp
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
# external
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class DataStore_Store_Product_Category(DataStore_Store_Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@classmethod
|
||||
def save_categories(cls, comment, categories):
|
||||
_m = 'DataStore_Store_Product_Category.save_categories'
|
||||
Helper_App.console_log(f'{_m}\nstarting...')
|
||||
Helper_App.console_log(f'comment: {comment}\ncategories: {categories}')
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid()
|
||||
now = datetime.now()
|
||||
user = cls.get_user_session()
|
||||
rows = []
|
||||
id_category_new = 0
|
||||
for category in categories:
|
||||
row = Product_Category_Temp.from_product_category(category)
|
||||
if row.id_category == '':
|
||||
id_category_new -= 1
|
||||
row.id_category = id_category_new
|
||||
else:
|
||||
Helper_App.console_log(f'row.id_category: {row.id_category}')
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
|
||||
Helper_App.console_log(f'rows: {rows}')
|
||||
DataStore_Store_Base.upload_bulk(Product_Category_Temp.__tablename__, rows, 1000)
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0,
|
||||
}
|
||||
save_result = cls.db_procedure_execute('p_shop_save_product_category', argument_dict_list)
|
||||
|
||||
# Errors
|
||||
cursor = save_result.cursor
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Product_Category.db_cursor_clear(cursor)
|
||||
|
||||
save_result.close()
|
||||
Helper_App.console_log('save procedure executed')
|
||||
return errors
|
||||
106
datastores/datastore_store_product_permutation.py
Normal file
106
datastores/datastore_store_product_permutation.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Product Permutation DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Product Permutations
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from business_objects.store.product_permutation import Product_Permutation, Product_Permutation_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
# db = SQLAlchemy()
|
||||
|
||||
|
||||
|
||||
class DataStore_Store_Product_Permutation(DataStore_Store_Base):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def save_permutations(cls, comment, permutations):
|
||||
_m = 'DataStore_Store_Product_Permutation.save_permutations'
|
||||
av.val_str(comment, 'comment', _m)
|
||||
# av.val_list(permutations, 'list_permutations', _m, Product_Permutation, 1)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
now = datetime.now()
|
||||
user = cls.get_user_session()
|
||||
rows = []
|
||||
for permutation in permutations:
|
||||
# row = permutation.to_temporary_record()
|
||||
row = Product_Permutation_Temp.from_product_permutation(permutation)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
|
||||
Helper_App.console_log(f'rows: {rows}')
|
||||
|
||||
"""
|
||||
cursor = db.cursor()
|
||||
Helper_App.console_log('cursor created')
|
||||
cursor.executemany(
|
||||
'''INSERT INTO Shop_Product_Permutation_Temp (
|
||||
id_permutation,
|
||||
id_product,
|
||||
description,
|
||||
cost_local,
|
||||
id_currency_cost,
|
||||
profit_local_min,
|
||||
latency_manufacture,
|
||||
id_unit_measurement_quantity,
|
||||
count_unit_measurement_quantity,
|
||||
quantity_min,
|
||||
quantity_max,
|
||||
quantity_stock,
|
||||
is_subscription,
|
||||
id_unit_measurement_interval_recurrence,
|
||||
count_interval_recurrence,
|
||||
id_stripe_product,
|
||||
does_expire_faster_once_unsealed,
|
||||
id_unit_measurement_interval_expiration_unsealed,
|
||||
count_interval_expiration_unsealed,
|
||||
active,
|
||||
guid
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)''',
|
||||
rows
|
||||
)
|
||||
Helper_App.console_log('cursor executed')
|
||||
db.commit()
|
||||
Helper_App.console_log('cursor committed')
|
||||
cursor.close()
|
||||
Helper_App.console_log('cursor closed')
|
||||
"""
|
||||
DataStore_Store_Base.upload_bulk(Product_Permutation_Temp.__tablename__, rows, 1000)
|
||||
Helper_App.console_log('bulk uploaded')
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0,
|
||||
}
|
||||
results = cls.db_procedure_execute('p_shop_save_product_permutation', argument_dict_list)
|
||||
DataStore_Store_Base.db_cursor_clear(results.cursor)
|
||||
Helper_App.console_log('saved product permutations')
|
||||
77
datastores/datastore_store_product_variation.py
Normal file
77
datastores/datastore_store_product_variation.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Product Variation DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Product Variations
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.product_variation import Product_Variation, Parameters_Product_Variation, Product_Variation_Temp
|
||||
from business_objects.store.product_variation_type import Product_Variation_Type, Product_Variation_Type_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
|
||||
class DataStore_Store_Product_Variation(DataStore_Store_Base):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@classmethod
|
||||
def save_product_variations(cls, comment, variation_types):
|
||||
_m = f'{cls.__class__}.save_product_variations'
|
||||
av.val_str(comment, 'comment', _m)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
user = cls.get_user_session()
|
||||
rows = []
|
||||
for variation_type in variation_types:
|
||||
row = Product_Variation_Type_Temp.from_product_variation_type(variation_type)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
Helper_App.console_log(f'rows: {rows}')
|
||||
|
||||
DataStore_Store_Base.upload_bulk(Product_Variation_Type_Temp.__tablename__, rows, 1000)
|
||||
Helper_App.console_log('bulk uploaded product variation types')
|
||||
|
||||
rows = []
|
||||
for variation_type in variation_types:
|
||||
if variation_type.variations is not None:
|
||||
for variation in variation_type.variations:
|
||||
row = Product_Variation_Temp.from_product_variation(variation)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
Helper_App.console_log(f'rows: {rows}')
|
||||
|
||||
DataStore_Store_Base.upload_bulk(Product_Variation_Temp.__tablename__, rows, 1000)
|
||||
Helper_App.console_log('bulk uploaded product variations')
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0,
|
||||
}
|
||||
cls.db_procedure_execute('p_shop_save_product_variation', argument_dict_list)
|
||||
Helper_App.console_log('saved product variations')
|
||||
146
datastores/datastore_store_stock_item.py
Normal file
146
datastores/datastore_store_stock_item.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Stock Item DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Stock Items
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item, Parameters_Stock_Item, Stock_Item_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
from extensions import db
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
# db = SQLAlchemy()
|
||||
|
||||
|
||||
class DataStore_Store_Stock_Item(DataStore_Store_Base):
|
||||
# Global constants
|
||||
# Attributes
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# Stock Items
|
||||
def get_many_stock_item(self, parameters_stock_item, category_list):
|
||||
# redundant argument validation?
|
||||
_m = 'DataStore_Store_Stock_Item.get_many_stock_item'
|
||||
av.val_instance(parameters_stock_item, 'parameters_stock_item', _m, Parameters_Stock_Item)
|
||||
argument_dict = parameters_stock_item.to_json()
|
||||
user = self.get_user_session()
|
||||
argument_dict = {
|
||||
'a_id_user': user.id_user
|
||||
, **argument_dict
|
||||
, 'a_debug': 0
|
||||
}
|
||||
ids_permutation = category_list.get_csv_ids_permutation()
|
||||
Helper_App.console_log(f'ids_permutation: {ids_permutation}')
|
||||
argument_dict['a_ids_product_permutation'] = ids_permutation
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
Helper_App.console_log('executing p_shop_get_many_stock_item')
|
||||
result = self.db_procedure_execute('p_shop_get_many_stock_item', argument_dict)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
category_list, errors = DataStore_Store_Stock_Item.input_many_stock_item(cursor, category_list)
|
||||
DataStore_Store_Stock_Item.db_cursor_clear(cursor)
|
||||
|
||||
return category_list, errors
|
||||
|
||||
|
||||
def input_many_stock_item(cursor, category_list):
|
||||
_m = 'DataStore_Store_Stock_Item.input_many_stock_item'
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw categories: {result_set_1}')
|
||||
for row in result_set_1:
|
||||
new_stock_item = Stock_Item.from_DB_stock_item(row)
|
||||
category_list.add_stock_item(new_stock_item) # , row)
|
||||
|
||||
# Errors
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
"""
|
||||
if len(errors) > 0:
|
||||
for error in errors:
|
||||
if error.code == 'PRODUCT_AVAILABILITY':
|
||||
ids_permutation_unavailable = DataStore_Store_Stock_Item.get_ids_permutation_from_error_availability(error.msg)
|
||||
for id_permutation in ids_permutation_unavailable:
|
||||
index_category = category_list.get_index_category_from_id_permutation(id_permutation)
|
||||
category = category_list.categories[index_category]
|
||||
index_product = category.get_index_product_from_id_permutation(id_permutation)
|
||||
product = category.products[index_product]
|
||||
index_permutation = product.get_index_permutation_from_id(id_permutation)
|
||||
permutation = product.permutations[index_permutation]
|
||||
permutation.is_available = False
|
||||
if 'region' in error.msg or 'currency' in error.msg:
|
||||
permutation.is_unavailable_in_currency_or_region = True
|
||||
"""
|
||||
DataStore_Store_Stock_Item.db_cursor_clear(cursor)
|
||||
return category_list, errors # categories, category_index
|
||||
|
||||
@classmethod
|
||||
def save_stock_items(cls, comment, stock_items):
|
||||
_m = 'DataStore_Store_Stock_Item.save_stock_items'
|
||||
av.val_str(comment, 'comment', _m)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
now = datetime.now()
|
||||
user = cls.get_user_session()
|
||||
rows = []
|
||||
for stock_item in stock_items:
|
||||
# row = permutation.to_temporary_record()
|
||||
row = Stock_Item_Temp.from_stock_item(stock_item)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
|
||||
Helper_App.console_log(f'rows: {rows}')
|
||||
|
||||
DataStore_Store_Base.upload_bulk(Stock_Item_Temp.__tablename__, rows, 1000)
|
||||
Helper_App.console_log('bulk uploaded')
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0
|
||||
}
|
||||
result = cls.db_procedure_execute('p_shop_save_stock_item', argument_dict_list)
|
||||
Helper_App.console_log('saved product permutations')
|
||||
|
||||
# Errors
|
||||
cursor = result.cursor
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
DataStore_Store_Stock_Item.db_cursor_clear(cursor)
|
||||
return errors
|
||||
143
datastores/datastore_store_supplier.py
Normal file
143
datastores/datastore_store_supplier.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Supplier DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Suppliers
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.supplier_address import Supplier_Address, Supplier_Address_Temp
|
||||
from business_objects.store.supplier import Supplier, Parameters_Supplier, Supplier_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
from extensions import db
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class DataStore_Store_Supplier(DataStore_Store_Base):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def get_many_supplier(cls, parameters_supplier):
|
||||
_m = 'DataStore_Store_Supplier.get_many_supplier'
|
||||
av.val_instance(parameters_supplier, 'parameters_supplier', _m, Parameters_Supplier)
|
||||
argument_dict = parameters_supplier.to_json()
|
||||
user = cls.get_user_session()
|
||||
argument_dict = {
|
||||
'a_id_user': user.id_user
|
||||
, **argument_dict
|
||||
, 'a_debug': 0
|
||||
}
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
Helper_App.console_log('executing p_shop_get_many_supplier')
|
||||
result = cls.db_procedure_execute('p_shop_get_many_supplier', argument_dict)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# Suppliers
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw suppliers: {result_set_1}')
|
||||
suppliers = []
|
||||
supplier_indexes = {}
|
||||
for row in result_set_1:
|
||||
new_supplier = Supplier.from_DB_supplier(row)
|
||||
supplier_indexes[new_supplier.id_supplier] = len(suppliers)
|
||||
suppliers.append(new_supplier)
|
||||
|
||||
# Supplier Addresses
|
||||
cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw supplier addresses: {result_set_1}')
|
||||
for row in result_set_1:
|
||||
new_address = Supplier_Address.from_DB_supplier(row)
|
||||
index_supplier = supplier_indexes[new_address.id_supplier]
|
||||
suppliers[index_supplier].addresses.append(new_address)
|
||||
|
||||
# Errors
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Supplier.db_cursor_clear(cursor)
|
||||
|
||||
return suppliers, errors
|
||||
|
||||
@classmethod
|
||||
def save_suppliers(cls, comment, suppliers):
|
||||
_m = 'DataStore_Store_Supplier.save_suppliers'
|
||||
Helper_App.console_log(f'{_m}\n{suppliers}')
|
||||
av.val_str(comment, 'comment', _m)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
now = datetime.now()
|
||||
user = cls.get_user_session()
|
||||
|
||||
rows = []
|
||||
for supplier in suppliers:
|
||||
row = Supplier_Temp.from_supplier(supplier)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
Helper_App.console_log(f'rows: {rows}')
|
||||
|
||||
DataStore_Store_Base.upload_bulk(Supplier_Temp.__tablename__, rows, 1000)
|
||||
Helper_App.console_log('bulk uploaded suppliers')
|
||||
|
||||
rows = []
|
||||
for supplier in suppliers:
|
||||
Helper_App.console_log(f'supplier: {supplier}')
|
||||
for supplier_address in supplier.addresses:
|
||||
row = Supplier_Address_Temp.from_supplier_address(supplier_address)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
Helper_App.console_log(f'rows: {rows}')
|
||||
|
||||
DataStore_Store_Base.upload_bulk(Supplier_Address_Temp.__tablename__, rows, 1000)
|
||||
Helper_App.console_log('bulk uploaded supplier addresses')
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0
|
||||
}
|
||||
result = cls.db_procedure_execute('p_shop_save_supplier', argument_dict_list)
|
||||
Helper_App.console_log('saved suppliers')
|
||||
|
||||
# Errors
|
||||
cursor = result.cursor
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Supplier.db_cursor_clear(cursor)
|
||||
return errors
|
||||
143
datastores/datastore_store_supplier_purchase_order.py
Normal file
143
datastores/datastore_store_supplier_purchase_order.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Supplier Purchase Order Purchase Order DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Supplier Purchase Order Purchase Orders
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.supplier_purchase_order import Supplier_Purchase_Order, Supplier_Purchase_Order_Product_Link, Parameters_Supplier_Purchase_Order, Supplier_Purchase_Order_Temp, Supplier_Purchase_Order_Product_Link_Temp
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
from extensions import db
|
||||
# external
|
||||
# from abc import ABC, abstractmethod, abstractproperty
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import text
|
||||
import stripe
|
||||
import os
|
||||
from flask import Flask, session, current_app
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import ClassVar
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class DataStore_Store_Supplier_Purchase_Order(DataStore_Store_Base):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_many_supplier_purchase_order(self, parameters_supplier_purchase_order):
|
||||
_m = 'DataStore_Store_Supplier_Purchase_Order.get_many_supplier_purchase_order'
|
||||
av.val_instance(parameters_supplier_purchase_order, 'parameters_supplier_purchase_order', _m, Parameters_Supplier_Purchase_Order)
|
||||
argument_dict = parameters_supplier_purchase_order.to_json()
|
||||
user = self.get_user_session()
|
||||
argument_dict = {
|
||||
'a_id_user': user.id_user
|
||||
, **argument_dict
|
||||
, 'a_debug': 0
|
||||
}
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
Helper_App.console_log('executing p_shop_get_many_supplier_purchase_order')
|
||||
result = self.db_procedure_execute('p_shop_get_many_supplier_purchase_order', argument_dict)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# Supplier_Purchase_Orders
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw supplier_purchase_orders: {result_set_1}')
|
||||
supplier_purchase_orders = []
|
||||
indices_supplier_purchase_order = {}
|
||||
for row in result_set_1:
|
||||
new_supplier_purchase_order = Supplier_Purchase_Order.from_DB_supplier_purchase_order(row)
|
||||
indices_supplier_purchase_order[new_supplier_purchase_order.id_order] = len(supplier_purchase_orders)
|
||||
supplier_purchase_orders.append(new_supplier_purchase_order)
|
||||
|
||||
# Supplier_Purchase_Orders Items
|
||||
cursor.nextset()
|
||||
result_set_2 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw supplier_purchase_order_product_links: {result_set_2}')
|
||||
order_product_links = []
|
||||
for row in result_set_2:
|
||||
new_link = Supplier_Purchase_Order_Product_Link.from_DB_supplier_purchase_order(row)
|
||||
order_product_links.append(new_link)
|
||||
supplier_purchase_orders[indices_supplier_purchase_order[new_link.id_order]].items.append(new_link)
|
||||
|
||||
|
||||
# Errors
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
if len(result_set_e) > 0:
|
||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Supplier_Purchase_Order.db_cursor_clear(cursor)
|
||||
|
||||
return supplier_purchase_orders, errors
|
||||
|
||||
@classmethod
|
||||
def save_supplier_purchase_orders(cls, comment, supplier_purchase_orders):
|
||||
_m = 'DataStore_Store_Supplier_Purchase_Order.save_supplier_purchase_orders'
|
||||
av.val_str(comment, 'comment', _m)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
now = datetime.now()
|
||||
user = cls.get_user_session()
|
||||
rows_order = []
|
||||
for supplier_purchase_order in supplier_purchase_orders:
|
||||
row = Supplier_Purchase_Order_Temp.from_supplier_purchase_order(supplier_purchase_order)
|
||||
row.guid = guid
|
||||
rows_order.append(row)
|
||||
Helper_App.console_log(f'order rows: {rows_order}')
|
||||
DataStore_Store_Base.upload_bulk(Supplier_Purchase_Order_Temp.__tablename__, rows_order, 1000)
|
||||
Helper_App.console_log('bulk uploaded orders')
|
||||
|
||||
rows_link = []
|
||||
for supplier_purchase_order in supplier_purchase_orders:
|
||||
for link in supplier_purchase_order.items:
|
||||
row = Supplier_Purchase_Order_Product_Link_Temp.from_supplier_purchase_order_product_link(link)
|
||||
row.guid = guid
|
||||
rows_link.append(row)
|
||||
Helper_App.console_log(f'link rows: {rows_link}')
|
||||
DataStore_Store_Base.upload_bulk(Supplier_Purchase_Order_Product_Link_Temp.__tablename__, rows_link, 1000)
|
||||
Helper_App.console_log('bulk uploaded links')
|
||||
|
||||
argument_dict_list = {
|
||||
'a_comment': comment,
|
||||
'a_guid': guid,
|
||||
'a_id_user': user.id_user,
|
||||
'a_debug': 0
|
||||
}
|
||||
result = cls.db_procedure_execute('p_shop_save_supplier_purchase_order', argument_dict_list)
|
||||
Helper_App.console_log('saved supplier purchase orders')
|
||||
|
||||
# Errors
|
||||
cursor = result.cursor
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||
errors = []
|
||||
warnings = []
|
||||
if len(result_set_e) > 0:
|
||||
for row in result_set_e:
|
||||
new_error = SQL_Error.from_DB_record(row)
|
||||
if new_error.code == 'WARNING':
|
||||
warnings.append(new_error)
|
||||
else:
|
||||
errors.append(new_error)
|
||||
Helper_App.console_log(f"Error [{new_error.code}]: {new_error.msg}")
|
||||
|
||||
cls.db_cursor_clear(cursor)
|
||||
return errors, warnings
|
||||
@@ -14,8 +14,10 @@ Datastore for Users
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item
|
||||
from business_objects.user import User, Parameters_User, User_Permission_Evaluation
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
# from datastores.datastore_base import DataStore_Base
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
@@ -34,7 +36,7 @@ from datetime import datetime
|
||||
db = SQLAlchemy()
|
||||
|
||||
|
||||
class DataStore_User(DataStore_Base):
|
||||
class DataStore_User(DataStore_Store_Base):
|
||||
# Global constants
|
||||
# Attributes
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Contact Us Form
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF form for handling user input on Contact Us page.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
# from business_objects.store.product_category import Filters_Product_Category # circular
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
from forms.base import Form_Base
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Form_Contact(FlaskForm):
|
||||
email = StringField('Email')
|
||||
contact_name = StringField('Name')
|
||||
company_name = StringField('Company')
|
||||
message = TextAreaField('Message')
|
||||
receive_marketing = BooleanField('I would like to receive marketing emails.')
|
||||
recaptcha = RecaptchaField()
|
||||
submit = SubmitField('Send Message')
|
||||
0
forms/store/__init__.py
Normal file
0
forms/store/__init__.py
Normal file
BIN
forms/store/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
forms/store/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/store/__pycache__/product.cpython-312.pyc
Normal file
BIN
forms/store/__pycache__/product.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/store/__pycache__/product_category.cpython-312.pyc
Normal file
BIN
forms/store/__pycache__/product_category.cpython-312.pyc
Normal file
Binary file not shown.
BIN
forms/store/__pycache__/product_permutation.cpython-312.pyc
Normal file
BIN
forms/store/__pycache__/product_permutation.cpython-312.pyc
Normal file
Binary file not shown.
40
forms/store/manufacturing_purchase_order.py
Normal file
40
forms/store/manufacturing_purchase_order.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Manufacturing Purchase Order Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling manufacturing purchase order filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField, DateField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Manufacturing_Purchase_Order(Form_Base):
|
||||
active = BooleanField("Active only?", default = True)
|
||||
date_from = DateField('Date from')
|
||||
date_to = DateField('Date to')
|
||||
def __repr__(self):
|
||||
return f'Filters_Manufacturing_Purchase_Order(active={self.active.data}, date_from={self.date_from.data}, date_to={self.date_to.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = f'{cls.__name__}.from_json'
|
||||
form = cls()
|
||||
form.active.data = av.input_bool(json[Store_Base.FLAG_ACTIVE], 'active', _m)
|
||||
if json[Store_Base.FLAG_DATE_FROM] != '':
|
||||
form.date_from.data = json[Store_Base.FLAG_DATE_FROM]
|
||||
if json[Store_Base.FLAG_DATE_TO] != '':
|
||||
form.date_to.data = json[Store_Base.FLAG_DATE_TO]
|
||||
return form
|
||||
43
forms/store/product.py
Normal file
43
forms/store/product.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Product Filter data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling user input.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
# from business_objects.store.product_category import Filters_Product_Category
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
|
||||
|
||||
class Filters_Product(FlaskForm):
|
||||
id_category = SelectField('Category', validators=[Optional()], choices=[('', 'All')], default='')
|
||||
is_not_empty = BooleanField('Not empty only?')
|
||||
active = BooleanField("Active only?", default = True)
|
||||
@classmethod
|
||||
def from_filters_product(cls, filters_product):
|
||||
form = Filters_Product()
|
||||
form.id_category = filters_product.id_category
|
||||
form.is_not_empty.data = filters_product.is_not_empty
|
||||
form.active.data = filters_product.active
|
||||
return form
|
||||
def __repr__(self):
|
||||
return f'Filters_Product(id_category={self.id_category}, is_not_empty={self.is_not_empty.data}, active={self.active.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
filters = cls()
|
||||
filters.id_category.data = json['id_category']
|
||||
filters.is_not_empty.data = json['is_not_empty']
|
||||
filters.active.data = json['active']
|
||||
return filters
|
||||
47
forms/store/product_category.py
Normal file
47
forms/store/product_category.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Product Category Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling product category filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
# from business_objects.store.product_category import Filters_Product_Category
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
# from helpers.DEPRECATED.helper_abc import Interface_ABC
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Product_Category(Form_Base):
|
||||
is_not_empty = BooleanField('Not empty only?')
|
||||
active = BooleanField("Active only?", default = True)
|
||||
"""
|
||||
@classmethod
|
||||
def from_filters(cls, filters):
|
||||
form = Filters_Product_Category()
|
||||
form.is_not_empty.data = filters.is_not_empty
|
||||
form.active.data = filters.active
|
||||
return form
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'Filters_Product_Category(is_not_empty={self.is_not_empty.data}, active={self.active.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = f'{cls.__name__}.from_json'
|
||||
form = Filters_Product_Category() # is_not_empty=json['is_not_empty'], active=json['active'])
|
||||
form.is_not_empty.data = av.input_bool(json[Store_Base.FLAG_IS_NOT_EMPTY], 'is_not_empty', _m)
|
||||
form.active.data = av.input_bool(json[Store_Base.FLAG_ACTIVE], 'active', _m)
|
||||
return form
|
||||
68
forms/store/product_permutation.py
Normal file
68
forms/store/product_permutation.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Product Category Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling product category filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
# from business_objects.store.product_category import Filters_Product_Category
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
# from helpers.DEPRECATED.helper_abc import Interface_ABC
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Product_Permutation(Form_Base):
|
||||
id_category = SelectField('Category', validators=[Optional()], choices=[('', 'All')], default='')
|
||||
id_product = SelectField('Product', validators=[Optional()], choices=[('', 'All')], default='')
|
||||
is_out_of_stock = BooleanField('Out of stock only?')
|
||||
active = BooleanField('Active only?', default=True)
|
||||
quantity_min = FloatField('Min stock')
|
||||
quantity_max = FloatField('Max stock')
|
||||
# submit = SubmitField('Submit')
|
||||
"""
|
||||
@classmethod
|
||||
def from_filters(cls, filters):
|
||||
form = Filters_Product_Permutation()
|
||||
form.id_category.choices = Store_Base.convert_list_objects_to_list_options(filters.categories)
|
||||
form.id_product.choices = Store_Base.convert_list_objects_to_list_options(filters.products)
|
||||
form.is_out_of_stock.data = filters.is_out_of_stock
|
||||
form.quantity_min.data = filters.quantity_min
|
||||
form.quantity_max.data = filters.quantity_max
|
||||
return form
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
Filters_Product_Permutation(
|
||||
id_category={self.id_category.data},
|
||||
id_product={self.id_product.data},
|
||||
is_out_of_stock={self.is_out_of_stock.data},
|
||||
active={self.active.data},
|
||||
quantity_min={self.quantity_min.data},
|
||||
quantity_max={self.quantity_max.data})
|
||||
'''
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
form = cls()
|
||||
form.id_category.choices = [(json[Store_Base.ATTR_ID_PRODUCT_CATEGORY], json[Store_Base.ATTR_ID_PRODUCT_CATEGORY])]
|
||||
form.id_category.data = json[Store_Base.ATTR_ID_PRODUCT_CATEGORY]
|
||||
form.id_product.choices = [(json[Store_Base.ATTR_ID_PRODUCT], json[Store_Base.ATTR_ID_PRODUCT])]
|
||||
form.id_product.data = json[Store_Base.ATTR_ID_PRODUCT]
|
||||
form.is_out_of_stock.data = av.input_bool(json[Store_Base.FLAG_IS_OUT_OF_STOCK], Store_Base.FLAG_IS_OUT_OF_STOCK, f'{cls.__name__}.from_json')
|
||||
form.active.data = av.input_bool(json[Store_Base.FLAG_ACTIVE], Store_Base.FLAG_ACTIVE, f'{cls.__name__}.from_json')
|
||||
form.quantity_min.data = json[Store_Base.FLAG_QUANTITY_MIN]
|
||||
form.quantity_max.data = json[Store_Base.FLAG_QUANTITY_MAX]
|
||||
return form
|
||||
38
forms/store/product_variation.py
Normal file
38
forms/store/product_variation.py
Normal file
@@ -0,0 +1,38 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Product Variation Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling product variation filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from forms.base import Form_Base
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField, DateField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Product_Variation(Form_Base):
|
||||
is_not_empty = BooleanField('Not empty only?')
|
||||
active = BooleanField("Active only?", default = True)
|
||||
def __repr__(self):
|
||||
return f'Filters_Product_Variation(is_not_empty={self.is_not_empty.data}, active={self.active.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = f'{cls.__name__}.from_json'
|
||||
Helper_App.console_log(f'{_m}\njson={json}')
|
||||
form = cls()
|
||||
form.is_not_empty.data = av.input_bool(json[Store_Base.FLAG_IS_NOT_EMPTY], Store_Base.FLAG_IS_NOT_EMPTY, _m)
|
||||
form.active.data = av.input_bool(json[Store_Base.FLAG_ACTIVE], Store_Base.FLAG_ACTIVE, _m)
|
||||
return form
|
||||
76
forms/store/stock_item.py
Normal file
76
forms/store/stock_item.py
Normal file
@@ -0,0 +1,76 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Product Category Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling product category filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
# from business_objects.store.product_category import Filters_Product_Category
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
# from helpers.DEPRECATED.helper_abc import Interface_ABC
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
class Filters_Stock_Item(Form_Base):
|
||||
id_category = SelectField('Category', choices=[Form_Base.get_choice_all()], default='')
|
||||
id_product = SelectField('Product', choices=[Form_Base.get_choice_all()], default='')
|
||||
is_out_of_stock = BooleanField('Out of stock only?')
|
||||
quantity_min = FloatField('Min stock')
|
||||
quantity_max = FloatField('Max stock')
|
||||
# submit = SubmitField('Submit')
|
||||
"""
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.__class__.__name__}(
|
||||
id_category={self.id_category.data},
|
||||
id_product={self.id_product.data},
|
||||
is_out_of_stock={self.is_out_of_stock.data},
|
||||
quantity_min={self.quantity_min.data},
|
||||
quantity_max={self.quantity_max.data})
|
||||
'''
|
||||
"""
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
form = cls()
|
||||
# form.id_category.choices = [(json[Store_Base.ATTR_ID_PRODUCT_CATEGORY], json[Store_Base.ATTR_ID_PRODUCT_CATEGORY])]
|
||||
form.id_category.data = json[Store_Base.ATTR_ID_PRODUCT_CATEGORY]
|
||||
# form.id_product.choices = [(json[Store_Base.ATTR_ID_PRODUCT], json[Store_Base.ATTR_ID_PRODUCT])]
|
||||
form.id_product.data = json[Store_Base.ATTR_ID_PRODUCT]
|
||||
form.is_out_of_stock.data = av.input_bool(json[Store_Base.FLAG_IS_OUT_OF_STOCK], Store_Base.FLAG_IS_OUT_OF_STOCK, f'{cls.__name__}.from_json')
|
||||
form.quantity_min.data = json[Store_Base.FLAG_QUANTITY_MIN]
|
||||
form.quantity_max.data = json[Store_Base.FLAG_QUANTITY_MAX]
|
||||
return form
|
||||
def to_json(self):
|
||||
return {
|
||||
Store_Base.ATTR_ID_PRODUCT_CATEGORY: self.id_category.data,
|
||||
Store_Base.ATTR_ID_PRODUCT: self.id_product.data,
|
||||
Store_Base.FLAG_IS_OUT_OF_STOCK: self.is_out_of_stock.data,
|
||||
Store_Base.FLAG_QUANTITY_MIN: self.quantity_min.data,
|
||||
Store_Base.FLAG_QUANTITY_MAX: self.quantity_max.data
|
||||
}
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
filters = cls()
|
||||
filters.id_category.choices = cls.get_choices_blank()
|
||||
filters.id_product.choices = cls.get_choices_blank()
|
||||
"""
|
||||
def import_values(self, form_filters):
|
||||
self.id_category.data = form_filters.id_category.data
|
||||
self.id_product.data = form_filters.id_product.data
|
||||
self.is_out_of_stock.data = form_filters.is_out_of_stock.data
|
||||
self.quantity_min.data = form_filters.quantity_min.data
|
||||
self.quantity_max.data = form_filters.quantity_max.data
|
||||
"""
|
||||
34
forms/store/supplier.py
Normal file
34
forms/store/supplier.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Supplier Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling supplier filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Supplier(Form_Base):
|
||||
active = BooleanField("Active only?", default = True)
|
||||
def __repr__(self):
|
||||
return f'Filters_Supplier(active={self.active.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = f'{cls.__name__}.from_json'
|
||||
form = cls()
|
||||
form.active.data = av.input_bool(json[Store_Base.FLAG_ACTIVE], 'active', _m)
|
||||
return form
|
||||
40
forms/store/supplier_purchase_order.py
Normal file
40
forms/store/supplier_purchase_order.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Backend
|
||||
Feature: Forms - Supplier Purchase Order Filters data input
|
||||
|
||||
Description:
|
||||
Defines Flask-WTF forms for handling supplier purchase order filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, BooleanField, IntegerField, SelectField, FloatField, DateField
|
||||
from wtforms.validators import InputRequired, NumberRange, Regexp, DataRequired, Optional
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class Filters_Supplier_Purchase_Order(Form_Base):
|
||||
active = BooleanField("Active only?", default = True)
|
||||
date_from = DateField('Date from')
|
||||
date_to = DateField('Date to')
|
||||
def __repr__(self):
|
||||
return f'Filters_Supplier_Purchase_Order(active={self.active.data}, date_from={self.date_from.data}, date_to={self.date_to.data})'
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = f'{cls.__name__}.from_json'
|
||||
form = cls()
|
||||
form.active.data = av.input_bool(json[Store_Base.FLAG_ACTIVE], 'active', _m)
|
||||
if json[Store_Base.FLAG_DATE_FROM] != '':
|
||||
form.date_from.data = json[Store_Base.FLAG_DATE_FROM]
|
||||
if json[Store_Base.FLAG_DATE_TO] != '':
|
||||
form.date_to.data = json[Store_Base.FLAG_DATE_TO]
|
||||
return form
|
||||
@@ -11,7 +11,7 @@ Defines Flask-WTF forms for handling unit of measurement filter input.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from forms.base import Form_Base
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
@@ -34,9 +34,9 @@ class Filters_Unit_Measurement(Form_Base):
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
form = Filters_Unit_Measurement()
|
||||
form.active.data = av.input_bool(json[Base.FLAG_ACTIVE], 'active', 'Filters_Unit_Measurement')
|
||||
form.active.data = av.input_bool(json[Store_Base.FLAG_ACTIVE], 'active', 'Filters_Unit_Measurement')
|
||||
return form
|
||||
def to_json(self):
|
||||
return {
|
||||
Base.FLAG_ACTIVE: av.input_bool(self.active.data, Base.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
Store_Base.FLAG_ACTIVE: av.input_bool(self.active.data, Store_Base.FLAG_ACTIVE, f'{self.__class__.__name__}.to_json'),
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
26
models/model_view_admin.py
Normal file
26
models/model_view_admin.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: View Models
|
||||
Feature: Store Permutations View Model
|
||||
|
||||
Description:
|
||||
Data model for store permutations view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from helpers.helper_app import Helper_App
|
||||
from models.model_view_base import Model_View_Base
|
||||
|
||||
# external
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
class Model_View_Admin(Model_View_Base):
|
||||
|
||||
def __init__(self, hash_page_current, **kwargs):
|
||||
_m = 'Model_View_Admin.__init__'
|
||||
Helper_App.console_log(f'{_m}\nstarting')
|
||||
super().__init__(hash_page_current=hash_page_current, **kwargs)
|
||||
27
models/model_view_admin_home.py
Normal file
27
models/model_view_admin_home.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: View Models
|
||||
Feature: Admin Home View Model
|
||||
|
||||
Description:
|
||||
Data model for admin home view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_admin import Model_View_Admin
|
||||
|
||||
# external
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
class Model_View_Admin_Home(Model_View_Admin):
|
||||
@property
|
||||
def title(self):
|
||||
return 'Admin Home'
|
||||
|
||||
def __init__(self, hash_page_current=Model_View_Admin.HASH_PAGE_ADMIN_HOME):
|
||||
super().__init__(hash_page_current=hash_page_current)
|
||||
|
||||
@@ -18,6 +18,7 @@ Base data model for views
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
from business_objects.base import Base
|
||||
from business_objects.store.product_category import Product_Category
|
||||
from business_objects.user import User, Parameters_User
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
from datastores.datastore_user import DataStore_User
|
||||
@@ -45,10 +46,8 @@ class Model_View_Base(BaseModel, ABC):
|
||||
ATTR_TEXT_EXPANDED: ClassVar[str] = 'textExpanded'
|
||||
ATTR_VALUE_CURRENT: ClassVar[str] = 'current-value'
|
||||
ATTR_VALUE_PREVIOUS: ClassVar[str] = 'previous-value'
|
||||
COMPANY_ADDRESS_SHORT: ClassVar[str] = '53 Alfred Green Close, Rugby, United Kingdom, CV22 6DN'
|
||||
COMPANY_NUMBER: ClassVar[str] = '13587499'
|
||||
FLAG_ACCESS_LEVEL: ClassVar[str] = 'access_level'
|
||||
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = Base.FLAG_ACCESS_LEVEL_REQUIRED
|
||||
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = Product_Category.FLAG_ACCESS_LEVEL_REQUIRED
|
||||
FLAG_ACTIVE: ClassVar[str] = Base.FLAG_ACTIVE
|
||||
FLAG_ADD: ClassVar[str] = 'add'
|
||||
# FLAG_ADD_DELETE: ClassVar[str] = 'add-delete'
|
||||
@@ -57,9 +56,6 @@ class Model_View_Base(BaseModel, ABC):
|
||||
FLAG_ADDRESS_LINE_2: ClassVar[str] = Base.FLAG_ADDRESS_LINE_2
|
||||
FLAG_BOOL_FALSE: ClassVar[str] = 'false'
|
||||
FLAG_BOOL_TRUE: ClassVar[str] = 'true'
|
||||
FLAG_BUTTON: ClassVar[str] = 'button'
|
||||
FLAG_BUTTON_LIGHT: ClassVar[str] = 'button-light'
|
||||
FLAG_BUTTON_PRIMARY: ClassVar[str] = 'button-primary'
|
||||
FLAG_CANCEL: ClassVar[str] = 'button-cancel'
|
||||
FLAG_CALLBACK: ClassVar[str] = 'callback'
|
||||
FLAG_CARD: ClassVar[str] = 'card'
|
||||
@@ -72,9 +68,8 @@ class Model_View_Base(BaseModel, ABC):
|
||||
FLAG_COMMENT: ClassVar[str] = 'comment'
|
||||
# FLAG_CONTACT_US: ClassVar[str] = 'button-contact'
|
||||
FLAG_CONTAINER: ClassVar[str] = 'container'
|
||||
FLAG_CONTAINER_CHECKBOX: ClassVar[str] = 'container-checkbox'
|
||||
FLAG_CONTAINER_ICON_AND_LABEL: ClassVar[str] = 'container-icon-label'
|
||||
FLAG_CONTAINER_INPUT: ClassVar[str] = 'container-input'
|
||||
FLAG_CONTAINER_INPUT: ClassVar[str] = FLAG_CONTAINER + '-input'
|
||||
FLAG_COUNTY: ClassVar[str] = Base.FLAG_COUNTY
|
||||
FLAG_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
||||
FLAG_CURRENCY: ClassVar[str] = 'currency'
|
||||
@@ -100,9 +95,8 @@ class Model_View_Base(BaseModel, ABC):
|
||||
FLAG_IMAGE_LOGO: ClassVar[str] = 'image-logo'
|
||||
FLAG_INITIALISED: ClassVar[str] = 'initialised'
|
||||
FLAG_IS_INCLUDED_VAT: ClassVar[str] = 'is_included_VAT'
|
||||
FLAG_LEFT_HAND_STUB: ClassVar[str] = 'lhs'
|
||||
FLAG_LOGO: ClassVar[str] = 'logo'
|
||||
FLAG_MESSAGE: ClassVar[str] = 'message'
|
||||
# FLAG_KEY_PRIMARY: ClassVar[str] = Store_Base.FLAG_KEY_PRIMARY
|
||||
FLAG_MESSAGE: ClassVar[str] = 'Message'
|
||||
FLAG_MODAL: ClassVar[str] = 'modal'
|
||||
FLAG_NAME: ClassVar[str] = Base.FLAG_NAME
|
||||
FLAG_NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_TEXT
|
||||
@@ -133,7 +127,6 @@ class Model_View_Base(BaseModel, ABC):
|
||||
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
|
||||
FLAG_PHONE_NUMBER: ClassVar[str] = Base.FLAG_PHONE_NUMBER
|
||||
FLAG_POSTCODE: ClassVar[str] = Base.FLAG_POSTCODE
|
||||
FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
|
||||
FLAG_ROW: ClassVar[str] = 'row'
|
||||
FLAG_ROW_NEW: ClassVar[str] = 'row-new'
|
||||
FLAG_ROWS: ClassVar[str] = Base.FLAG_ROWS
|
||||
@@ -160,10 +153,24 @@ class Model_View_Base(BaseModel, ABC):
|
||||
HASH_PAGE_LICENSE: ClassVar[str] = '/license'
|
||||
HASH_PAGE_PRIVACY_POLICY: ClassVar[str] = '/privacy-policy'
|
||||
HASH_PAGE_SERVICES: ClassVar[str] = '/services'
|
||||
# HASH_PAGE_STORE_ADMIN: ClassVar[str] = '/store/admin'
|
||||
HASH_PAGE_STORE_BASKET: ClassVar[str] = '/store/basket'
|
||||
HASH_PAGE_STORE_CUSTOMER_SALES_ORDERS: ClassVar[str] = '/store/customer_sales_orders'
|
||||
HASH_PAGE_STORE_HOME: ClassVar[str] = '/store'
|
||||
HASH_PAGE_STORE_MANUFACTURING_PURCHASE_ORDERS: ClassVar[str] = '/store/manufacturing_purchase_orders'
|
||||
HASH_PAGE_STORE_PRODUCT_CATEGORIES: ClassVar[str] = '/store/categories'
|
||||
HASH_PAGE_STORE_PRODUCTS: ClassVar[str] = '/store/products'
|
||||
HASH_PAGE_STORE_PRODUCT_PERMUTATIONS: ClassVar[str] = '/store/permutations'
|
||||
HASH_PAGE_STORE_PRODUCT_PRICES: ClassVar[str] = '/store/prices'
|
||||
HASH_PAGE_STORE_PRODUCT_VARIATIONS: ClassVar[str] = '/store/variations'
|
||||
HASH_PAGE_STORE_STOCK_ITEMS: ClassVar[str] = '/store/stock_items'
|
||||
HASH_PAGE_STORE_SUPPLIERS: ClassVar[str] = '/store/suppliers'
|
||||
HASH_PAGE_STORE_SUPPLIER_PURCHASE_ORDERS: ClassVar[str] = '/store/supplier_purchase_orders'
|
||||
HASH_PAGE_USER_ACCOUNT: ClassVar[str] = '/user'
|
||||
HASH_PAGE_USER_ADMIN: ClassVar[str] = '/user/admin'
|
||||
HASH_PAGE_USER_LOGIN: ClassVar[str] = '/login'
|
||||
HASH_PAGE_USER_LOGOUT: ClassVar[str] = '/logout'
|
||||
HASH_SCRIPTS_SECTION_STORE: ClassVar[str] = '/scripts_store'
|
||||
ID_BUTTON_ADD: ClassVar[str] = 'buttonAdd'
|
||||
ID_BUTTON_APPLY_FILTERS: ClassVar[str] = 'buttonApplyFilters'
|
||||
ID_BUTTON_CANCEL: ClassVar[str] = 'buttonCancel'
|
||||
@@ -185,6 +192,14 @@ class Model_View_Base(BaseModel, ABC):
|
||||
# ID_BUTTON_NAV_CONTACT: ClassVar[str] = 'navContact'
|
||||
ID_BUTTON_NAV_HOME: ClassVar[str] = 'navHome'
|
||||
ID_BUTTON_NAV_SERVICES: ClassVar[str] = 'navServices'
|
||||
ID_BUTTON_NAV_STORE_HOME: ClassVar[str] = 'navStoreHome'
|
||||
ID_BUTTON_NAV_STORE_PRODUCT: ClassVar[str] = 'navStoreProduct'
|
||||
ID_BUTTON_NAV_STORE_PRODUCT_CATEGORIES: ClassVar[str] = 'navStoreProductCategories'
|
||||
ID_BUTTON_NAV_STORE_PRODUCT_PERMUTATIONS: ClassVar[str] = 'navStoreProductPermutations'
|
||||
ID_BUTTON_NAV_STORE_PRODUCT_PRICES: ClassVar[str] = 'navStoreProductPrices'
|
||||
ID_BUTTON_NAV_STORE_PRODUCT_VARIATIONS: ClassVar[str] = 'navStoreProductVariations'
|
||||
ID_BUTTON_NAV_STORE_STOCK_ITEMS: ClassVar[str] = 'navStoreStockItems'
|
||||
ID_BUTTON_NAV_USER_ACCOUNT: ClassVar[str] = 'navUserAccount'
|
||||
ID_BUTTON_NAV_USER_ADMIN: ClassVar[str] = 'navUserAdmin'
|
||||
ID_BUTTON_NAV_USER_LOGIN: ClassVar[str] = 'navUserLogin'
|
||||
ID_BUTTON_NAV_USER_LOGOUT: ClassVar[str] = 'navUserLogout'
|
||||
@@ -196,7 +211,6 @@ class Model_View_Base(BaseModel, ABC):
|
||||
ID_TABLE_MAIN: ClassVar[str] = 'tableMain'
|
||||
ID_TEXTAREA_CONFIRM: ClassVar[str] = 'textareaConfirm'
|
||||
NAME_COMPANY: ClassVar[str] = 'Precision And Research Technology Systems Limited'
|
||||
NAME_COMPANY_SHORT: ClassVar[str] = 'PARTS Ltd'
|
||||
NAME_CSRF_TOKEN: ClassVar[str] = 'csrf-token'
|
||||
# URL_HOST: ClassVar[str] = os.env() 'http://127.0.0.1:5000' # 'https://www.partsltd.co.uk'
|
||||
URL_GITHUB: ClassVar[str] = 'https://github.com/Teddy-1024'
|
||||
@@ -378,6 +392,4 @@ class Model_View_Base(BaseModel, ABC):
|
||||
return date_time.strftime('%Y-%m-%dT%H:%M')
|
||||
@staticmethod
|
||||
def jsonify(data):
|
||||
return jsonify(data)
|
||||
def get_mail_contact_public(self):
|
||||
return self.app.config['MAIL_CONTACT_PUBLIC']
|
||||
return jsonify(data)
|
||||
@@ -14,27 +14,18 @@ Data model for contact view
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
from lib import argument_validation as av
|
||||
from forms.contact import Form_Contact
|
||||
from forms.forms import Form_Contact
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from abc import abstractproperty
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
class Model_View_Contact(Model_View_Base):
|
||||
# Attributes
|
||||
FLAG_COMPANY_NAME: ClassVar[str] = 'company_name'
|
||||
FLAG_CONTACT_NAME: ClassVar[str] = 'contact_name'
|
||||
FLAG_RECEIVE_MARKETING: ClassVar[str] = 'receive_marketing'
|
||||
"""
|
||||
ID_EMAIL: ClassVar[str] = 'email'
|
||||
ID_COMPANY_NAME: ClassVar[str] = 'company_name'
|
||||
ID_CONTACT_NAME: ClassVar[str] = 'contact_name'
|
||||
ID_MESSAGE: ClassVar[str] = 'msg'
|
||||
ID_RECEIVE_MARKETING: ClassVar[str] = 'receive_marketing'
|
||||
ID_NAME: ClassVar[str] = 'name'
|
||||
"""
|
||||
|
||||
ID_EMAIL: str = 'email'
|
||||
ID_MESSAGE: str = 'msg'
|
||||
ID_NAME: str = 'name'
|
||||
|
||||
form_contact: Form_Contact
|
||||
|
||||
@property
|
||||
|
||||
27
models/model_view_services.py
Normal file
27
models/model_view_services.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: View Models
|
||||
Feature: Services View Model
|
||||
|
||||
Description:
|
||||
Data model for services view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
# external
|
||||
|
||||
class Model_View_Services(Model_View_Base):
|
||||
# Attributes
|
||||
@property
|
||||
def title(self):
|
||||
return 'Services'
|
||||
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_SERVICES):
|
||||
# Constructor
|
||||
super().__init__(hash_page_current=hash_page_current)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user