Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a8799058e | |||
| 8485b8a24d | |||
| 4f5037b504 | |||
| 63776954e1 | |||
| dd608022cd | |||
| 4add7e626e | |||
| 1a7b72022d | |||
| 90cf9eaee7 | |||
|
|
7b9e900cfe | ||
| bade1f11dd | |||
| b843849af9 | |||
| 29205de12f | |||
| a105372638 | |||
| 7e8266d735 | |||
| cc6c3699f6 | |||
| d84cc29edb | |||
|
|
2fcd7f4276 | ||
| 56ed26b3f0 | |||
| 18a9a65f70 | |||
|
|
d07f409426 | ||
|
|
2461aef77b | ||
| baa158fcd0 | |||
| 2f63d27c5b | |||
| e7231cb67a | |||
| d1b90db6d7 | |||
| 120cccd0d5 | |||
| 2364931054 | |||
| decab6a638 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,6 +11,7 @@ __pycache__/
|
||||
|
||||
# Ignore logs and databases
|
||||
*.log
|
||||
*.log.*
|
||||
|
||||
# Ignore logs and databases
|
||||
# *.sql
|
||||
|
||||
56
app.py
56
app.py
@@ -17,19 +17,10 @@ Initializes the Flask application, sets the configuration based on the environme
|
||||
# IMPORTS
|
||||
# internal
|
||||
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 controllers.core.contact import routes_core_contact
|
||||
from controllers.core.home import routes_core_home
|
||||
from controllers.legal.legal import routes_legal
|
||||
from extensions import db, csrf, mail, oauth
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session
|
||||
@@ -50,6 +41,7 @@ sys.path.insert(0, os.path.dirname(__file__)) # Todo: why?
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = os.getenv('KEY_SECRET_FLASK')
|
||||
|
||||
# AppConfig(app)
|
||||
app.config.from_object(app_config) # for db init with required keys
|
||||
@@ -82,12 +74,13 @@ def make_session_permanent():
|
||||
session.permanent = True
|
||||
|
||||
csrf = CSRFProtect()
|
||||
"""
|
||||
cors = CORS()
|
||||
db = SQLAlchemy()
|
||||
mail = Mail()
|
||||
oauth = OAuth()
|
||||
"""
|
||||
cors = CORS(app, resources={
|
||||
r"/static/*": {
|
||||
"origins": [app.config["URL_HOST"]],
|
||||
"methods": ["GET"],
|
||||
"max_age": 3600
|
||||
}
|
||||
})
|
||||
|
||||
csrf.init_app(app)
|
||||
cors.init_app(app)
|
||||
@@ -114,22 +107,23 @@ with app.app_context():
|
||||
)
|
||||
|
||||
|
||||
app.register_blueprint(routes_core)
|
||||
app.register_blueprint(routes_core_home)
|
||||
app.register_blueprint(routes_core_contact)
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@app.template_filter('console_log')
|
||||
def console_log(value):
|
||||
Helper_App.console_log(value)
|
||||
return value
|
||||
return value
|
||||
|
||||
@app.after_request
|
||||
def add_cache_headers(response):
|
||||
if request.path.startswith('/static/'):
|
||||
# Cache static assets
|
||||
response.headers['Cache-Control'] = 'public, max-age=31536000'
|
||||
else:
|
||||
# No caching for dynamic content
|
||||
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
||||
return response
|
||||
Binary file not shown.
@@ -1,107 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Address Business Object
|
||||
|
||||
Description:
|
||||
Business object for address
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.base import 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 Address(db.Model, 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] = Base.ATTR_ID_ADDRESS
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_POSTCODE
|
||||
__tablename__ = 'Shop_Address'
|
||||
id_address = db.Column(db.Integer, primary_key=True)
|
||||
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__()
|
||||
Base.__init__(self)
|
||||
self.region = None
|
||||
@classmethod
|
||||
def from_DB_storage_location(cls, query_row):
|
||||
address = cls()
|
||||
address.id_address = query_row[2]
|
||||
address.id_region = query_row[3]
|
||||
return address
|
||||
@classmethod
|
||||
def from_DB_plant(cls, query_row):
|
||||
address = cls()
|
||||
address.id_address = query_row[1]
|
||||
address.id_region = query_row[2]
|
||||
return address
|
||||
@classmethod
|
||||
def from_DB_stock_item(cls, query_row):
|
||||
address = cls()
|
||||
address.id_address = query_row[6]
|
||||
address.id_region = query_row[7]
|
||||
return address
|
||||
@classmethod
|
||||
def from_DB_supplier(cls, query_row):
|
||||
address = cls()
|
||||
address.id_address = query_row[1]
|
||||
address.postcode = query_row[2]
|
||||
return address
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_ADDRESS}: {self.id_address}
|
||||
{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):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_ADDRESS: self.id_address,
|
||||
self.FLAG_REGION: None if self.region is None else 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.region = Region.from_json(json[cls.FLAG_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
|
||||
32
business_objects/api.py
Normal file
32
business_objects/api.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Base Business Object
|
||||
|
||||
Description:
|
||||
Abstract business object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from extensions import db
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from typing import ClassVar
|
||||
from flask import jsonify
|
||||
|
||||
|
||||
class API():
|
||||
|
||||
@staticmethod
|
||||
def get_standard_response(success: bool, status_code: int, message: str, data: any, errors: list, meta: dict):
|
||||
return jsonify({
|
||||
"success": success,
|
||||
"status_code": status_code,
|
||||
"message": message,
|
||||
"data": data,
|
||||
"errors": errors,
|
||||
"meta": meta
|
||||
})
|
||||
@@ -7,7 +7,7 @@ Technology: Business Objects
|
||||
Feature: Base Business Object
|
||||
|
||||
Description:
|
||||
Abstract business object
|
||||
Abstract base class for all business objects in app
|
||||
"""
|
||||
|
||||
# internal
|
||||
@@ -67,6 +67,7 @@ class Base():
|
||||
FLAG_VALUE_LOCAL_VAT_EXCL: ClassVar[str] = 'value_local_vat_excl'
|
||||
FLAG_VALUE_LOCAL_VAT_INCL: ClassVar[str] = 'value_local_vat_incl'
|
||||
FLAG_WEBSITE: ClassVar[str] = 'website'
|
||||
ID_USER_GUEST: ClassVar[int] = 3
|
||||
"""
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'name-attribute-option-text'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = 'name-attribute-option-value'
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
"""
|
||||
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.store_base import Store_Base
|
||||
from extensions import db
|
||||
from lib import argument_validation as av
|
||||
# external
|
||||
from typing import ClassVar
|
||||
|
||||
# CLASSES
|
||||
"""
|
||||
class Currency_Enum(Enum):
|
||||
GBP = 1
|
||||
|
||||
def text(self):
|
||||
return Currency_Enum.Currency_Enum_Text(self)
|
||||
|
||||
def Currency_Enum_Text(currency):
|
||||
av.val_instance(currency, 'currency', 'Currency_Enum_Text', Currency_Enum)
|
||||
if currency == Currency_Enum.GBP:
|
||||
return 'GBP'
|
||||
else:
|
||||
# return 'Unknown'
|
||||
raise ValueError("Unknown Currency Enum.")
|
||||
|
||||
def get_member_by_text(text):
|
||||
for member in Resolution_Level_Enum.__members__.values():
|
||||
if member.name == text:
|
||||
return member
|
||||
raise ValueError("Unknown Currency Enum.")
|
||||
# return Resolution_Level_Enum.HIGH
|
||||
"""
|
||||
|
||||
class Currency(db.Model, Store_Base):
|
||||
FLAG_FACTOR_FROM_GBP: ClassVar[str] = 'factor-from-GBP'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_CURRENCY
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
|
||||
id_currency = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
name = db.Column(db.String(255))
|
||||
symbol = db.Column(db.String(50))
|
||||
factor_from_GBP = db.Column(db.Float)
|
||||
display_order = db.Column(db.Integer)
|
||||
active = db.Column(db.Boolean)
|
||||
@classmethod
|
||||
def from_DB_currency(cls, query_row):
|
||||
_m = 'Currency.from_DB_currency'
|
||||
v_arg_type = 'class attribute'
|
||||
currency = cls()
|
||||
currency.id_currency = query_row[0]
|
||||
currency.code = query_row[1]
|
||||
currency.name = query_row[2]
|
||||
currency.symbol = query_row[3]
|
||||
currency.factor_from_GBP = query_row[4]
|
||||
currency.display_order = query_row[5]
|
||||
currency.active = av.input_bool(query_row[6], 'active', _m, v_arg_type=v_arg_type)
|
||||
return currency
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue_product_permutation(cls, query_row):
|
||||
currency = cls()
|
||||
currency.id_currency = query_row[6]
|
||||
currency.code = query_row[7]
|
||||
currency.symbol = query_row[8]
|
||||
return currency
|
||||
@classmethod
|
||||
def from_DB_get_many_product_price_and_discount_and_delivery_region(cls, query_row):
|
||||
currency = cls()
|
||||
return currency
|
||||
@classmethod
|
||||
def from_DB_stock_item(cls, query_row):
|
||||
currency = cls()
|
||||
currency.id_currency = query_row[12]
|
||||
currency.code = query_row[13]
|
||||
currency.symbol = query_row[14]
|
||||
return currency
|
||||
@classmethod
|
||||
def from_DB_supplier(cls, query_row):
|
||||
currency = cls()
|
||||
currency.id_currency = query_row[1]
|
||||
currency.code = query_row[2]
|
||||
currency.symbol = query_row[3]
|
||||
return currency
|
||||
@classmethod
|
||||
def from_DB_supplier_purchase_order(cls, query_row):
|
||||
currency = cls()
|
||||
currency.id_currency = query_row[3]
|
||||
currency.code = query_row[4]
|
||||
currency.symbol = query_row[5]
|
||||
return currency
|
||||
@classmethod
|
||||
def from_DB_manufacturing_purchase_order(cls, query_row):
|
||||
currency = cls()
|
||||
currency.id_currency = query_row[1]
|
||||
currency.code = query_row[2]
|
||||
currency.symbol = query_row[3]
|
||||
return currency
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id: {self.id_currency}
|
||||
name: {self.name}
|
||||
code: {self.code}
|
||||
symbol: {self.symbol}
|
||||
factor from GBP: {self.factor_from_GBP}
|
||||
display_order: {self.display_order}
|
||||
active: {self.active}
|
||||
'''
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.NAME_ATTR_OPTION_TEXT: self.FLAG_NAME,
|
||||
self.NAME_ATTR_OPTION_VALUE: self.ATTR_ID_CURRENCY,
|
||||
self.ATTR_ID_CURRENCY: self.id_currency,
|
||||
self.FLAG_CODE: self.code,
|
||||
self.FLAG_NAME: self.name,
|
||||
self.FLAG_SYMBOL: self.symbol,
|
||||
self.FLAG_FACTOR_FROM_GBP: self.factor_from_GBP,
|
||||
self.FLAG_DISPLAY_ORDER: self.display_order,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json_currency, key_suffix = ''):
|
||||
currency = cls()
|
||||
currency.id_currency = json_currency[f'{cls.ATTR_ID_CURRENCY}{key_suffix}']
|
||||
currency.code = json_currency.get(f'{cls.FLAG_CODE}{key_suffix}')
|
||||
currency.name = json_currency.get(f'{cls.FLAG_NAME}{key_suffix}')
|
||||
currency.symbol = json_currency.get(f'{cls.FLAG_SYMBOL}{key_suffix}')
|
||||
currency.factor_from_GBP = json_currency.get(f'{cls.FLAG_FACTOR_FROM_GBP}{key_suffix}')
|
||||
currency.display_order = json_currency.get(f'{cls.FLAG_DISPLAY_ORDER}{key_suffix}')
|
||||
currency.active = json_currency.get(f'{cls.FLAG_ACTIVE}{key_suffix}')
|
||||
return currency
|
||||
|
||||
def to_json_option(self):
|
||||
return {
|
||||
'value': self.id_currency,
|
||||
'text': self.name
|
||||
}
|
||||
@@ -7,7 +7,7 @@ Technology: Business Objects
|
||||
Feature: Database Base Business Objects
|
||||
|
||||
Description:
|
||||
Abstract business object for database objects
|
||||
Abstract base class for database objects
|
||||
"""
|
||||
|
||||
# internal
|
||||
@@ -22,32 +22,7 @@ from sqlalchemy.ext.declarative import DeclarativeMeta
|
||||
# from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
|
||||
class Get_Many_Parameters_Base(BaseModel, metaclass=ABCMeta):
|
||||
# a_id_user: int
|
||||
def __init__(self, **kwargs): # , a_id_user
|
||||
super().__init__(**kwargs) # a_id_user=a_id_user,
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def get_default(cls): # , id_user
|
||||
pass
|
||||
def to_json(self):
|
||||
return self.dict()
|
||||
"""
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
"""
|
||||
"""
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def from_form(cls, form):
|
||||
pass
|
||||
"""
|
||||
|
||||
|
||||
# db = SQLAlchemy()
|
||||
# Base = declarative_base()
|
||||
class SQLAlchemy_ABCMeta(db.Model.__class__, ABCMeta):
|
||||
pass
|
||||
|
||||
@@ -63,10 +38,6 @@ class SQLAlchemy_ABC(db.Model, metaclass=SQLAlchemy_ABCMeta):
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
pass
|
||||
"""
|
||||
def to_json_option(self):
|
||||
pass
|
||||
"""
|
||||
def to_temporary_record(self):
|
||||
pass
|
||||
def to_object_with_missing_attributes(self, excluded_attributes):
|
||||
|
||||
@@ -12,7 +12,7 @@ Business object for product
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.store_base import Store_Base
|
||||
from business_objects.base import Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
@@ -20,22 +20,19 @@ from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Access_Level(db.Model, Store_Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Store_Base.ATTR_ID_ACCESS_LEVEL
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Store_Base.FLAG_NAME
|
||||
__tablename__ = 'Shop_Access_Level_Temp'
|
||||
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
|
||||
__tablename__ = 'PH_Access_Level_Temp'
|
||||
id_access_level = 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))
|
||||
priority = db.Column(db.Integer)
|
||||
display_order = db.Column(db.Integer)
|
||||
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)
|
||||
Base.__init__(self)
|
||||
@classmethod
|
||||
def from_DB_access_level(cls, query_row):
|
||||
access_level = cls()
|
||||
@@ -74,7 +71,6 @@ class Access_Level(db.Model, Store_Base):
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f'Access Level.from_json: {json}')
|
||||
access_level = cls()
|
||||
access_level.id_access_level = json[cls.ATTR_ID_ACCESS_LEVEL],
|
||||
access_level.code = json[cls.FLAG_CODE],
|
||||
@@ -83,4 +79,4 @@ class Access_Level(db.Model, Store_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
|
||||
136
business_objects/project_hub/contact_form.py
Normal file
136
business_objects/project_hub/contact_form.py
Normal file
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Contact_Form Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.db_base import SQLAlchemy_ABC
|
||||
import lib.argument_validation as av
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Contact_Form(SQLAlchemy_ABC, Base):
|
||||
FLAG_ALTCHA: ClassVar[str] = 'altcha'
|
||||
FLAG_CONTACT_FORM: ClassVar[str] = 'contact-form'
|
||||
FLAG_NAME_COMPANY: ClassVar[str] = 'name-company'
|
||||
FLAG_NAME_CONTACT: ClassVar[str] = 'name-contact'
|
||||
FLAG_MESSAGE: ClassVar[str] = 'message'
|
||||
FLAG_RECEIVE_MARKETING_COMMUNICATIONS: ClassVar[str] = 'receive-marketing-communications'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = FLAG_CONTACT_FORM
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_EMAIL
|
||||
|
||||
__tablename__ = 'PH_Contact_Form'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
|
||||
id_contact_form = db.Column(db.Integer, primary_key=True)
|
||||
email = db.Column(db.String(255))
|
||||
name_contact = db.Column(db.String(255))
|
||||
name_company = db.Column(db.String(255))
|
||||
message = db.Column(db.Text)
|
||||
receive_marketing_communications = db.Column(db.Boolean)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
|
||||
def __init__(self):
|
||||
self.id_contact_form = 0
|
||||
self.is_new = False
|
||||
super().__init__()
|
||||
|
||||
def from_DB_Contact_Form(query_row):
|
||||
_m = 'Contact_Form.from_DB_Contact_Form'
|
||||
contact_form = Contact_Form()
|
||||
contact_form.id_contact_form = query_row[0]
|
||||
contact_form.email = query_row[1]
|
||||
contact_form.name_contact = query_row[2]
|
||||
contact_form.name_company = query_row[3]
|
||||
contact_form.message = query_row[4]
|
||||
contact_form.receive_marketing_communications = av.input_bool(query_row[5], 'receive_marketing_communications', _m)
|
||||
contact_form.active = av.input_bool(query_row[6], 'active', _m)
|
||||
contact_form.created_on = query_row[7]
|
||||
return contact_form
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
_m = 'Contact_Form.from_json'
|
||||
contact_form = cls()
|
||||
if json is None: return Contact_Form
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
contact_form.id_contact_form = -1
|
||||
contact_form.email = json[cls.FLAG_EMAIL]
|
||||
contact_form.name_contact = json[cls.FLAG_NAME_CONTACT]
|
||||
contact_form.name_company = json[cls.FLAG_NAME_COMPANY]
|
||||
contact_form.message = json[cls.FLAG_MESSAGE]
|
||||
contact_form.receive_marketing_communications = json[cls.FLAG_RECEIVE_MARKETING_COMMUNICATIONS]
|
||||
contact_form.active = json[cls.FLAG_ACTIVE]
|
||||
contact_form.created_on = json.get(cls.FLAG_CREATED_ON, None)
|
||||
Helper_App.console_log(f'Contact_Form: {contact_form}')
|
||||
return contact_form
|
||||
|
||||
|
||||
def to_json(self):
|
||||
as_json = {
|
||||
self.FLAG_CONTACT_FORM: self.id_contact_form
|
||||
, self.FLAG_EMAIL: self.email
|
||||
, self.FLAG_NAME_CONTACT: self.name_contact
|
||||
, self.FLAG_NAME_COMPANY: self.name_company
|
||||
, self.FLAG_MESSAGE: self.message
|
||||
, self.FLAG_RECEIVE_MARKETING_COMMUNICATIONS: self.receive_marketing_communications
|
||||
, self.FLAG_ACTIVE: self.active
|
||||
, self.FLAG_CREATED_ON: self.created_on
|
||||
}
|
||||
Helper_App.console_log(f'as_json: {as_json}')
|
||||
return as_json
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.__class__.__name__}(
|
||||
{self.FLAG_CONTACT_FORM}: {self.id_contact_form}
|
||||
{self.FLAG_EMAIL}: {self.email}
|
||||
{self.FLAG_NAME_CONTACT}: {self.name_contact}
|
||||
{self.FLAG_NAME_COMPANY}: {self.name_company}
|
||||
{self.FLAG_MESSAGE}: {self.message}
|
||||
{self.FLAG_RECEIVE_MARKETING_COMMUNICATIONS}: {self.receive_marketing_communications}
|
||||
{self.FLAG_ACTIVE}: {self.active}
|
||||
{self.FLAG_CREATED_ON}: {self.created_on}
|
||||
)
|
||||
'''
|
||||
|
||||
class Contact_Form_Temp(db.Model, Base):
|
||||
__tablename__ = 'PH_Contact_Form_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_temp = db.Column(db.Integer, primary_key=True)
|
||||
id_contact_form = db.Column(db.Integer)
|
||||
email = db.Column(db.String(255))
|
||||
name_contact = db.Column(db.String(255))
|
||||
name_company = db.Column(db.String(255))
|
||||
message = db.Column(db.Text)
|
||||
receive_marketing_communications = db.Column(db.Boolean)
|
||||
active = db.Column(db.Boolean)
|
||||
created_on = db.Column(db.DateTime)
|
||||
guid: str = db.Column(db.String(36))
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def from_contact_form(cls, contact_form):
|
||||
_m = 'Contact_Form_Temp.from_Contact_Form'
|
||||
temp = cls()
|
||||
temp.id_contact_form = contact_form.id_contact_form
|
||||
temp.email = contact_form.email
|
||||
temp.name_contact = contact_form.name_contact
|
||||
temp.name_company = contact_form.name_company
|
||||
temp.message = contact_form.message
|
||||
temp.receive_marketing_communications = contact_form.receive_marketing_communications
|
||||
temp.active = contact_form.active
|
||||
temp.created_on = contact_form.created_on
|
||||
return temp
|
||||
133
business_objects/project_hub/user.py
Normal file
133
business_objects/project_hub/user.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: User Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.db_base import SQLAlchemy_ABC
|
||||
import lib.argument_validation as av
|
||||
from forms.forms import Form_Contact
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class User(SQLAlchemy_ABC, Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_ID_USER
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'email'
|
||||
|
||||
__tablename__ = 'PH_User'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
|
||||
id_user = db.Column(db.Integer, primary_key=True)
|
||||
id_user_auth0 = db.Column(db.String(255))
|
||||
firstname = db.Column(db.String(255))
|
||||
surname = db.Column(db.String(255))
|
||||
email = db.Column(db.String(255))
|
||||
is_email_verified = db.Column(db.Boolean)
|
||||
is_super_user = db.Column(db.Boolean)
|
||||
is_new = db.Column(db.Boolean)
|
||||
|
||||
def __init__(self):
|
||||
self.id_user = 0
|
||||
self.is_new = False
|
||||
super().__init__()
|
||||
|
||||
def from_DB_user(query_row):
|
||||
_m = 'User.from_DB_user'
|
||||
user = User()
|
||||
user.id_user = query_row[0]
|
||||
user.id_user_auth0 = query_row[1]
|
||||
user.firstname = query_row[2]
|
||||
user.surname = query_row[3]
|
||||
user.email = query_row[4]
|
||||
user.is_email_verified = av.input_bool(query_row[5], 'is_email_verified', _m)
|
||||
user.is_super_user = av.input_bool(query_row[9], 'is_super_user', _m)
|
||||
user.is_new = av.input_bool(query_row[12], 'is_new', _m)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
_m = 'User.from_json'
|
||||
user = User()
|
||||
if json is None: return user
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
user.id_user = json['id_user']
|
||||
user.id_user_auth0 = json['id_user_auth0']
|
||||
user.firstname = json['firstname']
|
||||
user.surname = json['surname']
|
||||
user.email = json['email']
|
||||
user.is_email_verified = av.input_bool(json['is_email_verified'], 'is_email_verified', _m)
|
||||
user.is_super_user = av.input_bool(json['is_super_user'], 'is_super_user', _m)
|
||||
Helper_App.console_log(f'user: {user}')
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def from_json_auth0(json):
|
||||
_m = 'User.from_json_auth0'
|
||||
user = User()
|
||||
if json is None: return user
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
user_info = json['userinfo']
|
||||
user.id_user = None
|
||||
user.id_user_auth0 = user_info['sub']
|
||||
user.firstname = None
|
||||
user.surname = None
|
||||
user.email = user_info['email']
|
||||
user.is_email_verified = av.input_bool(user_info['email_verified'], 'is_email_verified', _m)
|
||||
user.is_super_user = None
|
||||
Helper_App.console_log(f'user: {user}')
|
||||
return user
|
||||
|
||||
def to_json(self):
|
||||
as_json = {
|
||||
'id_user': self.id_user,
|
||||
'id_user_auth0': self.id_user_auth0,
|
||||
'firstname': self.firstname,
|
||||
'surname': self.surname,
|
||||
'email': self.email,
|
||||
'is_email_verified': self.is_email_verified,
|
||||
'is_super_user': self.is_super_user
|
||||
}
|
||||
Helper_App.console_log(f'as_json: {as_json}')
|
||||
return as_json
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_user: {self.id_user}
|
||||
id_user_auth0: {self.id_user_auth0}
|
||||
firstname: {self.firstname}
|
||||
surname: {self.surname}
|
||||
email: {self.email}
|
||||
is_email_verified: {self.is_email_verified}
|
||||
is_super_user: {self.is_super_user}
|
||||
'''
|
||||
|
||||
def get_is_logged_in(self):
|
||||
return (self.id_user > 0 and self.id_user != Base.ID_USER_GUEST)
|
||||
|
||||
class User_Temp(db.Model, Base):
|
||||
__tablename__ = 'Shop_User_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_user = db.Column(db.Integer, primary_key=True)
|
||||
id_user_auth0 = db.Column(db.String(255))
|
||||
firstname = db.Column(db.String(255))
|
||||
surname = db.Column(db.String(255))
|
||||
email = db.Column(db.String(255))
|
||||
is_email_verified = db.Column(db.Boolean)
|
||||
is_super_user = db.Column(db.Boolean)
|
||||
id_currency_default = db.Column(db.Integer)
|
||||
id_region_default = db.Column(db.Integer)
|
||||
is_included_VAT_default = db.Column(db.Boolean)
|
||||
# is_logged_in: bool
|
||||
|
||||
def __init__(self):
|
||||
self.id_user = 0
|
||||
super().__init__()
|
||||
@@ -1,87 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Address Region Business Object
|
||||
|
||||
Description:
|
||||
Business object for address region
|
||||
"""
|
||||
|
||||
# internal
|
||||
import lib.argument_validation as av
|
||||
from business_objects.base import Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Region(db.Model, Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_ID_REGION
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = Base.FLAG_NAME
|
||||
__tablename__ = 'Shop_Region'
|
||||
id_region = db.Column(db.Integer, primary_key=True)
|
||||
code = db.Column(db.String(50))
|
||||
name = db.Column(db.String(200))
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
# region = None
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
Base.__init__(self)
|
||||
|
||||
@classmethod
|
||||
def from_DB_stock_item(cls, query_row):
|
||||
region = cls()
|
||||
region.id_region = query_row[7]
|
||||
return region
|
||||
@classmethod
|
||||
def from_DB_supplier(cls, query_row):
|
||||
region = cls()
|
||||
region.id_region = query_row[2]
|
||||
region.name = query_row[3]
|
||||
return region
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
{self.ATTR_ID_REGION}: {self.id_region}
|
||||
{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_REGION: self.id_region,
|
||||
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}')
|
||||
plant = cls()
|
||||
plant.id_region = json[cls.ATTR_ID_REGION]
|
||||
plant.code = json[cls.FLAG_CODE]
|
||||
plant.name = json[cls.FLAG_NAME]
|
||||
plant.active = json[cls.FLAG_ACTIVE]
|
||||
return plant
|
||||
@classmethod
|
||||
def from_DB_get_many_product_catalogue(cls, query_row):
|
||||
region = cls()
|
||||
region.id_region = query_row[0]
|
||||
region.name = query_row[1]
|
||||
region.code = query_row[2]
|
||||
# self.display_order = query_row[3]
|
||||
return region
|
||||
@classmethod
|
||||
def from_DB_region(cls, query_row):
|
||||
region = cls()
|
||||
region.id_region = query_row[0]
|
||||
region.code = query_row[1]
|
||||
region.name = query_row[2]
|
||||
region.active = av.input_bool(query_row[3], cls.FLAG_ACTIVE, f'{cls.__name__}.from_DB_region')
|
||||
return region
|
||||
@@ -7,7 +7,7 @@ Technology: Business Objects
|
||||
Feature: SQL Error Business Object
|
||||
|
||||
Description:
|
||||
Business object for SQL errors
|
||||
Business object for SQL errors returned by Get Many Stored Procedures
|
||||
"""
|
||||
|
||||
# internal
|
||||
@@ -22,11 +22,9 @@ import locale
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
|
||||
# VARIABLE INSTANTIATION
|
||||
db = SQLAlchemy()
|
||||
|
||||
|
||||
# CLASSES
|
||||
class SQL_Error(db.Model):
|
||||
display_order = db.Column(db.Integer, primary_key=True)
|
||||
id_type = db.Column(db.Integer)
|
||||
|
||||
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.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,184 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,98 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,75 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
"""
|
||||
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
|
||||
|
||||
@@ -1,354 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,89 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,93 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,917 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,529 +0,0 @@
|
||||
"""
|
||||
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__)
|
||||
@@ -1,617 +0,0 @@
|
||||
"""
|
||||
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
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,217 +0,0 @@
|
||||
"""
|
||||
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,
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,169 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,303 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,88 +0,0 @@
|
||||
"""
|
||||
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}'
|
||||
@@ -1,129 +0,0 @@
|
||||
"""
|
||||
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__)
|
||||
@@ -1,161 +0,0 @@
|
||||
"""
|
||||
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)
|
||||
@@ -1,200 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,146 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,343 +0,0 @@
|
||||
"""
|
||||
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}
|
||||
'''
|
||||
@@ -1,110 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: Unit of Measurement Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.db_base import SQLAlchemy_ABC, Get_Many_Parameters_Base
|
||||
from extensions import db
|
||||
# from forms.forms import Form_Filters_User
|
||||
from helpers.helper_app import Helper_App
|
||||
import lib.argument_validation as av
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class Unit_Measurement(SQLAlchemy_ABC, Base):
|
||||
ATTR_ID_UNIT_MEASUREMENT: ClassVar[str] = 'id_unit_measurement'
|
||||
FLAG_IS_BASE_UNIT: ClassVar[str] = 'is_base_unit'
|
||||
FLAG_IS_UNIT_OF_DISTANCE: ClassVar[str] = 'is_unit_of_distance'
|
||||
FLAG_IS_UNIT_OF_MASS: ClassVar[str] = 'is_unit_of_mass'
|
||||
FLAG_IS_UNIT_OF_TIME: ClassVar[str] = 'is_unit_of_time'
|
||||
FLAG_IS_UNIT_OF_VOLUME: ClassVar[str] = 'is_unit_of_volume'
|
||||
FLAG_NAME_PLURAL: ClassVar[str] = 'name_plural'
|
||||
FLAG_NAME_SINGULAR: ClassVar[str] = 'name_singular'
|
||||
FLAG_SYMBOL: ClassVar[str] = 'symbol'
|
||||
FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX: ClassVar[str] = 'symbol_is_suffix_not_prefix'
|
||||
# KEY_UNIT_MEASUREMENT: ClassVar[str] = 'unit_of_measurement'
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = ATTR_ID_UNIT_MEASUREMENT
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = FLAG_NAME_SINGULAR
|
||||
|
||||
id_unit_measurement = db.Column(db.Integer, primary_key=True)
|
||||
name_singular = db.Column(db.String(255))
|
||||
name_plural = db.Column(db.String(256))
|
||||
symbol = db.Column(db.String(50))
|
||||
symbol_is_suffix_not_prefix = db.Column(db.Boolean)
|
||||
is_base_unit = db.Column(db.Boolean)
|
||||
is_unit_of_distance = db.Column(db.Boolean)
|
||||
is_unit_of_mass = db.Column(db.Boolean)
|
||||
is_unit_of_time = db.Column(db.Boolean)
|
||||
is_unit_of_volume = db.Column(db.Boolean)
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
def from_DB_unit_measurement(query_row):
|
||||
_m = 'Unit_Measurement.from_DB_unit_measurement'
|
||||
unit = Unit_Measurement()
|
||||
unit.id_unit_measurement = query_row[0]
|
||||
unit.name_singular = query_row[1]
|
||||
unit.name_plural = query_row[2]
|
||||
unit.symbol = query_row[3]
|
||||
unit.symbol_is_suffix_not_prefix = av.input_bool(query_row[4], 'symbol_is_suffix_not_prefix', _m)
|
||||
unit.is_base_unit = av.input_bool(query_row[5], 'is_base_unit', _m)
|
||||
unit.is_unit_of_distance = av.input_bool(query_row[6], 'is_unit_of_distance', _m)
|
||||
unit.is_unit_of_mass = av.input_bool(query_row[7], 'is_unit_of_mass', _m)
|
||||
unit.is_unit_of_time = av.input_bool(query_row[8], 'is_unit_of_time', _m)
|
||||
unit.is_unit_of_volume = av.input_bool(query_row[9], 'is_unit_of_volume', _m)
|
||||
unit.active = av.input_bool(query_row[10], 'active', _m)
|
||||
return unit
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
self.ATTR_ID_UNIT_MEASUREMENT: self.id_unit_measurement,
|
||||
self.FLAG_NAME_SINGULAR: self.name_singular,
|
||||
self.FLAG_NAME_PLURAL: self.name_plural,
|
||||
self.FLAG_SYMBOL: self.symbol,
|
||||
self.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX: self.symbol_is_suffix_not_prefix,
|
||||
self.FLAG_IS_BASE_UNIT: self.is_base_unit,
|
||||
self.FLAG_IS_UNIT_OF_DISTANCE: self.is_unit_of_distance,
|
||||
self.FLAG_IS_UNIT_OF_MASS: self.is_unit_of_mass,
|
||||
self.FLAG_IS_UNIT_OF_TIME: self.is_unit_of_time,
|
||||
self.FLAG_IS_UNIT_OF_VOLUME: self.is_unit_of_volume,
|
||||
self.FLAG_ACTIVE: self.active,
|
||||
}
|
||||
@classmethod
|
||||
def from_json(cls, json):
|
||||
Helper_App.console_log(f' Unit_Measurement.from_json: {json}')
|
||||
unit = cls()
|
||||
unit.id_unit_measurement = json[cls.ATTR_ID_UNIT_MEASUREMENT]
|
||||
unit.name_singular = json[cls.FLAG_NAME_SINGULAR]
|
||||
unit.name_plural = json[cls.FLAG_NAME_PLURAL]
|
||||
unit.symbol = json[cls.FLAG_SYMBOL]
|
||||
unit.symbol_is_suffix_not_prefix = json[cls.FLAG_SYMBOL_IS_SUFFIX_NOT_PREFIX]
|
||||
unit.is_base_unit = json[cls.FLAG_IS_BASE_UNIT]
|
||||
unit.is_unit_of_distance = json[cls.FLAG_IS_UNIT_OF_DISTANCE]
|
||||
unit.is_unit_of_mass = json[cls.FLAG_IS_UNIT_OF_MASS]
|
||||
unit.is_unit_of_time = json[cls.FLAG_IS_UNIT_OF_TIME]
|
||||
unit.is_unit_of_volume = json[cls.FLAG_IS_UNIT_OF_VOLUME]
|
||||
unit.active = json[cls.FLAG_ACTIVE]
|
||||
return unit
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_unit_of_measurement: {self.id_unit_measurement},
|
||||
name_singular: {self.name_singular},
|
||||
name_plural: {self.name_plural},
|
||||
symbol: {self.symbol},
|
||||
symbol_is_suffix_not_prefix: {self.symbol_is_suffix_not_prefix},
|
||||
is_base_unit: {self.is_base_unit},
|
||||
is_unit_of_distance: {self.is_unit_of_distance},
|
||||
is_unit_of_mass: {self.is_unit_of_mass},
|
||||
is_unit_of_time: {self.is_unit_of_time},
|
||||
is_unit_of_volume: {self.is_unit_of_volume},
|
||||
active: {self.active}
|
||||
'''
|
||||
@@ -1,293 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: Business Objects
|
||||
Feature: User Business Object
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.base import Base
|
||||
from business_objects.db_base import Get_Many_Parameters_Base
|
||||
import lib.argument_validation as av
|
||||
from forms.forms import Form_Filters_User
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
|
||||
class User(db.Model, Base):
|
||||
NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.ATTR_ID_USER
|
||||
NAME_ATTR_OPTION_TEXT: ClassVar[str] = 'email'
|
||||
|
||||
__tablename__ = 'Shop_User'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
|
||||
id_user = db.Column(db.Integer, primary_key=True)
|
||||
id_user_auth0 = db.Column(db.String(255))
|
||||
firstname = db.Column(db.String(255))
|
||||
surname = db.Column(db.String(255))
|
||||
email = db.Column(db.String(255))
|
||||
is_email_verified = db.Column(db.Boolean)
|
||||
is_super_user = db.Column(db.Boolean)
|
||||
id_currency_default = db.Column(db.Integer)
|
||||
id_region_default = db.Column(db.Integer)
|
||||
is_included_VAT_default = db.Column(db.Boolean)
|
||||
can_admin_store = db.Column(db.Boolean)
|
||||
can_admin_user = db.Column(db.Boolean)
|
||||
is_new = db.Column(db.Boolean)
|
||||
# is_logged_in: bool
|
||||
|
||||
def __init__(self):
|
||||
self.id_user = 0
|
||||
self.is_logged_in = False
|
||||
self.is_new = False
|
||||
super().__init__()
|
||||
self.currency_default = None
|
||||
self.region_default = None
|
||||
|
||||
def from_DB_user(query_row):
|
||||
_m = 'User.from_DB_user'
|
||||
user = User()
|
||||
user.id_user = query_row[0]
|
||||
user.id_user_auth0 = query_row[1]
|
||||
user.firstname = query_row[2]
|
||||
user.surname = query_row[3]
|
||||
user.email = query_row[4]
|
||||
user.is_email_verified = av.input_bool(query_row[5], 'is_email_verified', _m)
|
||||
user.id_currency_default = query_row[6]
|
||||
user.id_region_default = query_row[7]
|
||||
user.is_included_VAT_default = av.input_bool(query_row[8], 'is_included_VAT_default', _m)
|
||||
user.is_super_user = av.input_bool(query_row[9], 'is_super_user', _m)
|
||||
user.can_admin_store = av.input_bool(query_row[10], 'can_admin_store', _m)
|
||||
user.can_admin_user = av.input_bool(query_row[11], 'can_admin_user', _m)
|
||||
user.is_logged_in = (user.id_user is not None and user.id_user > 0)
|
||||
user.is_new = av.input_bool(query_row[12], 'is_new', _m)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
_m = 'User.from_json'
|
||||
user = User()
|
||||
if json is None: return user
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
user.id_user = json['id_user']
|
||||
user.id_user_auth0 = json['id_user_auth0']
|
||||
user.firstname = json['firstname']
|
||||
user.surname = json['surname']
|
||||
user.email = json['email']
|
||||
user.is_email_verified = av.input_bool(json['is_email_verified'], 'is_email_verified', _m)
|
||||
user.is_super_user = av.input_bool(json['is_super_user'], 'is_super_user', _m)
|
||||
user.id_currency_default = json['id_currency_default']
|
||||
user.id_region_default = json['id_region_default']
|
||||
user.is_included_VAT_default = av.input_bool(json['is_included_VAT_default'], 'is_included_VAT_default', _m)
|
||||
user.can_admin_store = av.input_bool(json['can_admin_store'], 'can_admin_store', _m)
|
||||
user.can_admin_user = av.input_bool(json['can_admin_user'], 'can_admin_user', _m)
|
||||
user.is_logged_in = (user.id_user_auth0 is not None)
|
||||
Helper_App.console_log(f'user: {user}')
|
||||
return user
|
||||
|
||||
# Helper_App.console_log(f'user: {user}')
|
||||
@staticmethod
|
||||
def from_json_auth0(json):
|
||||
_m = 'User.from_json_auth0'
|
||||
user = User()
|
||||
if json is None: return user
|
||||
Helper_App.console_log(f'{_m}\njson: {json}')
|
||||
user_info = json['userinfo']
|
||||
user.id_user = None
|
||||
user.id_user_auth0 = user_info['sub']
|
||||
user.firstname = None
|
||||
user.surname = None
|
||||
user.email = user_info['email']
|
||||
user.is_email_verified = av.input_bool(user_info['email_verified'], 'is_email_verified', _m)
|
||||
user.is_super_user = None
|
||||
user.id_currency_default = None
|
||||
user.id_region_default = None
|
||||
user.is_included_VAT_default = None
|
||||
user.can_admin_store = None
|
||||
user.can_admin_user = None
|
||||
user.is_logged_in = (user.id_user_auth0 is not None and user.id_user_auth0 != '')
|
||||
Helper_App.console_log(f'user: {user}')
|
||||
return user
|
||||
|
||||
def to_json(self):
|
||||
as_json = {
|
||||
'id_user': self.id_user,
|
||||
'id_user_auth0': self.id_user_auth0,
|
||||
'firstname': self.firstname,
|
||||
'surname': self.surname,
|
||||
'email': self.email,
|
||||
'is_email_verified': self.is_email_verified,
|
||||
'is_super_user': self.is_super_user,
|
||||
'id_currency_default': self.id_currency_default,
|
||||
'id_region_default': self.id_region_default,
|
||||
'is_included_VAT_default': self.is_included_VAT_default,
|
||||
'can_admin_store': self.can_admin_store,
|
||||
'can_admin_user': self.can_admin_user
|
||||
}
|
||||
Helper_App.console_log(f'as_json: {as_json}')
|
||||
return as_json
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_user: {self.id_user}
|
||||
id_user_auth0: {self.id_user_auth0}
|
||||
firstname: {self.firstname}
|
||||
surname: {self.surname}
|
||||
email: {self.email}
|
||||
is_email_verified: {self.is_email_verified}
|
||||
is_super_user: {self.is_super_user}
|
||||
id_currency_default: {self.id_currency_default}
|
||||
id_region_default: {self.id_region_default}
|
||||
is_included_VAT_default: {self.is_included_VAT_default}
|
||||
can_admin_store: {self.can_admin_store}
|
||||
can_admin_user: {self.can_admin_user}
|
||||
'''
|
||||
|
||||
|
||||
class Parameters_User(Get_Many_Parameters_Base):
|
||||
get_all_user: bool
|
||||
get_inactive_user: bool
|
||||
ids_user: str
|
||||
ids_user_auth0: str
|
||||
|
||||
@staticmethod
|
||||
def from_form(form):
|
||||
av.val_instance(form, 'form', 'Parameters_User.from_form', Form_Filters_User)
|
||||
get_inactive = av.input_bool(form.active.data, "active", "Parameters_User.from_form")
|
||||
id_user = '' if form.id_user.data is None else form.id_user.data
|
||||
return Parameters_User(
|
||||
get_all_user = (id_user == ''),
|
||||
get_inactive_user = get_inactive,
|
||||
ids_user = id_user,
|
||||
ids_user_auth0 = '',
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def from_user(user):
|
||||
av.val_instance(user, 'user', 'Parameters_User.from_user', User)
|
||||
return Parameters_User(
|
||||
get_all_user = ((user.id_user is None or user.id_user == 0) and user.id_user_auth0 is None),
|
||||
get_inactive_user = False,
|
||||
ids_user = '' if user.id_user is None else str(user.id_user),
|
||||
ids_user_auth0 = user.id_user_auth0,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_default():
|
||||
return Parameters_User(
|
||||
get_all_user = False,
|
||||
get_inactive_user = False,
|
||||
ids_user = '',
|
||||
ids_user_auth0 = ''
|
||||
)
|
||||
""" User_Eval
|
||||
@dataclass
|
||||
class User_Filters():
|
||||
ids_user: str
|
||||
get_inactive_users: bool
|
||||
ids_permission: str
|
||||
ids_access_level: str
|
||||
ids_product: str
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
**self.get_shared_json_attributes(self),
|
||||
'a_ids_user': self.ids_user,
|
||||
'a_get_inactive_users': self.get_inactive_users,
|
||||
'a_ids_permission': self.ids_permission,
|
||||
'a_ids_access_level': self.ids_access_level,
|
||||
'a_ids_product': self.ids_product,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def from_form(form):
|
||||
av.val_instance(form, 'form', 'User_Filters.from_form', Form_Filters_User)
|
||||
get_inactive = av.input_bool(form.active.data, "active", "User_Filters.from_form")
|
||||
return User_Filters(
|
||||
ids_user = form.id_user.data,
|
||||
get_inactive_users = get_inactive,
|
||||
ids_permission = form.ids_permission.data,
|
||||
ids_access_level = form.ids_access_level.data,
|
||||
ids_product = form.ids_product.data,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_default(datastore_store):
|
||||
is_user_logged_in, id_user = datastore_store.get_login_user()
|
||||
return User_Filters(
|
||||
ids_user = id_user,
|
||||
get_inactive_users = False,
|
||||
ids_permission = '',
|
||||
ids_access_level = '',
|
||||
ids_product = '',
|
||||
)
|
||||
"""
|
||||
|
||||
class User_Permission_Evaluation(db.Model):
|
||||
id_evaluation = db.Column(db.Integer, primary_key=True)
|
||||
guid = db.Column(db.String(255))
|
||||
id_user = db.Column(db.Integer)
|
||||
id_permission_required = db.Column(db.Integer)
|
||||
priority_access_level_required = db.Column(db.Integer)
|
||||
id_product = db.Column(db.Integer)
|
||||
is_super_user = db.Column(db.Boolean)
|
||||
priority_access_level_user = db.Column(db.Integer)
|
||||
can_view = db.Column(db.Boolean)
|
||||
can_edit = db.Column(db.Boolean)
|
||||
can_admin = db.Column(db.Boolean)
|
||||
|
||||
def from_DB_user_eval(query_row):
|
||||
user_permission_evaluation = User_Permission_Evaluation()
|
||||
user_permission_evaluation.id_evaluation = query_row[0]
|
||||
user_permission_evaluation.guid = query_row[1]
|
||||
user_permission_evaluation.id_user = query_row[2]
|
||||
user_permission_evaluation.id_permission_required = query_row[3]
|
||||
user_permission_evaluation.priority_access_level_required = query_row[4]
|
||||
user_permission_evaluation.id_product = query_row[5]
|
||||
user_permission_evaluation.is_super_user = query_row[6]
|
||||
user_permission_evaluation.priority_access_level_user = query_row[7]
|
||||
user_permission_evaluation.can_view = query_row[8]
|
||||
user_permission_evaluation.can_edit = query_row[9]
|
||||
user_permission_evaluation.can_admin = query_row[10]
|
||||
return user_permission_evaluation
|
||||
|
||||
def __repr__(self):
|
||||
return f'''
|
||||
id_evaluation: {self.id_evaluation}
|
||||
guid: {self.guid}
|
||||
id_user: {self.id_user}
|
||||
id_permission_required: {self.id_permission_required}
|
||||
priority_access_level_required: {self.priority_access_level_required}
|
||||
id_product: {self.id_product}
|
||||
is_super_user: {self.is_super_user}
|
||||
priority_access_level_user: {self.priority_access_level_user}
|
||||
can_view: {self.can_view}
|
||||
can_edit: {self.can_edit}
|
||||
can_admin: {self.can_admin}
|
||||
'''
|
||||
|
||||
|
||||
class User_Temp(db.Model, Base):
|
||||
__tablename__ = 'Shop_User_Temp'
|
||||
__table_args__ = { 'extend_existing': True }
|
||||
id_user = db.Column(db.Integer, primary_key=True)
|
||||
id_user_auth0 = db.Column(db.String(255))
|
||||
firstname = db.Column(db.String(255))
|
||||
surname = db.Column(db.String(255))
|
||||
email = db.Column(db.String(255))
|
||||
is_email_verified = db.Column(db.Boolean)
|
||||
is_super_user = db.Column(db.Boolean)
|
||||
id_currency_default = db.Column(db.Integer)
|
||||
id_region_default = db.Column(db.Integer)
|
||||
is_included_VAT_default = db.Column(db.Boolean)
|
||||
# is_logged_in: bool
|
||||
|
||||
def __init__(self):
|
||||
self.id_user = 0
|
||||
self.is_logged_in = False
|
||||
super().__init__()
|
||||
13
config.py
13
config.py
@@ -11,7 +11,6 @@ Configuration variables
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
from lib import argument_validation as av
|
||||
import os
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
from flask import current_app
|
||||
@@ -40,8 +39,8 @@ class Config:
|
||||
# Auth0
|
||||
SESSION_COOKIE_SECURE = True
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
# SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
# PERMANENT_SESSION_LIFETIME = 3600
|
||||
SESSION_COOKIE_SAMESITE = 'Strict'
|
||||
REMEMBER_COOKIE_SECURE = True
|
||||
WTF_CSRF_ENABLED = True
|
||||
# WTF_CSRF_CHECK_DEFAULT = False # We'll check it manually for API routes
|
||||
# WTF_CSRF_HEADERS = ['X-CSRFToken'] # Accept CSRF token from this header
|
||||
@@ -52,7 +51,7 @@ class Config:
|
||||
DOMAIN_AUTH0 = os.getenv('DOMAIN_AUTH0')
|
||||
ID_TOKEN_USER = 'user'
|
||||
# PostgreSQL
|
||||
DB_NAME = os.getenv('partsltd')
|
||||
DB_NAME = os.getenv('partsltd_prod')
|
||||
DB_USER = os.getenv('DB_USER')
|
||||
DB_PASSWORD = os.getenv('DB_PASSWORD')
|
||||
DB_HOST = os.getenv('DB_HOST')
|
||||
@@ -80,9 +79,15 @@ class Config:
|
||||
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
|
||||
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')
|
||||
MAIL_CONTACT_PUBLIC = os.getenv('MAIL_CONTACT_PUBLIC')
|
||||
"""
|
||||
# Recaptcha
|
||||
RECAPTCHA_PUBLIC_KEY = os.getenv('RECAPTCHA_PUBLIC_KEY')
|
||||
RECAPTCHA_PRIVATE_KEY = os.getenv('RECAPTCHA_PRIVATE_KEY')
|
||||
"""
|
||||
# ALTCHA
|
||||
ALTCHA_API_KEY = os.getenv('ALTCHA_API_KEY')
|
||||
ALTCHA_SECRET_KEY = os.getenv('ALTCHA_SECRET_KEY')
|
||||
ALTCHA_REGION = 'eu'
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
is_development = True
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Core 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.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
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
|
||||
from flask_mail import Mail, Message
|
||||
from extensions import db, oauth, mail
|
||||
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_core = Blueprint('routes_core', __name__)
|
||||
|
||||
|
||||
@routes_core.route(Model_View_Home.HASH_PAGE_HOME, methods=['GET'])
|
||||
def home():
|
||||
try:
|
||||
model = Model_View_Home()
|
||||
html_body = render_template('pages/core/_home.html', model = model)
|
||||
except Exception as e:
|
||||
return jsonify(error=str(e)), 403
|
||||
return html_body
|
||||
|
||||
@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:
|
||||
return jsonify(error=str(e)), 403
|
||||
return html_body
|
||||
|
||||
@routes_core.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['POST'])
|
||||
def contact_post():
|
||||
try:
|
||||
form = Form_Contact()
|
||||
if form.validate_on_submit():
|
||||
# Handle form submission
|
||||
email = form.email.data
|
||||
CC = form.CC.data # not in use
|
||||
name = form.name.data
|
||||
message = form.message.data
|
||||
# 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\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
|
||||
143
controllers/core/contact.py
Normal file
143
controllers/core/contact.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Core - Contact Routes
|
||||
|
||||
Description:
|
||||
Contact Page Controller.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from business_objects.api import API
|
||||
from business_objects.project_hub.contact_form import Contact_Form
|
||||
from datastores.project_hub.datastore_contact_form import DataStore_Contact_Form
|
||||
from forms.contact import Form_Contact
|
||||
from helpers.helper_app import Helper_App
|
||||
from models.model_view_contact import Model_View_Contact
|
||||
from models.model_view_contact_success import Model_View_Contact_Success
|
||||
from models.model_view_home import Model_View_Home
|
||||
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, flash
|
||||
from flask_mail import Mail, Message
|
||||
from extensions import db, oauth, mail
|
||||
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 json
|
||||
import base64
|
||||
import hmac
|
||||
import hashlib
|
||||
import datetime
|
||||
from altcha import ChallengeOptions, create_challenge, verify_solution
|
||||
|
||||
routes_core_contact = Blueprint('routes_core_contact', __name__)
|
||||
|
||||
|
||||
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['GET'])
|
||||
def contact():
|
||||
try:
|
||||
form = Form_Contact()
|
||||
model = Model_View_Contact(form)
|
||||
html_body = render_template('pages/core/_contact.html', model = model)
|
||||
return html_body
|
||||
except Exception as e:
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
|
||||
@routes_core_contact.route(Model_View_Contact.HASH_GET_ALTCHA_CHALLENGE, methods=['GET'])
|
||||
def create_altcha_challenge():
|
||||
options = ChallengeOptions(
|
||||
expires = datetime.datetime.now() + datetime.timedelta(hours=1),
|
||||
max_number = 100000, # The maximum random number
|
||||
hmac_key = current_app.app_config.ALTCHA_SECRET_KEY,
|
||||
)
|
||||
challenge = create_challenge(options)
|
||||
Helper_App.console_log(f"Challenge created: {challenge}")
|
||||
# return jsonify({"challenge": challenge})
|
||||
return jsonify({
|
||||
"algorithm": challenge.algorithm,
|
||||
"challenge": challenge.challenge,
|
||||
"salt": challenge.salt,
|
||||
"signature": challenge.signature,
|
||||
})
|
||||
|
||||
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['POST'])
|
||||
def contact_post():
|
||||
try:
|
||||
form = Form_Contact()
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
email = form.email.data
|
||||
# CC = form.CC.data # not in use
|
||||
contact_name = form.contact_name.data
|
||||
company_name = form.company_name.data
|
||||
message = form.message.data
|
||||
receive_marketing = form.receive_marketing.data
|
||||
receive_marketing_text = "I would like to receive marketing emails.\n" 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}"
|
||||
mail.send(mailItem)
|
||||
# save to database
|
||||
datastore = DataStore_Contact_Form()
|
||||
contact_form = Contact_Form.from_json(form.to_json())
|
||||
datastore.save_contact_forms(
|
||||
comment = contact_form.message
|
||||
, contact_forms = [contact_form]
|
||||
)
|
||||
return redirect(url_for(Model_View_Contact.ENDPOINT_PAGE_CONTACT_SUCCESS))
|
||||
except Exception as e:
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {form.errors}",
|
||||
data = None,
|
||||
errors = [str(form.errors)],
|
||||
meta = None
|
||||
)
|
||||
# html_body = render_template('pages/core/_contact.html', model = model)
|
||||
except Exception as e:
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
|
||||
@routes_core_contact.route(Model_View_Contact.HASH_PAGE_CONTACT_SUCCESS, methods=['GET'])
|
||||
def contact_success():
|
||||
try:
|
||||
model = Model_View_Contact_Success()
|
||||
html_body = render_template('pages/core/_contact_success.html', model = model)
|
||||
return html_body
|
||||
except Exception as e:
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
31
controllers/core/home.py
Normal file
31
controllers/core/home.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Core - Home Routes
|
||||
|
||||
Description:
|
||||
Home Page Controller.
|
||||
"""
|
||||
|
||||
# internal
|
||||
from business_objects.api import API
|
||||
from models.model_view_home import Model_View_Home
|
||||
# external
|
||||
from flask import render_template, jsonify, Blueprint
|
||||
|
||||
|
||||
routes_core_home = Blueprint('routes_core_home', __name__)
|
||||
|
||||
|
||||
@routes_core_home.route(Model_View_Home.HASH_PAGE_HOME, methods=['GET'])
|
||||
def home():
|
||||
try:
|
||||
model = Model_View_Home()
|
||||
html_body = render_template('pages/core/_home.html', model = model)
|
||||
except Exception as e:
|
||||
return jsonify(error=str(e)), 403
|
||||
return html_body
|
||||
|
||||
@@ -7,7 +7,7 @@ Technology: App Routing
|
||||
Feature: Legal 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.
|
||||
Legal Section Controller.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
@@ -20,12 +20,8 @@ from models.model_view_accessibility_statement import Model_View_Accessibility_S
|
||||
from models.model_view_retention_schedule import Model_View_Retention_Schedule
|
||||
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
|
||||
from flask import render_template, Blueprint
|
||||
|
||||
|
||||
routes_legal = Blueprint('routes_legal', __name__)
|
||||
|
||||
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.
@@ -1,82 +0,0 @@
|
||||
"""
|
||||
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,167 +0,0 @@
|
||||
"""
|
||||
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
|
||||
from flask import Flask, render_template, render_template_string, jsonify, request, send_from_directory, redirect
|
||||
from dotenv import 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 == '':
|
||||
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:
|
||||
stripe.set_app_info(
|
||||
'stripe-samples/checkout-one-time-payments',
|
||||
version='0.0.1',
|
||||
url='https://github.com/stripe-samples/checkout-one-time-payments')
|
||||
|
||||
# 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(
|
||||
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(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': key_public, # os.getenv('KEY_PUBLIC_STRIPE'),
|
||||
'unitAmount': price['unit_amount'],
|
||||
'currency': price['currency']
|
||||
})
|
||||
|
||||
# Fetch the Checkout Session to display the JSON result on the success page
|
||||
@app.route('/checkout-session', methods=['GET'])
|
||||
def get_checkout_session():
|
||||
id = request.args.get('sessionId')
|
||||
checkout_session = stripe.checkout.Session.retrieve(id)
|
||||
return jsonify(checkout_session)
|
||||
|
||||
|
||||
@app.route('/create-checkout-session', methods=['POST'])
|
||||
def create_checkout_session():
|
||||
quantity = request.form.get('quantity', 1)
|
||||
domain_url = os.getenv('DOMAIN')
|
||||
|
||||
try:
|
||||
# Create new Checkout Session for the order
|
||||
# Other optional params include:
|
||||
# [billing_address_collection] - to display billing address details on the page
|
||||
# [customer] - if you have an existing Stripe Customer ID
|
||||
# [payment_intent_data] - lets capture the payment later
|
||||
# [customer_email] - lets you prefill the email input in the form
|
||||
# [automatic_tax] - to automatically calculate sales tax, VAT and GST in the checkout page
|
||||
# For full details see https://stripe.com/docs/api/checkout/sessions/create
|
||||
|
||||
# ?session_id={CHECKOUT_SESSION_ID} means the redirect will have the session ID set as a query param
|
||||
checkout_session = stripe.checkout.Session.create(
|
||||
success_url=domain_url + '/success.html?session_id={CHECKOUT_SESSION_ID}',
|
||||
cancel_url=domain_url + '/canceled.html',
|
||||
mode='payment',
|
||||
# automatic_tax={'enabled': True},
|
||||
line_items=[{
|
||||
'price': os.getenv('PRICE'),
|
||||
'quantity': quantity,
|
||||
}]
|
||||
)
|
||||
return redirect(checkout_session.url, code=303)
|
||||
except Exception as e:
|
||||
return jsonify(error=str(e)), 403
|
||||
|
||||
|
||||
@app.route('/webhook', methods=['POST'])
|
||||
def webhook_received():
|
||||
# You can use webhooks to receive information about asynchronous payment events.
|
||||
# For more about our webhook events check out https://stripe.com/docs/webhooks.
|
||||
webhook_secret = os.getenv('STRIPE_WEBHOOK_SECRET')
|
||||
request_data = json.loads(request.data)
|
||||
|
||||
if webhook_secret:
|
||||
# Retrieve the event by verifying the signature using the raw body and secret if webhook signing is configured.
|
||||
signature = request.headers.get('stripe-signature')
|
||||
try:
|
||||
event = stripe.Webhook.construct_event(
|
||||
payload=request.data, sig_header=signature, secret=webhook_secret)
|
||||
data = event['data']
|
||||
except Exception as e:
|
||||
return e
|
||||
# Get the type of webhook event sent - used to check the status of PaymentIntents.
|
||||
event_type = event['type']
|
||||
else:
|
||||
data = request_data['data']
|
||||
event_type = request_data['type']
|
||||
data_object = data['object']
|
||||
|
||||
Helper_App.console_log('event ' + event_type)
|
||||
|
||||
if event_type == 'checkout.session.completed':
|
||||
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)
|
||||
@@ -1,86 +0,0 @@
|
||||
"""
|
||||
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}'
|
||||
})
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
"""
|
||||
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}'
|
||||
})
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
"""
|
||||
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}'
|
||||
})
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
"""
|
||||
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}'
|
||||
})
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
"""
|
||||
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}'
|
||||
})
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: Store 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.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from models.model_view_store import Model_View_Store
|
||||
# external
|
||||
from flask import Flask, render_template, jsonify, request, render_template_string, send_from_directory, redirect, url_for, session, Blueprint, current_app, Response
|
||||
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 = Blueprint('routes_store', __name__)
|
||||
|
||||
@routes_store.route(Model_View_Store.HASH_SCRIPTS_SECTION_STORE, methods=['GET'])
|
||||
def scripts_section_store():
|
||||
hash_page_current = request.args.get('hash_page_current', default = Model_View_Store.HASH_SCRIPTS_SECTION_STORE, type = str)
|
||||
model = Model_View_Store(hash_page_current=hash_page_current)
|
||||
template = render_template('js/sections/store.js', model = model)
|
||||
return Response(template, mimetype='application/javascript')
|
||||
@@ -1,83 +0,0 @@
|
||||
"""
|
||||
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}'
|
||||
})
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
"""
|
||||
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}'
|
||||
})
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: App Routing
|
||||
Feature: User 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.
|
||||
"""
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
from models.model_view_user import Model_View_User
|
||||
from business_objects.user import User, Parameters_User
|
||||
from datastores.datastore_user import DataStore_User
|
||||
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 flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy import exc
|
||||
from flask_wtf.csrf import generate_csrf
|
||||
from werkzeug.exceptions import BadRequest
|
||||
from extensions import oauth # db,
|
||||
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
|
||||
from functools import wraps
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
routes_user = Blueprint('routes_user', __name__)
|
||||
|
||||
def handle_db_disconnect(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
try:
|
||||
return f(*args, **kwargs)
|
||||
except exc.OperationalError as e:
|
||||
if "MySQL server has gone away" in str(e):
|
||||
# Close the session and create a new connection
|
||||
db.session.remove()
|
||||
db.session.rollback()
|
||||
# Retry the operation
|
||||
return f(*args, **kwargs)
|
||||
raise
|
||||
return decorated_function
|
||||
|
||||
# User authentication
|
||||
@routes_user.route("/login", methods=['POST', 'OPTIONS'])
|
||||
def login():
|
||||
try:
|
||||
Helper_App.console_log('login')
|
||||
Helper_App.console_log(f'method={request.method}')
|
||||
try:
|
||||
data = request.json
|
||||
try:
|
||||
data = request.get_json()
|
||||
except:
|
||||
data = {}
|
||||
except:
|
||||
data = {}
|
||||
Helper_App.console_log(f'data={data}')
|
||||
hash_callback = data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME)
|
||||
Helper_App.console_log(f'hash_callback: {hash_callback}')
|
||||
|
||||
"""
|
||||
# Verify CSRF token manually
|
||||
Helper_App.console_log(f'request headers={request.headers}')
|
||||
token = request.headers.get(Model_View_Base.FLAG_CSRF_TOKEN)
|
||||
Helper_App.console_log(f'token={token}')
|
||||
Helper_App.console_log(f'session={session}')
|
||||
Helper_App.console_log(f'session token={session.get('csrf_token')}')
|
||||
if not token or token != session.get('csrf_token'):
|
||||
token = data.get(Model_View_Base.FLAG_CSRF_TOKEN, None)
|
||||
Helper_App.console_log(f'token={token}')
|
||||
if not token or token != session.get('csrf_token'):
|
||||
raise BadRequest('Invalid or missing CSRF token')
|
||||
"""
|
||||
# OAuth login
|
||||
# callback_login = F'{Model_View_Base.HASH_CALLBACK_LOGIN}{data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME)}'
|
||||
|
||||
# encoded_path = quote(data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME))
|
||||
uri_redirect = url_for('routes_user.login_callback', _external=True) # , subpath=encoded_path
|
||||
|
||||
# uri_redirect = f'{current_app.URL_HOST}/login_callback?subpath={data.get(Model_View_Base.FLAG_CALLBACK, Model_View_Base.HASH_PAGE_HOME)}'
|
||||
Helper_App.console_log(f'redirect uri: {uri_redirect}')
|
||||
|
||||
Helper_App.console_log(f'Before red')
|
||||
|
||||
red = oauth.auth0.authorize_redirect(
|
||||
redirect_uri = uri_redirect,
|
||||
state = quote(hash_callback)
|
||||
)
|
||||
Helper_App.console_log(f'redirect: {red}')
|
||||
headers = red.headers['Location']
|
||||
Helper_App.console_log(f'headers: {headers}')
|
||||
parsed_url = urlparse(headers)
|
||||
query_params = parse_qs(parsed_url.query)
|
||||
Helper_App.console_log(f"""
|
||||
OAuth Authorize Redirect URL:
|
||||
|
||||
Base URL: {parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}
|
||||
{parsed_url}
|
||||
|
||||
Query Parameters: {query_params}
|
||||
""")
|
||||
return jsonify({'Success': True, Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_SUCCESS, f'{Model_View_Base.FLAG_CALLBACK}': headers})
|
||||
|
||||
return jsonify({'status': 'success', 'redirect': callback})
|
||||
except Exception as e:
|
||||
return jsonify({'status': 'error', 'message': str(e)}), 400
|
||||
|
||||
|
||||
@routes_user.route("/login_callback") # <path:subpath>/<code>
|
||||
@handle_db_disconnect
|
||||
def login_callback():
|
||||
Helper_App.console_log('login_callback')
|
||||
try:
|
||||
error_state = request.args.get(Model_View_User.FLAG_ERROR_OAUTH)
|
||||
has_error = error_state is not None
|
||||
if has_error:
|
||||
error_description = request.args.get(Model_View_User.FLAG_ERROR_DESCRIPTION_OAUTH)
|
||||
error_text = f'Error: {error_state}: {error_description}'
|
||||
Helper_App.console_log(error_text)
|
||||
return login()
|
||||
# Helper_App.console_log(f'code: {code}')
|
||||
token = None
|
||||
try:
|
||||
token = oauth.auth0.authorize_access_token()
|
||||
except Exception as e:
|
||||
# Log the error for debugging
|
||||
Helper_App.console_log(f"Error: {str(e)}")
|
||||
session[current_app.config['ID_TOKEN_USER']] = token
|
||||
# import user id
|
||||
"""
|
||||
Helper_App.console_log(f'str(type(token)) = {str(type(token))}')
|
||||
Helper_App.console_log(f'token = {token}')
|
||||
userinfo = token.get('userinfo')
|
||||
Helper_App.console_log(f'user info: {userinfo}')
|
||||
# id_user = token.get('sub')
|
||||
id_user = userinfo.get('sub')
|
||||
Helper_App.console_log(f'user ID: {id_user}')
|
||||
"""
|
||||
user = User.from_json_auth0(token) # datastore_user.get_user_auth0()
|
||||
Helper_App.console_log(f'user: {user}')
|
||||
filters = Parameters_User.from_user(user)
|
||||
datastore_user = DataStore_User()
|
||||
users, errors = datastore_user.get_many_user(filters, user)
|
||||
try:
|
||||
user = users[0]
|
||||
Helper_App.console_log('User logged in')
|
||||
Helper_App.console_log(f'user ({str(type(user))}): {user}')
|
||||
Helper_App.console_log(f'user key: {Model_View_Base.FLAG_USER}')
|
||||
user_json = user.to_json()
|
||||
session[Model_View_Base.FLAG_USER] = user_json
|
||||
Helper_App.console_log(f'user stored on session')
|
||||
except:
|
||||
Helper_App.console_log(f'User not found: {Parameters_User}\nDatabase query error: {errors}')
|
||||
|
||||
try:
|
||||
hash_callback = token.get('hash_callback')
|
||||
if hash_callback is None:
|
||||
Helper_App.console_log('hash is none')
|
||||
state = request.args.get('state')
|
||||
Helper_App.console_log(f'state: {state}')
|
||||
hash_callback = state # .get('hash_callback')
|
||||
Helper_App.console_log(f'hash_callback: {hash_callback}')
|
||||
except:
|
||||
Helper_App.console_log("get hash callback failed")
|
||||
# id_user = get_id_user()
|
||||
# add user to database
|
||||
# DataStore_Store().add_new_user(id_user) # this is part of get basket - should occur on page load
|
||||
|
||||
Helper_App.console_log(f'user session: {session[Model_View_Base.FLAG_USER]}')
|
||||
return redirect(f"{current_app.config['URL_HOST']}{hash_callback}")
|
||||
except Exception as e:
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_FAILURE, Model_View_Base.FLAG_MESSAGE: f'Controller error.\n{e}'})
|
||||
|
||||
@routes_user.route("/logout")
|
||||
def logout():
|
||||
session.clear()
|
||||
url_logout = f"https://{current_app.config['DOMAIN_AUTH0']}/v2/logout?" + urlencode(
|
||||
{
|
||||
"returnTo": url_for("routes_user.logout_callback", _external=True),
|
||||
"client_id": current_app.config['ID_AUTH0_CLIENT'],
|
||||
}# ,
|
||||
# quote_via=quote_plus,
|
||||
)
|
||||
Helper_App.console_log(f"Redirecting to {url_logout}")
|
||||
return redirect(url_logout)
|
||||
|
||||
@routes_user.route("/logout_callback") # <path:subpath>/<code>
|
||||
@handle_db_disconnect
|
||||
def logout_callback():
|
||||
return redirect(url_for('routes_core.home'))
|
||||
try:
|
||||
session[current_app.ID_TOKEN_USER] = None
|
||||
user = User()
|
||||
try:
|
||||
hash_callback = token.get('hash_callback')
|
||||
if hash_callback is None:
|
||||
Helper_App.console_log('hash is none')
|
||||
state = request.args.get('state')
|
||||
Helper_App.console_log(f'state: {state}')
|
||||
hash_callback = state # .get('hash_callback')
|
||||
Helper_App.console_log(f'hash_callback: {hash_callback}')
|
||||
except:
|
||||
Helper_App.console_log("get hash callback failed")
|
||||
# id_user = get_id_user()
|
||||
# add user to database
|
||||
# DataStore_Store().add_new_user(id_user) # this is part of get basket - should occur on page load
|
||||
|
||||
Helper_App.console_log(f'user session: {session[Model_View_Base.FLAG_USER]}')
|
||||
return redirect(f'{current_app.URL_HOST}{hash_callback}')
|
||||
except Exception as e:
|
||||
return jsonify({Model_View_Base.FLAG_STATUS: Model_View_Base.FLAG_FAILURE, Model_View_Base.FLAG_MESSAGE: f'Controller error.\n{e}'})
|
||||
|
||||
|
||||
@routes_user.route("/user")
|
||||
def user():
|
||||
try:
|
||||
model = Model_View_User()
|
||||
for currency in model.currencies:
|
||||
if currency.id_currency == model.user.id_currency_default:
|
||||
model.user.currency_default = currency
|
||||
break
|
||||
for region in model.regions:
|
||||
if region.id_region == model.user.id_region_default:
|
||||
model.user.region_default = region
|
||||
break
|
||||
model.users = [model.user]
|
||||
if not model.is_user_logged_in:
|
||||
# return redirect(url_for('routes_user.login', data = jsonify({ Model_View_User.FLAG_CALLBACK: Model_View_User.HASH_PAGE_USER_ACCOUNT })))
|
||||
return redirect(url_for('routes_core.home'))
|
||||
html_body = render_template('pages/user/_user.html', model = model)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
return html_body
|
||||
@@ -13,22 +13,8 @@ Datastore for Store
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
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 business_objects.project_hub.user import User
|
||||
# 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
|
||||
@@ -36,52 +22,26 @@ from forms.access_level import Filters_Access_Level
|
||||
from forms.unit_measurement import Filters_Unit_Measurement
|
||||
from helpers.helper_app import Helper_App
|
||||
# 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
|
||||
import time
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
# db = SQLAlchemy()
|
||||
|
||||
|
||||
class DataStore_Base(BaseModel):
|
||||
# Global constants
|
||||
# Attributes
|
||||
"""
|
||||
app: Flask = None
|
||||
db: SQLAlchemy = None
|
||||
session: object = None
|
||||
"""
|
||||
|
||||
# model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
# Constructor
|
||||
"""
|
||||
self.db = db
|
||||
self.app = current_app
|
||||
with self.app.app_context():
|
||||
self.session = session
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def db_procedure_execute(proc_name, argument_dict_list = None):
|
||||
# Argument validation
|
||||
_m = 'DataStore_Base.db_procedure_execute'
|
||||
av.val_str(proc_name, 'proc_name', _m)
|
||||
has_arguments = not str(type(argument_dict_list)) == "<class 'NoneType'>"
|
||||
if has_arguments:
|
||||
# av.val_list_instances(argument_dict_list, 'argument_dict_list', _m, dict)
|
||||
pass
|
||||
# Methods
|
||||
proc_string = f'CALL {proc_name}('
|
||||
has_arguments = not str(type(argument_dict_list)) == "<class 'NoneType'>"
|
||||
if has_arguments:
|
||||
arg_keys = list(argument_dict_list.keys())
|
||||
for i in range(len(arg_keys)):
|
||||
@@ -90,9 +50,6 @@ class DataStore_Base(BaseModel):
|
||||
proc_string = text(proc_string)
|
||||
Helper_App.console_log(f'{_m}\nproc_string: {proc_string}\nargs: {argument_dict_list}')
|
||||
|
||||
# with self.db.session.begin() as session:
|
||||
# conn = Helper_DB_MySQL(self.app).get_db_connection()
|
||||
|
||||
if has_arguments:
|
||||
result = db.session.execute(proc_string, argument_dict_list)
|
||||
else:
|
||||
@@ -100,114 +57,19 @@ class DataStore_Base(BaseModel):
|
||||
Helper_App.console_log(f'result: {result}')
|
||||
# conn.session.remove()
|
||||
return result
|
||||
cursor = result.cursor
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'categories: {result_set_1}')
|
||||
cursor.nextset()
|
||||
result_set_2 = cursor.fetchall()
|
||||
Helper_App.console_log(f'products: {result_set_2}')
|
||||
|
||||
@staticmethod
|
||||
def db_cursor_clear(cursor):
|
||||
while cursor.nextset():
|
||||
Helper_App.console_log(f'new result set: {cursor.fetchall()}')
|
||||
@classmethod
|
||||
def get_many_region_and_currency(cls):
|
||||
_m = 'DataStore_Base.get_many_region_and_currency'
|
||||
_m_db_currency = 'p_shop_get_many_currency'
|
||||
_m_db_region = 'p_shop_get_many_region'
|
||||
|
||||
argument_dict_list_currency = {
|
||||
'a_get_inactive_currency': 0
|
||||
}
|
||||
argument_dict_list_region = {
|
||||
'a_get_inactive_currency': 0
|
||||
}
|
||||
|
||||
Helper_App.console_log(f'executing {_m_db_currency}')
|
||||
result = cls.db_procedure_execute(_m_db_currency, argument_dict_list_currency)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
currencies = []
|
||||
for row in result_set_1:
|
||||
currency = Currency.make_from_DB_currency(row)
|
||||
currencies.append(currency)
|
||||
Helper_App.console_log(f'currencies: {currencies}')
|
||||
DataStore_Base.db_cursor_clear(cursor)
|
||||
|
||||
Helper_App.console_log(f'executing {_m_db_region}')
|
||||
result = cls.db_procedure_execute(_m_db_region, argument_dict_list_region)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
regions = []
|
||||
for row in result_set_1:
|
||||
region = Region.make_from_DB_region(row)
|
||||
regions.append(region)
|
||||
Helper_App.console_log(f'regions: {regions}')
|
||||
DataStore_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return regions, currencies
|
||||
@staticmethod
|
||||
def get_user_session():
|
||||
Helper_App.console_log('DataStore_Base.get_user_session')
|
||||
user = User.from_json(session.get(User.FLAG_USER))
|
||||
if user.is_logged_in:
|
||||
filters_user = Parameters_User.get_default()
|
||||
filters_user.ids_user = user.id_user
|
||||
users = DataStore_Base.get_many_user(filters_user)
|
||||
if user.id_user <= 0:
|
||||
user.id_user = 3
|
||||
return user
|
||||
@classmethod
|
||||
def get_many_user(cls, filters=None):
|
||||
_m = 'DataStore_Store_Base.get_many_access_level'
|
||||
user = User.from_json(session.get(User.FLAG_USER))
|
||||
if filters is None:
|
||||
filters_user = Parameters_User.get_default()
|
||||
filters_user.ids_user = user.id_user if user.is_logged_in else None
|
||||
av.val_instance(filters, 'filters', _m, Parameters_User)
|
||||
argument_dict = filters.to_json()
|
||||
|
||||
argument_dict = {
|
||||
'a_id_user': user.id_user,
|
||||
'a_id_user_auth0': user.id_user_auth0,
|
||||
**argument_dict,
|
||||
'a_debug': 0,
|
||||
}
|
||||
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
Helper_App.console_log('executing p_get_many_user')
|
||||
result = cls.db_procedure_execute('p_get_many_user', argument_dict)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# users
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw users: {result_set_1}')
|
||||
users = []
|
||||
for row in result_set_1:
|
||||
new_user = User.from_DB_user(row)
|
||||
users.append(new_user)
|
||||
|
||||
# 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_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return users, errors
|
||||
|
||||
@staticmethod
|
||||
def upload_bulk(permanent_table_name, records, batch_size):
|
||||
@@ -225,30 +87,6 @@ class DataStore_Base(BaseModel):
|
||||
else:
|
||||
expected_columns = set(column.name for column in db.inspect(table_object).columns)
|
||||
Helper_App.console_log(f'expected_columns: {expected_columns}')
|
||||
""" v1, v2
|
||||
try:
|
||||
for i in range(0, len(records), batch_size):
|
||||
"" v1
|
||||
batch = records[i:i+batch_size]
|
||||
Helper_App.console_log(f'batch: {batch}')
|
||||
db.session.bulk_save_objects(batch)
|
||||
""
|
||||
""
|
||||
data = [object.to_json() for object in batch]
|
||||
Helper_App.console_log(f'data: {data}')
|
||||
for row in data:
|
||||
row_keys = set(row.keys())
|
||||
if row_keys != expected_columns:
|
||||
Helper_App.console_log(f"Column mismatch in row: {row}")
|
||||
Helper_App.console_log(f'missing columns: {expected_columns - row_keys}')
|
||||
Helper_App.console_log(f'extra columns: {row_keys - expected_columns}')
|
||||
# db.session.bulk_insert_mappings(permanent_table_name, data)
|
||||
""
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'{_m}\n{e}')
|
||||
db.session.rollback()
|
||||
raise e
|
||||
"""
|
||||
max_retries = 3
|
||||
initial_backoff = 1
|
||||
for i in range(0, len(records), batch_size):
|
||||
@@ -274,104 +112,3 @@ class DataStore_Base(BaseModel):
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
raise e
|
||||
|
||||
@classmethod
|
||||
def get_many_access_level(cls, filters=None):
|
||||
_m = 'DataStore_Store_Base.get_many_access_level'
|
||||
if filters is None:
|
||||
filters = Filters_Access_Level()
|
||||
av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
||||
argument_dict = filters.to_json()
|
||||
# user = cls.get_user_session()
|
||||
# argument_dict['a_id_user'] = 1 # 'auth0|6582b95c895d09a70ba10fef' # id_user
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
Helper_App.console_log('executing p_shop_get_many_access_level')
|
||||
result = cls.db_procedure_execute('p_shop_get_many_access_level', argument_dict)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# access_levels
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw access levels: {result_set_1}')
|
||||
access_levels = []
|
||||
for row in result_set_1:
|
||||
new_access_level = Access_Level.from_DB_access_level(row)
|
||||
access_levels.append(new_access_level)
|
||||
|
||||
# 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_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return access_levels, errors
|
||||
@classmethod
|
||||
def get_many_unit_measurement(cls, filters=None):
|
||||
_m = 'DataStore_Store_Base.get_many_unit_measurement'
|
||||
if filters is None:
|
||||
filters = Filters_Unit_Measurement()
|
||||
av.val_instance(filters, 'filters', _m, Filters_Unit_Measurement)
|
||||
argument_dict = filters.to_json()
|
||||
# user = cls.get_user_session()
|
||||
# argument_dict['a_id_user'] = 1 # 'auth0|6582b95c895d09a70ba10fef' # id_user
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
Helper_App.console_log('executing p_shop_get_many_unit_measurement')
|
||||
result = cls.db_procedure_execute('p_shop_get_many_unit_measurement', argument_dict)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# units of measurement
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw units of measurement: {result_set_1}')
|
||||
units = []
|
||||
for row in result_set_1:
|
||||
new_unit = Unit_Measurement.from_DB_unit_measurement(row)
|
||||
units.append(new_unit)
|
||||
|
||||
# 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_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return units, errors
|
||||
|
||||
@classmethod
|
||||
def get_many_region(cls, get_inactive = False):
|
||||
_m = 'DataStore_Store_Base.get_many_region'
|
||||
_m_db_region = 'p_shop_get_many_region'
|
||||
|
||||
argument_dict_list_region = {
|
||||
'a_get_inactive_region': 1 if get_inactive else 0
|
||||
}
|
||||
|
||||
Helper_App.console_log(f'executing {_m_db_region}')
|
||||
result = cls.db_procedure_execute(_m_db_region, argument_dict_list_region)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
regions = []
|
||||
for row in result_set_1:
|
||||
region = Region.from_DB_region(row)
|
||||
regions.append(region)
|
||||
Helper_App.console_log(f'regions: {regions}')
|
||||
DataStore_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return regions
|
||||
@@ -1,351 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Base Store DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.store.product_category import Product_Category_Container, Product_Category
|
||||
from business_objects.currency import Currency
|
||||
from business_objects.store.image import Image
|
||||
from business_objects.store.delivery_option import Delivery_Option
|
||||
from business_objects.region import Region
|
||||
from business_objects.store.discount import Discount
|
||||
from business_objects.store.order import Order
|
||||
from business_objects.store.plant import Plant
|
||||
from business_objects.store.product import Product, Product_Permutation, Parameters_Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.store.stock_item import Stock_Item
|
||||
from business_objects.store.storage_location import Storage_Location
|
||||
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_base import DataStore_Base
|
||||
from extensions import db
|
||||
from helpers.helper_app import Helper_App
|
||||
from helpers.helper_db_mysql import Helper_DB_MySQL
|
||||
import lib.argument_validation as av
|
||||
# from models.model_view_store_checkout import Model_View_Store_Checkout # circular!
|
||||
# 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_Base(DataStore_Base):
|
||||
# Global constants
|
||||
KEY_BASKET: ClassVar[str] = Basket.KEY_BASKET
|
||||
KEY_IS_INCLUDED_VAT: ClassVar[str] = Basket.KEY_IS_INCLUDED_VAT # 'is_included_VAT'
|
||||
KEY_ID_CURRENCY: ClassVar[str] = Basket.KEY_ID_CURRENCY # 'id_currency'
|
||||
KEY_ID_REGION_DELIVERY: ClassVar[str] = Basket.KEY_ID_REGION_DELIVERY # 'id_region_delivery'
|
||||
# Attributes
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@classmethod
|
||||
def get_many_product(cls, product_filters):
|
||||
# redundant argument validation?
|
||||
_m = 'DataStore_Store_Base.get_many_product'
|
||||
av.val_instance(product_filters, 'product_filters', _m, Parameters_Product)
|
||||
argument_dict = product_filters.to_json()
|
||||
user = cls.get_user_session()
|
||||
"""
|
||||
argument_dict['a_id_user'] = user.id_user # 'auth0|6582b95c895d09a70ba10fef' # id_user
|
||||
argument_dict['a_debug'] = 0
|
||||
"""
|
||||
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_product')
|
||||
result = cls.db_procedure_execute('p_shop_get_many_product', argument_dict)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
|
||||
category_list = Product_Category_Container()
|
||||
Helper_App.console_log(f'initial category_list: {category_list}')
|
||||
|
||||
# Categories
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw categories: {result_set_1}')
|
||||
for row in result_set_1:
|
||||
new_category = Product_Category.from_DB_get_many_product_catalogue(row)
|
||||
Helper_App.console_log(f'new_category: {new_category}')
|
||||
category_list.add_product_category(new_category)
|
||||
|
||||
Helper_App.console_log(f'category-loaded category_list: {category_list}')
|
||||
|
||||
# Products
|
||||
cursor.nextset()
|
||||
result_set_2 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw products: {result_set_2}')
|
||||
for row in result_set_2:
|
||||
Helper_App.console_log(f'row: {row}')
|
||||
new_product = Product.from_DB_get_many_product_catalogue(row)
|
||||
Helper_App.console_log(f'new_product: {new_product}')
|
||||
try:
|
||||
category_list.add_product(new_product)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error adding product: {e}')
|
||||
|
||||
# Permutations
|
||||
cursor.nextset()
|
||||
result_set_3 = cursor.fetchall()
|
||||
for row in result_set_3:
|
||||
new_permutation = Product_Permutation.from_DB_get_many_product_catalogue(row)
|
||||
try:
|
||||
category_list.add_product_permutation(new_permutation)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error adding permutation: {e}')
|
||||
|
||||
# Product_Variations
|
||||
cursor.nextset()
|
||||
result_set_4 = cursor.fetchall()
|
||||
for row in result_set_4:
|
||||
new_variation_type = Product_Variation_Type.from_DB_get_many_product_catalogue(row)
|
||||
try:
|
||||
category_list.add_product_variation_type(new_variation_type)
|
||||
except Exception as e:
|
||||
Helper_App.console_log(f'Error adding variation: {e}')
|
||||
|
||||
# Images
|
||||
cursor.nextset()
|
||||
result_set_5 = cursor.fetchall()
|
||||
for row in result_set_5:
|
||||
new_image = Image.from_DB_get_many_product_catalogue(row)
|
||||
category_list.add_product_image(new_image)
|
||||
|
||||
# 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}")
|
||||
|
||||
category_list.get_all_product_variation_trees()
|
||||
"""
|
||||
for category in category_list.categories:
|
||||
Helper_App.console_log(f'category: {category.name}')
|
||||
for product in category.products:
|
||||
permutation = product.get_permutation_selected()
|
||||
Helper_App.console_log(f'product: {product.name}\nselected permutation: {permutation}')
|
||||
"""
|
||||
|
||||
if len(errors) > 0:
|
||||
for error in errors:
|
||||
if error.code == 'PRODUCT_AVAILABILITY':
|
||||
ids_permutation_unavailable = DataStore_Store_Base.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_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
Helper_App.console_log(f'get many category_list: {category_list}')
|
||||
return category_list, errors # categories, category_index
|
||||
|
||||
"""
|
||||
def get_many_id_price(self, product_ids):
|
||||
_m = 'DataStore_Store_Base.get_many_id_price'
|
||||
av.val_str(product_ids, 'product_ids', _m)
|
||||
price_ids = []
|
||||
for product_id in product_ids.split(','):
|
||||
if product_id == 'prod_PB0NUOSEs06ymG':
|
||||
price_ids.append() # get price id
|
||||
return price_ids
|
||||
"""
|
||||
@staticmethod
|
||||
def get_ids_permutation_from_error_availability(msg_error_availability):
|
||||
ids_permutation = []
|
||||
index_colon = msg_error_availability.find(':', msg_error_availability.find(':'))
|
||||
msg_error_availability = msg_error_availability[index_colon + 1:]
|
||||
index_comma = 0
|
||||
while index_comma > -1:
|
||||
msg_error_availability = msg_error_availability[index_comma:]
|
||||
index_comma = msg_error_availability.find(',')
|
||||
ids_permutation.append(msg_error_availability[:index_comma])
|
||||
return ids_permutation
|
||||
|
||||
@classmethod
|
||||
def get_many_plant(cls, get_inactive = False):
|
||||
_m = 'DataStore_Store_Base.get_many_plant'
|
||||
_m_db_plant = 'p_shop_get_many_plant'
|
||||
|
||||
argument_dict_list_plant = {
|
||||
'a_get_inactive_plant': 1 if get_inactive else 0
|
||||
}
|
||||
|
||||
Helper_App.console_log(f'executing {_m_db_plant}')
|
||||
result = cls.db_procedure_execute(_m_db_plant, argument_dict_list_plant)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
plants = []
|
||||
for row in result_set_1:
|
||||
plant = Plant.from_DB_plant(row)
|
||||
plants.append(plant)
|
||||
Helper_App.console_log(f'plants: {plants}')
|
||||
DataStore_Store_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return plants
|
||||
|
||||
@classmethod
|
||||
def get_many_storage_location(self, get_inactive = False):
|
||||
_m = 'DataStore_Store_Base.get_many_storage_location'
|
||||
_m_db_storage_location = 'p_shop_get_many_storage_location'
|
||||
|
||||
argument_dict_list_storage_location = {
|
||||
'a_get_inactive_storage_location': 1 if get_inactive else 0
|
||||
}
|
||||
|
||||
Helper_App.console_log(f'executing {_m_db_storage_location}')
|
||||
result = self.db_procedure_execute(_m_db_storage_location, argument_dict_list_storage_location)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
storage_locations = []
|
||||
for row in result_set_1:
|
||||
storage_location = Storage_Location.from_DB_storage_location(row)
|
||||
storage_locations.append(storage_location)
|
||||
Helper_App.console_log(f'storage_locations: {storage_locations}')
|
||||
DataStore_Store_Base.db_cursor_clear(cursor)
|
||||
cursor.close()
|
||||
|
||||
return storage_locations
|
||||
|
||||
@classmethod
|
||||
def get_many_currency(cls, get_inactive = False):
|
||||
_m = 'DataStore_Store_Base.get_many_currency'
|
||||
_m_db_currency = 'p_shop_get_many_currency'
|
||||
|
||||
argument_dict_list_currency = {
|
||||
'a_get_inactive_currency': 1 if get_inactive else 0
|
||||
}
|
||||
|
||||
Helper_App.console_log(f'executing {_m_db_currency}')
|
||||
result = cls.db_procedure_execute(_m_db_currency, argument_dict_list_currency)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
# cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
currencies = []
|
||||
for row in result_set_1:
|
||||
currency = Currency.from_DB_currency(row)
|
||||
currencies.append(currency)
|
||||
Helper_App.console_log(f'currencies: {currencies}')
|
||||
DataStore_Store_Base.db_cursor_clear(cursor)
|
||||
|
||||
return currencies
|
||||
|
||||
@classmethod
|
||||
def get_many_region_and_currency(cls, get_inactive_currency = False, get_inactive_region = False):
|
||||
_m = 'DataStore_Store_Base.get_many_region_and_currency'
|
||||
currencies = cls.get_many_currency(get_inactive_currency)
|
||||
regions = cls.get_many_region(get_inactive_region)
|
||||
return regions, currencies
|
||||
|
||||
@classmethod
|
||||
def get_many_product_variation(cls, variation_filters):
|
||||
_m = 'DataStore_Store_Base.get_many_product_variation'
|
||||
Helper_App.console_log(_m)
|
||||
av.val_instance(variation_filters, 'variation_filters', _m, Parameters_Product_Variation)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid()
|
||||
# now = datetime.now()
|
||||
# user = self.get_user_session()
|
||||
|
||||
"""
|
||||
argument_dict_list = {
|
||||
'a_id_user': id_user,
|
||||
'a_comment': comment,
|
||||
'a_guid': guid
|
||||
}
|
||||
"""
|
||||
user = cls.get_user_session()
|
||||
argument_dict_list = {
|
||||
# 'a_guid': guid
|
||||
'a_id_user': user.id_user
|
||||
, **variation_filters.to_json()
|
||||
, 'a_debug': 0
|
||||
}
|
||||
# argument_dict_list['a_guid'] = guid
|
||||
result = cls.db_procedure_execute('p_shop_get_many_product_variation', argument_dict_list)
|
||||
|
||||
cursor = result.cursor
|
||||
result_set_vt = cursor.fetchall()
|
||||
|
||||
# Product_Variation Types
|
||||
# variation_container = Product_Variation_Container()
|
||||
variation_types = []
|
||||
index_variation_type = {}
|
||||
for row in result_set_vt:
|
||||
new_variation_type = Product_Variation_Type.from_DB_get_many_product_variation(row)
|
||||
# variation_container.add_product_variation_type(new_variation_type)
|
||||
index_variation_type[new_variation_type.id_type] = len(variation_types)
|
||||
variation_types.append(new_variation_type)
|
||||
|
||||
Helper_App.console_log(f'index_variation_type: {index_variation_type}')
|
||||
|
||||
# Product_Variations
|
||||
cursor.nextset()
|
||||
result_set_v = cursor.fetchall()
|
||||
# variations = Product_Variation_Container()
|
||||
variations = []
|
||||
for row in result_set_v:
|
||||
new_variation = Product_Variation.from_DB_get_many_product_variation(row)
|
||||
# new_variation.variation_type = variation_types_dict[new_variation.id_type]
|
||||
# variation_container.add_product_variation(new_variation)
|
||||
variation_types[index_variation_type[new_variation.id_type]].variations.append(new_variation)
|
||||
variations.append(new_variation)
|
||||
|
||||
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_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Base.db_cursor_clear(cursor)
|
||||
|
||||
cursor.close()
|
||||
|
||||
return variation_types, variations, errors
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,137 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,139 +0,0 @@
|
||||
"""
|
||||
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
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
"""
|
||||
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_base import Table_Shop_Product_Category, Table_Shop_Product_Category_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_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}')
|
||||
# av.val_str(comment, 'comment', _m)
|
||||
# av.val_list_instances(categories, 'categories', _m, Product_Category, 1)
|
||||
|
||||
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)
|
||||
# row = category.to_temporary_record()
|
||||
# id_tmp =
|
||||
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
|
||||
# row.created_on = now
|
||||
# row.created_by = user.id_user
|
||||
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_Category_Temp (id_category, code, name, description, active, display_order, guid, created_on, created_by) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)',
|
||||
categories
|
||||
)
|
||||
Helper_App.console_log('bulk upload executed')
|
||||
db.commit()
|
||||
Helper_App.console_log('bulk upload committed')
|
||||
cursor.close()
|
||||
Helper_App.console_log('cursor closed')
|
||||
"""
|
||||
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] # (row[0], row[1])
|
||||
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
|
||||
@@ -1,106 +0,0 @@
|
||||
"""
|
||||
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')
|
||||
@@ -1,77 +0,0 @@
|
||||
"""
|
||||
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')
|
||||
@@ -1,146 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,195 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: Store Stripe DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Store Stripe service
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.store.basket import Basket, Basket_Item
|
||||
from business_objects.store.product import Product, Product_Permutation, Product_Price, Parameters_Product
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from datastores.datastore_store_base import DataStore_Store_Base
|
||||
# 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
|
||||
from helpers.helper_app import Helper_App
|
||||
# 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_Stripe(DataStore_Store_Base):
|
||||
# Global constants
|
||||
# Attributes
|
||||
key_public_stripe: str = None
|
||||
key_secret_stripe: str = None
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.key_secret_stripe = os.environ.get("KEY_SECRET_STRIPE")
|
||||
self.key_public_stripe = os.environ.get("KEY_PUBLIC_STRIPE")
|
||||
|
||||
# For sample support and debugging, not required for production:
|
||||
stripe.set_app_info(
|
||||
'stripe-samples/checkout-one-time-payments',
|
||||
version='0.0.1',
|
||||
url='https://github.com/stripe-samples/checkout-one-time-payments')
|
||||
stripe.api_key = self.key_secret_stripe
|
||||
|
||||
def get_many_stripe_product_new(self):
|
||||
_m = 'DataStore_Store_Stripe.get_many_stripe_product_new'
|
||||
_m_db = 'p_shop_get_many_stripe_product_new'
|
||||
# av.val_str(id_user)
|
||||
# validation conducted by server
|
||||
|
||||
argument_dict_list = {
|
||||
'a_id_user': self.info_user
|
||||
}
|
||||
|
||||
Helper_App.console_log(f'executing {_m_db}')
|
||||
result = self.db_procedure_execute(_m_db, argument_dict_list)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
|
||||
# Products
|
||||
cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
products = []
|
||||
for row in result_set_1:
|
||||
new_product = Product.from_DB_Stripe_product(row) # Product(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19])
|
||||
products.append(new_product)
|
||||
Helper_App.console_log(f'products: {products}')
|
||||
|
||||
# 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_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Stripe.db_cursor_clear(cursor)
|
||||
|
||||
return products
|
||||
|
||||
def get_many_stripe_price_new(self):
|
||||
_m = 'DataStore_Store_Stripe.get_many_stripe_price_new'
|
||||
_m_db = 'p_shop_get_many_stripe_price_new'
|
||||
# av.val_str(id_user)
|
||||
# validation conducted by server
|
||||
|
||||
argument_dict_list = {
|
||||
'a_id_user': self.info_user
|
||||
}
|
||||
|
||||
Helper_App.console_log(f'executing {_m_db}')
|
||||
result = self.db_procedure_execute(_m_db, argument_dict_list)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
|
||||
# Products
|
||||
cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
products = []
|
||||
for row in result_set_1:
|
||||
new_product = Product.from_DB_Stripe_price(row) # Product(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19])
|
||||
products.append(new_product)
|
||||
Helper_App.console_log(f'products: {products}')
|
||||
|
||||
# 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_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_Store_Stripe.db_cursor_clear(cursor)
|
||||
|
||||
return products
|
||||
|
||||
def get_many_product_new(self):
|
||||
_m = 'DataStore_Store_Stripe.get_many_product_new'
|
||||
# Stripe
|
||||
new_products = self.get_many_stripe_product_new()
|
||||
for product in new_products:
|
||||
product.id_stripe_product = self.create_stripe_product(product)
|
||||
return new_products
|
||||
|
||||
def get_many_price_new(self):
|
||||
_m = 'DataStore_Store_Stripe.get_many_product_new'
|
||||
# Stripe
|
||||
new_products = self.get_many_stripe_price_new()
|
||||
for product in new_products:
|
||||
product.id_stripe_price = self.create_stripe_price(product)
|
||||
return new_products
|
||||
|
||||
# Stripe
|
||||
def create_stripe_product(self, product): # _name, product_description):
|
||||
_m = 'DataStore_Store_Stripe_Checkout.create_stripe_product'
|
||||
# av.val_str(product_name, 'product_name', _m)
|
||||
# av.val_str(product_description, 'product_description', _m)
|
||||
av.val_instance(product, 'product', _m, Product)
|
||||
|
||||
Helper_App.console_log(f'stripe.api_key = {stripe.api_key}')
|
||||
new_product = stripe.Product.create(
|
||||
name = product.name,
|
||||
description = product.description,
|
||||
)
|
||||
|
||||
# Save these identifiers
|
||||
Helper_App.console_log(f"Success! Here is your new Stripe product id: {new_product.id}")
|
||||
|
||||
return new_product.id
|
||||
|
||||
def create_stripe_price(self, product, currency): # product_id, product_price, product_currency, product_is_subscription, product_recurring_interval = '', product_interval_count = 0):
|
||||
_m = 'DataStore_Store_Stripe_Checkout.create_stripe_price'
|
||||
"""
|
||||
av.val_str(p_id, 'p_id', _m)
|
||||
av.full_val_float(p_price, 'p_price', _m, 0.01)
|
||||
p_price = round(p_price, 2)
|
||||
av.val_str(p_currency, 'p_currency', _m)
|
||||
av.full_val_bool(p_is_subscription, 'p_is_subscription', _m)
|
||||
p_is_subscription = bool(p_is_subscription)
|
||||
av.val_str(p_recurring_interval, 'p_recurring_interval', _m)
|
||||
av.full_val_int(p_interval_count, 'p_interval_count', _m, 1 if p_is_subscription else 0)
|
||||
p_interval_count = int(p_interval_count)
|
||||
"""
|
||||
av.val_instance(product, 'product', _m, Product)
|
||||
av.val_str(currency, 'currency', _m)
|
||||
|
||||
Helper_App.console_log(f'stripe.api_key = {stripe.api_key}')
|
||||
|
||||
new_product_price = stripe.Price.create(
|
||||
unit_amount = product.unit_price,
|
||||
currency = currency,
|
||||
recurring = { "interval": product.name_recurring_interval, "interval_count": product.count_recurring_interval } if product.is_subscription else None,
|
||||
product = product.id_stripe_product
|
||||
)
|
||||
|
||||
# Save these identifiers
|
||||
Helper_App.console_log(f"Success! Here is your Stripe product price id: {new_product_price.id} for {product.name}")
|
||||
|
||||
return new_product_price.id
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,143 +0,0 @@
|
||||
"""
|
||||
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
|
||||
@@ -1,253 +0,0 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: User DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Users
|
||||
"""
|
||||
|
||||
# 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
|
||||
from business_objects.user import User, Parameters_User, User_Permission_Evaluation
|
||||
# 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!
|
||||
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_User(DataStore_Store_Base):
|
||||
# Global constants
|
||||
# Attributes
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def edit_user(self):
|
||||
# redundant argument validation?
|
||||
_m = 'DataStore_User.edit_user'
|
||||
# av.val_instance(filters, 'filters', _m, Filters_Product_Category)
|
||||
|
||||
argument_dict_list = {
|
||||
'a_id_user': self.info_user.get('sub'),
|
||||
'a_name': self.info_user.get('name'),
|
||||
'a_email': self.info_user.get('email'),
|
||||
'a_email_verified': 1 if self.info_user.get('email_verified') == 'True' else 0
|
||||
}
|
||||
|
||||
result = self.db_procedure_execute('p_shop_edit_user', argument_dict_list)
|
||||
cursor = result.cursor
|
||||
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw user data: {result_set_1}')
|
||||
|
||||
# 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_User.db_cursor_clear(cursor)
|
||||
|
||||
return (result_set_1[0][1] == b'\x01')
|
||||
|
||||
"""
|
||||
def get_many_user_order(self, id_user, ids_order, n_order_max, id_checkout_session):
|
||||
_m = 'DataStore_User.get_many_user_order'
|
||||
# av.val_str(id_user)
|
||||
# validation conducted by server
|
||||
|
||||
argument_dict_list = {
|
||||
'a_id_user': id_user,
|
||||
'a_ids_order': ids_order,
|
||||
'a_n_order_max': n_order_max,
|
||||
'a_id_checkout_session': id_checkout_session
|
||||
}
|
||||
|
||||
Helper_App.console_log('executing p_shop_get_many_user_order')
|
||||
result = self.db_procedure_execute('p_shop_get_many_user_order', argument_dict_list)
|
||||
cursor = result.cursor
|
||||
Helper_App.console_log('data received')
|
||||
|
||||
|
||||
# Discount Delivery Regions
|
||||
cursor.nextset()
|
||||
result_set_1 = cursor.fetchall()
|
||||
orders = []
|
||||
for row in result_set_1:
|
||||
new_order = Order(row[0], row[1], row[2], row[3], row[4], row[5], row[6])
|
||||
orders.append(new_order)
|
||||
Helper_App.console_log(f'orders: {orders}')
|
||||
|
||||
# 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_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_User.db_cursor_clear(cursor)
|
||||
|
||||
return orders
|
||||
"""
|
||||
|
||||
def get_many_user(self, user_filters, user=None):
|
||||
_m = 'DataStore_User.get_many_user'
|
||||
Helper_App.console_log(_m)
|
||||
# av.val_str(user_filters, 'user_filters', _m)
|
||||
# av.val_list(permutations, 'list_permutations', _m, Product_Permutation, 1)
|
||||
av.val_instance(user_filters, 'user_filters', _m, Parameters_User)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid()
|
||||
# now = datetime.now()
|
||||
# user = self.get_user_session()
|
||||
|
||||
"""
|
||||
argument_dict_list = {
|
||||
'a_id_user': id_user,
|
||||
'a_comment': comment,
|
||||
'a_guid': guid
|
||||
}
|
||||
"""
|
||||
if user is None:
|
||||
user = self.get_user_session()
|
||||
argument_dict_list = {
|
||||
# 'a_guid': guid
|
||||
'a_id_user': user.id_user
|
||||
, 'a_id_user_auth0': user.id_user_auth0
|
||||
, **user_filters.to_json()
|
||||
, 'a_debug': 0
|
||||
|
||||
}
|
||||
# argument_dict_list['a_guid'] = guid
|
||||
result = self.db_procedure_execute('p_get_many_user', argument_dict_list)
|
||||
"""
|
||||
query = text(f"SELECT * FROM Shop_Calc_User_Temp UE_T WHERE UE_T.guid = '{guid}'")
|
||||
result = self.db.session.execute(query)
|
||||
"""
|
||||
cursor = result.cursor
|
||||
result_set = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw users: {result_set}')
|
||||
Helper_App.console_log(f'type result set: {str(type(result_set))}')
|
||||
Helper_App.console_log(f'len result set: {len(result_set)}')
|
||||
"""
|
||||
user_permission_evals = []
|
||||
for row in result_set:
|
||||
user_permission_eval = User_Permission_Evaluation.from_DB_user_eval(row)
|
||||
user_permission_evals.append(user_permission_eval)
|
||||
Helper_App.console_log(f'user_permission_evals: {user_permission_evals}')
|
||||
"""
|
||||
users = []
|
||||
if len(result_set) > 0:
|
||||
for row in result_set:
|
||||
Helper_App.console_log(f'row: {row}')
|
||||
user = User.from_DB_user(row)
|
||||
users.append(user)
|
||||
Helper_App.console_log(f'user {str(type(user))}: {user}')
|
||||
Helper_App.console_log(f'type users: {str(type(users))}\n type user 0: {str(type(None if len(users) == 0 else users[0]))}')
|
||||
# error_list, cursor = self.get_error_list_from_cursor(cursor)
|
||||
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_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_User.db_cursor_clear(cursor)
|
||||
|
||||
return users, errors
|
||||
|
||||
def get_many_user(self, user_filters, user=None):
|
||||
_m = 'DataStore_User.get_many_user'
|
||||
Helper_App.console_log(_m)
|
||||
# av.val_str(user_filters, 'user_filters', _m)
|
||||
# av.val_list(permutations, 'list_permutations', _m, Product_Permutation, 1)
|
||||
av.val_instance(user_filters, 'user_filters', _m, Parameters_User)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid()
|
||||
# now = datetime.now()
|
||||
# user = self.get_user_session()
|
||||
|
||||
"""
|
||||
argument_dict_list = {
|
||||
'a_id_user': id_user,
|
||||
'a_comment': comment,
|
||||
'a_guid': guid
|
||||
}
|
||||
"""
|
||||
if user is None:
|
||||
user = self.get_user_session()
|
||||
argument_dict_list = {
|
||||
# 'a_guid': guid
|
||||
'a_id_user': user.id_user
|
||||
, 'a_id_user_auth0': user.id_user_auth0
|
||||
, **user_filters.to_json()
|
||||
, 'a_debug': 0
|
||||
|
||||
}
|
||||
# argument_dict_list['a_guid'] = guid
|
||||
result = self.db_procedure_execute('p_get_many_user', argument_dict_list)
|
||||
"""
|
||||
query = text(f"SELECT * FROM Shop_Calc_User_Temp UE_T WHERE UE_T.guid = '{guid}'")
|
||||
result = self.db.session.execute(query)
|
||||
"""
|
||||
cursor = result.cursor
|
||||
result_set = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw users: {result_set}')
|
||||
Helper_App.console_log(f'type result set: {str(type(result_set))}')
|
||||
Helper_App.console_log(f'len result set: {len(result_set)}')
|
||||
"""
|
||||
user_permission_evals = []
|
||||
for row in result_set:
|
||||
user_permission_eval = User_Permission_Evaluation.from_DB_user_eval(row)
|
||||
user_permission_evals.append(user_permission_eval)
|
||||
Helper_App.console_log(f'user_permission_evals: {user_permission_evals}')
|
||||
"""
|
||||
users = []
|
||||
if len(result_set) > 0:
|
||||
for row in result_set:
|
||||
Helper_App.console_log(f'row: {row}')
|
||||
user = User.from_DB_user(row)
|
||||
users.append(user)
|
||||
Helper_App.console_log(f'user {str(type(user))}: {user}')
|
||||
Helper_App.console_log(f'type users: {str(type(users))}\n type user 0: {str(type(None if len(users) == 0 else users[0]))}')
|
||||
# error_list, cursor = self.get_error_list_from_cursor(cursor)
|
||||
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_e]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
DataStore_User.db_cursor_clear(cursor)
|
||||
|
||||
return users, errors
|
||||
113
datastores/project_hub/datastore_contact_form.py
Normal file
113
datastores/project_hub/datastore_contact_form.py
Normal file
@@ -0,0 +1,113 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: DataStores
|
||||
Feature: User DataStore
|
||||
|
||||
Description:
|
||||
Datastore for Users
|
||||
"""
|
||||
|
||||
# internal
|
||||
# from routes import bp_home
|
||||
import lib.argument_validation as av
|
||||
from business_objects.sql_error import SQL_Error
|
||||
from business_objects.project_hub.contact_form import Contact_Form, Contact_Form_Temp
|
||||
from datastores.datastore_base import DataStore_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 datetime import datetime
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
|
||||
class DataStore_Contact_Form(DataStore_Base):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def get_many_contact_form(cls):
|
||||
_m = f'{cls.__qualname__}.get_many_contact_form'
|
||||
user = cls.get_user_session()
|
||||
argument_dict = {
|
||||
'a_id_user': user.id_user
|
||||
, 'a_debug': 0
|
||||
}
|
||||
Helper_App.console_log(f'argument_dict: {argument_dict}')
|
||||
result = cls.db_procedure_execute('p_ph_get_many_contact_form', argument_dict)
|
||||
cursor = result.cursor
|
||||
|
||||
# Contact_Forms
|
||||
result_set_1 = cursor.fetchall()
|
||||
Helper_App.console_log(f'raw contact_forms: {result_set_1}')
|
||||
contact_forms = []
|
||||
contact_form_indexes = {}
|
||||
for row in result_set_1:
|
||||
new_contact_form = Contact_Form.from_DB_contact_form(row)
|
||||
contact_form_indexes[new_contact_form.id_contact_form] = len(contact_forms)
|
||||
contact_forms.append(new_contact_form)
|
||||
|
||||
# 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]
|
||||
for error in errors:
|
||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||
|
||||
cls.db_cursor_clear(cursor)
|
||||
|
||||
return contact_forms, errors
|
||||
|
||||
@classmethod
|
||||
def save_contact_forms(cls, comment, contact_forms):
|
||||
_m = f'{cls}.save_contact_forms'
|
||||
av.val_str(comment, 'comment', _m)
|
||||
|
||||
guid = Helper_DB_MySQL.create_guid_str()
|
||||
now = datetime.now()
|
||||
user = cls.get_user_session()
|
||||
|
||||
Helper_App.console_log(f'saving contact forms: {contact_forms}')
|
||||
|
||||
rows = []
|
||||
for contact_form in contact_forms:
|
||||
row = Contact_Form_Temp.from_contact_form(contact_form)
|
||||
row.guid = guid
|
||||
rows.append(row)
|
||||
|
||||
cls.upload_bulk(Contact_Form_Temp.__tablename__, rows, 1000)
|
||||
|
||||
Helper_App.console_log('Contact Forms 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_ph_save_contact_form', argument_dict_list)
|
||||
|
||||
Helper_App.console_log('Contact Forms saved')
|
||||
|
||||
# Errors
|
||||
cursor = result.cursor
|
||||
cursor.nextset()
|
||||
result_set_e = cursor.fetchall()
|
||||
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}")
|
||||
|
||||
cls.db_cursor_clear(cursor)
|
||||
return errors
|
||||
@@ -8,7 +8,7 @@ from authlib.integrations.flask_client import OAuth
|
||||
|
||||
|
||||
csrf = CSRFProtect()
|
||||
cors = CORS()
|
||||
# cors = CORS()
|
||||
db = SQLAlchemy()
|
||||
mail = Mail()
|
||||
oauth = OAuth()
|
||||
100
forms/contact.py
Normal file
100
forms/contact.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
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.base import Base
|
||||
from business_objects.project_hub.contact_form import Contact_Form
|
||||
# from models.model_view_store import Model_View_Store # circular
|
||||
from models.model_view_base import Model_View_Base
|
||||
from forms.base import Form_Base
|
||||
# external
|
||||
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField, HiddenField, BooleanField, Field, EmailField
|
||||
from wtforms.validators import DataRequired, Email, ValidationError
|
||||
import markupsafe
|
||||
from flask_wtf.recaptcha import RecaptchaField
|
||||
from abc import ABCMeta, abstractmethod
|
||||
import json
|
||||
from altcha import verify_solution
|
||||
import base64
|
||||
|
||||
class ALTCHAValidator:
|
||||
def __init__(self, message=None):
|
||||
self.message = message or 'ALTCHA verification failed'
|
||||
|
||||
def __call__(self, form, field):
|
||||
altcha_data = field.data
|
||||
|
||||
if not altcha_data:
|
||||
raise ValidationError(self.message)
|
||||
|
||||
try:
|
||||
# The data is base64 encoded JSON
|
||||
try:
|
||||
# First try to decode it as JSON directly (if it's not base64 encoded)
|
||||
altcha_payload = json.loads(altcha_data)
|
||||
except json.JSONDecodeError:
|
||||
# If direct JSON decoding fails, try base64 decoding first
|
||||
decoded_data = base64.b64decode(altcha_data).decode('utf-8')
|
||||
altcha_payload = json.loads(decoded_data)
|
||||
|
||||
ok, err = verify_solution(altcha_payload, current_app.app_config.ALTCHA_SECRET_KEY, check_expires=True)
|
||||
|
||||
if err or not ok:
|
||||
raise ValidationError(self.message + ': ' + (err or 'Invalid solution'))
|
||||
|
||||
except Exception as e:
|
||||
raise ValidationError(f'Invalid ALTCHA data: {str(e)}')
|
||||
|
||||
class ALTCHAField(Field):
|
||||
def __init__(self, label='', validators=None, **kwargs):
|
||||
validators = validators or []
|
||||
validators.append(ALTCHAValidator())
|
||||
|
||||
super(ALTCHAField, self).__init__(label, validators, **kwargs)
|
||||
|
||||
def __call__(self, **kwargs):
|
||||
html = f"""
|
||||
<altcha-widget
|
||||
challengeurl="/get-challenge"
|
||||
auto="onload"
|
||||
id="{self.id}"
|
||||
name="{self.name}">
|
||||
</altcha-widget>
|
||||
"""
|
||||
return markupsafe.Markup(html)
|
||||
|
||||
|
||||
class Form_Contact(FlaskForm):
|
||||
email = EmailField('Email')
|
||||
contact_name = StringField('Name')
|
||||
company_name = StringField('Company')
|
||||
message = TextAreaField('Message')
|
||||
receive_marketing = BooleanField('I would like to receive marketing emails.')
|
||||
# recaptcha = RecaptchaField()
|
||||
# altcha = HiddenField('ALTCHA') # , validators=[validate_altcha]
|
||||
altcha = ALTCHAField('Verify you are human')
|
||||
submit = SubmitField('Send Message')
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
Base.FLAG_EMAIL: self.email.data
|
||||
, Contact_Form.FLAG_NAME_CONTACT: self.contact_name.data
|
||||
, Contact_Form.FLAG_NAME_COMPANY: self.company_name.data
|
||||
, Contact_Form.FLAG_MESSAGE: self.message.data
|
||||
, Contact_Form.FLAG_RECEIVE_MARKETING_COMMUNICATIONS: self.receive_marketing.data
|
||||
, Contact_Form.FLAG_ALTCHA: self.altcha.data
|
||||
, Base.FLAG_ACTIVE: True
|
||||
, Base.FLAG_CREATED_ON: None
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user