Feat: \n 1. Contact Us page form submission success page created. \n 2. Contact Us page styling and CAPTCHA text content. \n 3. Removal of ERP, Google CAPTCHA, and ALTCHA API code and left over comments in JavaScript, Python.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,6 +11,7 @@ __pycache__/
|
||||
|
||||
# Ignore logs and databases
|
||||
*.log
|
||||
*.log.*
|
||||
|
||||
# Ignore logs and databases
|
||||
# *.sql
|
||||
|
||||
2
app.py
2
app.py
@@ -19,7 +19,6 @@ Initializes the Flask application, sets the configuration based on the environme
|
||||
from config import app_config, Config
|
||||
from controllers.core import routes_core
|
||||
from controllers.legal import routes_legal
|
||||
from controllers.user import routes_user
|
||||
from extensions import db, csrf, mail, oauth
|
||||
from helpers.helper_app import Helper_App
|
||||
# external
|
||||
@@ -109,7 +108,6 @@ with app.app_context():
|
||||
|
||||
app.register_blueprint(routes_core)
|
||||
app.register_blueprint(routes_legal)
|
||||
app.register_blueprint(routes_user)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ class Access_Level(db.Model, 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],
|
||||
|
||||
@@ -94,7 +94,6 @@ class Address(db.Model, Base):
|
||||
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]),
|
||||
|
||||
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
|
||||
})
|
||||
@@ -62,7 +62,6 @@ class Region(db.Model, Base):
|
||||
}
|
||||
@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]
|
||||
|
||||
@@ -79,7 +79,6 @@ class Unit_Measurement(SQLAlchemy_ABC, Base):
|
||||
}
|
||||
@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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,10 +12,12 @@ Initializes the Flask application, sets the configuration based on the environme
|
||||
|
||||
# IMPORTS
|
||||
# internal
|
||||
from business_objects.api import API
|
||||
from datastores.datastore_base import DataStore_Base
|
||||
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
|
||||
@@ -51,49 +53,26 @@ def contact():
|
||||
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 jsonify(error=str(e)), 403
|
||||
return html_body
|
||||
return API.get_standard_response(
|
||||
success = False,
|
||||
status_code = 500,
|
||||
message = f"Error: {e}",
|
||||
data = None,
|
||||
errors = [str(e)],
|
||||
meta = None
|
||||
)
|
||||
|
||||
@routes_core.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['POST'])
|
||||
def contact_post():
|
||||
try:
|
||||
form = Form_Contact()
|
||||
Helper_App.console_log(f"Form submitted: {request.form}")
|
||||
Helper_App.console_log(f"ALTCHA data in request: {request.form.get('altcha')}")
|
||||
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." 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)
|
||||
flash('Thank you for your message. We will get back to you soon!', 'success')
|
||||
return "Submitted."
|
||||
except Exception as e:
|
||||
return f"Error: {e}"
|
||||
print(f"Form validation errors: {form.errors}")
|
||||
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_Contact.HASH_ALTCHA_CREATE_CHALLENGE, methods=['GET'])
|
||||
@routes_core.route(Model_View_Contact.HASH_GET_ALTCHA_CHALLENGE, methods=['GET'])
|
||||
def create_altcha_challenge():
|
||||
Helper_App.console_log(f'secret key: {current_app.app_config.ALTCHA_SECRET_KEY}')
|
||||
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)
|
||||
print("Challenge created:", challenge)
|
||||
Helper_App.console_log(f"Challenge created: {challenge}")
|
||||
# return jsonify({"challenge": challenge})
|
||||
return jsonify({
|
||||
"algorithm": challenge.algorithm,
|
||||
@@ -102,58 +81,64 @@ def create_altcha_challenge():
|
||||
"signature": challenge.signature,
|
||||
})
|
||||
|
||||
"""
|
||||
def verify_altcha_signature(payload):
|
||||
"" "Verify the ALTCHA signature"" "
|
||||
if 'algorithm' not in payload or 'signature' not in payload or 'verificationData' not in payload:
|
||||
return False
|
||||
|
||||
algorithm = payload['algorithm']
|
||||
signature = payload['signature']
|
||||
verification_data = payload['verificationData']
|
||||
|
||||
# Calculate SHA hash of the verification data
|
||||
if algorithm == 'SHA-256':
|
||||
hash_func = hashlib.sha256
|
||||
else:
|
||||
# Fallback to SHA-256 if algorithm not specified
|
||||
hash_func = hashlib.sha256
|
||||
|
||||
# Calculate the hash of verification_data
|
||||
data_hash = hash_func(verification_data.encode('utf-8')).digest()
|
||||
|
||||
# Calculate the HMAC signature
|
||||
calculated_signature = hmac.new(
|
||||
current_app.config["ALTCHA_SECRET_KEY"].encode('utf-8'),
|
||||
data_hash,
|
||||
hash_func
|
||||
).hexdigest()
|
||||
|
||||
# Compare the calculated signature with the provided signature
|
||||
return hmac.compare_digest(calculated_signature, signature)
|
||||
@routes_core.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)
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
|
||||
def create_altcha_dummy_signature(challenge):
|
||||
# Example payload to verify
|
||||
payload = {
|
||||
"algorithm": challenge.algorithm,
|
||||
"challenge": challenge.challenge,
|
||||
"number": 12345, # Example number
|
||||
"salt": challenge.salt,
|
||||
"signature": challenge.signature,
|
||||
}
|
||||
return payload
|
||||
|
||||
@routes_core.route(Model_View_Contact.HASH_ALTCHA_VERIFY_SOLUTION, methods=['POST'])
|
||||
def verify_altcha_challenge():
|
||||
payload = request.json
|
||||
|
||||
ok, err = verify_solution(payload, current_app.config["ALTCHA_SECRET_KEY"], check_expires=True)
|
||||
if err:
|
||||
return jsonify({"error": err}), 400
|
||||
elif ok:
|
||||
return jsonify({"verified": True})
|
||||
else:
|
||||
return jsonify({"verified": False}), 403
|
||||
"""
|
||||
@routes_core.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
|
||||
)
|
||||
|
||||
@@ -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,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
|
||||
@@ -89,60 +89,11 @@ 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')
|
||||
@@ -214,30 +165,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):
|
||||
@@ -271,17 +198,9 @@ class DataStore_Base(BaseModel):
|
||||
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)
|
||||
@@ -290,7 +209,6 @@ class DataStore_Base(BaseModel):
|
||||
# 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])
|
||||
@@ -308,17 +226,9 @@ class DataStore_Base(BaseModel):
|
||||
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)
|
||||
@@ -327,7 +237,6 @@ class DataStore_Base(BaseModel):
|
||||
# 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])
|
||||
@@ -348,18 +257,13 @@ class DataStore_Base(BaseModel):
|
||||
'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()
|
||||
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -42,9 +42,7 @@ class DataStore_User(DataStore_Base):
|
||||
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'),
|
||||
@@ -57,12 +55,10 @@ class DataStore_User(DataStore_Base):
|
||||
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:
|
||||
@@ -71,67 +67,12 @@ class DataStore_User(DataStore_Base):
|
||||
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 = {
|
||||
@@ -142,92 +83,47 @@ class DataStore_User(DataStore_Base):
|
||||
, '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}')
|
||||
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'
|
||||
av.val_instance(user_filters, 'user_filters', _m, Parameters_User)
|
||||
|
||||
guid = Helper_DB_MySQL.create_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
|
||||
|
||||
}
|
||||
result = self.db_procedure_execute('p_get_many_user', argument_dict_list)
|
||||
cursor = result.cursor
|
||||
result_set = cursor.fetchall()
|
||||
users = []
|
||||
if len(result_set) > 0:
|
||||
for row in result_set:
|
||||
|
||||
@@ -19,7 +19,7 @@ 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
|
||||
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
|
||||
@@ -76,12 +76,12 @@ class ALTCHAField(Field):
|
||||
|
||||
|
||||
class Form_Contact(FlaskForm):
|
||||
email = StringField('Email')
|
||||
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('Verification')
|
||||
altcha = ALTCHAField('Verify you are human')
|
||||
submit = SubmitField('Send Message')
|
||||
|
||||
@@ -31,7 +31,7 @@ def error_msg_str(v, v_name, method, v_type, suppress_errors = False, suppress_c
|
||||
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
|
||||
error_msg = error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, "<class 'bool'>", suppress_errors)
|
||||
if suppress_errors:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return error_msg
|
||||
else:
|
||||
raise ValueError(error_msg)
|
||||
@@ -40,7 +40,7 @@ def error_msg_str(v, v_name, method, v_type, suppress_errors = False, suppress_c
|
||||
error_msg = error_msg_str(method, 'method', my_f, "<class 'str'>", suppress_errors, suppress_console_outputs)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return error_msg
|
||||
else:
|
||||
raise ValueError(error_msg)
|
||||
@@ -50,7 +50,7 @@ def error_msg_str(v, v_name, method, v_type, suppress_errors = False, suppress_c
|
||||
error_msg = error_msg_str(v_name, 'v_name', my_f, "<class 'str'>", suppress_errors, suppress_console_outputs)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return error_msg
|
||||
else:
|
||||
raise ValueError(error_msg)
|
||||
@@ -61,7 +61,7 @@ def error_msg_str(v, v_name, method, v_type, suppress_errors = False, suppress_c
|
||||
error_msg = error_msg_str(v_type, 'v_type', my_f, "<class 'str'>", suppress_errors, suppress_console_outputs)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return error_msg
|
||||
else:
|
||||
raise ValueError(error_msg)
|
||||
@@ -70,7 +70,7 @@ def error_msg_str(v, v_name, method, v_type, suppress_errors = False, suppress_c
|
||||
error_msg = error_msg_str(v_arg_type, 'v_arg_type', my_f, "<class 'str'>", suppress_errors, suppress_console_outputs)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return error_msg
|
||||
else:
|
||||
raise ValueError(error_msg)
|
||||
@@ -96,7 +96,7 @@ def val_bool(v_input, v_name, method, suppress_errors = False, suppress_console_
|
||||
if str(type(suppress_console_outputs)) != v_type:
|
||||
error_msg = error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, v_type, suppress_errors)
|
||||
if suppress_errors:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
v_type = "<class 'str'>"
|
||||
@@ -111,7 +111,7 @@ def val_bool(v_input, v_name, method, suppress_errors = False, suppress_console_
|
||||
error_msg = error_msg_str(method, 'method', my_f, v_type, suppress_errors, suppress_console_outputs)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
my_f = method + '.' + my_f
|
||||
@@ -126,7 +126,7 @@ def val_bool(v_input, v_name, method, suppress_errors = False, suppress_console_
|
||||
error_msg = error_msg_str(v_name, 'v_name', my_f, v_type, suppress_errors, suppress_console_outputs)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
# v_arg_type
|
||||
@@ -140,7 +140,7 @@ def val_bool(v_input, v_name, method, suppress_errors = False, suppress_console_
|
||||
error_msg = error_msg_str(v_arg_type, 'v_arg_type', my_f, v_type, suppress_errors, suppress_console_outputs)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
else:
|
||||
raise ValueError(error_msg)
|
||||
@@ -150,7 +150,7 @@ def val_bool(v_input, v_name, method, suppress_errors = False, suppress_console_
|
||||
error_msg = error_msg_str(v_input, v_name, method, v_type, suppress_errors, suppress_console_outputs)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
# RETURNS
|
||||
@@ -176,7 +176,7 @@ def val_str(v_input, v_name, method, min_len = -1, max_len = -1, suppress_errors
|
||||
val_bool(suppress_errors, 'suppress_errors', my_f)
|
||||
# suppress_console_outputs
|
||||
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
|
||||
print(error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, "<class 'bool'>", suppress_errors))
|
||||
Helper_App.console_log(error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, "<class 'bool'>", suppress_errors))
|
||||
return False
|
||||
# method
|
||||
valid = True
|
||||
@@ -189,7 +189,7 @@ def val_str(v_input, v_name, method, min_len = -1, max_len = -1, suppress_errors
|
||||
error_msg = error_msg_str(method, 'method', my_f, v_type)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
my_f = method + '.' + my_f
|
||||
@@ -204,7 +204,7 @@ def val_str(v_input, v_name, method, min_len = -1, max_len = -1, suppress_errors
|
||||
error_msg = error_msg_str(v_name, 'v_name', my_f, v_type)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
# v_arg_type
|
||||
@@ -218,7 +218,7 @@ def val_str(v_input, v_name, method, min_len = -1, max_len = -1, suppress_errors
|
||||
error_msg = error_msg_str(v_arg_type, 'v_arg_type', my_f, v_type)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
# min_len
|
||||
@@ -227,7 +227,7 @@ def val_str(v_input, v_name, method, min_len = -1, max_len = -1, suppress_errors
|
||||
error_msg = error_msg_str(min_len, 'min_len', my_f, v_type)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
# max_len
|
||||
@@ -242,7 +242,7 @@ def val_str(v_input, v_name, method, min_len = -1, max_len = -1, suppress_errors
|
||||
error_msg = error_msg_str(max_len, 'max_len', my_f, v_type)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
# v_input
|
||||
@@ -256,15 +256,15 @@ def val_str(v_input, v_name, method, min_len = -1, max_len = -1, suppress_errors
|
||||
L = len(v_input)
|
||||
if min_len != -1 and L < min_len:
|
||||
valid = False
|
||||
print(f"Minimum str length {min_len} not met.")
|
||||
Helper_App.console_log(f"Minimum str length {min_len} not met.")
|
||||
if max_len != -1 and L > max_len:
|
||||
print(f"Maximum str length {max_len} not met.")
|
||||
Helper_App.console_log(f"Maximum str length {max_len} not met.")
|
||||
valid = False
|
||||
if not valid:
|
||||
error_msg = error_msg_str(v_input, v_name, method, v_type, suppress_errors, suppress_console_outputs, v_arg_type)
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
# RETURNS
|
||||
@@ -297,7 +297,7 @@ def val_int(v_input, v_name, method, v_min: Optional[int] = None, v_max: Optiona
|
||||
val_bool(suppress_errors, 'suppress_errors', my_f)
|
||||
# suppress_console_outputs
|
||||
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
|
||||
print(error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, "<class 'bool'>", suppress_errors))
|
||||
Helper_App.console_log(error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, "<class 'bool'>", suppress_errors))
|
||||
return False
|
||||
# method
|
||||
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
|
||||
@@ -322,28 +322,28 @@ def val_int(v_input, v_name, method, v_min: Optional[int] = None, v_max: Optiona
|
||||
if not mytype == str(type(v_input)):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
if (v_min != None and v_max != None):
|
||||
if (v_min > v_max):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
||||
Helper_App.console_log(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
||||
return False
|
||||
raise ValueError(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
||||
if (v_min != None):
|
||||
if (v_input < v_min):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg + f"\nValue less than minimum {v_min}.")
|
||||
Helper_App.console_log(error_msg + f"\nValue less than minimum {v_min}.")
|
||||
return False
|
||||
raise ValueError(error_msg + f"\nValue less than minimum {v_min}.")
|
||||
if (v_max != None):
|
||||
if (v_input > v_max):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg + f"\nValue greater than maximum {v_max}.")
|
||||
Helper_App.console_log(error_msg + f"\nValue greater than maximum {v_max}.")
|
||||
return False
|
||||
raise ValueError(error_msg + f"\nValue greater than maximum {v_max}.")
|
||||
# RETURNS
|
||||
@@ -368,7 +368,7 @@ def val_float(v_input, v_name, method, v_min = None, v_max = None, suppress_erro
|
||||
val_bool(suppress_errors, 'suppress_errors', my_f)
|
||||
# suppress_console_outputs
|
||||
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
|
||||
print(error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, "<class 'bool'>", suppress_errors))
|
||||
Helper_App.console_log(error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, "<class 'bool'>", suppress_errors))
|
||||
return False
|
||||
# v_name
|
||||
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
|
||||
@@ -393,28 +393,28 @@ def val_float(v_input, v_name, method, v_min = None, v_max = None, suppress_erro
|
||||
if not mytype == str(type(v_input)):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return False
|
||||
raise ValueError(error_msg)
|
||||
if (v_min != None and v_max != None):
|
||||
if (v_min > v_max):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
||||
Helper_App.console_log(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
||||
return False
|
||||
raise ValueError(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
||||
if (v_min != None):
|
||||
if (v_input < v_min):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg + f"\nValue less than minimum {v_min}.")
|
||||
Helper_App.console_log(error_msg + f"\nValue less than minimum {v_min}.")
|
||||
return False
|
||||
raise ValueError(error_msg + f"\nValue less than minimum {v_min}.")
|
||||
if (v_max != None):
|
||||
if (v_input > v_max):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg + f"\nValue greater than maximum {v_max}.")
|
||||
Helper_App.console_log(error_msg + f"\nValue greater than maximum {v_max}.")
|
||||
return False
|
||||
raise ValueError(error_msg + f"\nValue greater than maximum {v_max}.")
|
||||
# RETURNS
|
||||
@@ -456,7 +456,7 @@ def input_bool(v_input, v_name, method, suppress_errors = False, suppress_consol
|
||||
if not val_str(v_input, v_name, my_f, suppress_errors=True, suppress_console_outputs=True):
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return None
|
||||
raise ValueError(error_msg)
|
||||
else:
|
||||
@@ -471,7 +471,7 @@ def input_bool(v_input, v_name, method, suppress_errors = False, suppress_consol
|
||||
return False
|
||||
if suppress_errors:
|
||||
if not suppress_console_outputs:
|
||||
print(error_msg)
|
||||
Helper_App.console_log(error_msg)
|
||||
return None
|
||||
raise ValueError(error_msg)
|
||||
else:
|
||||
|
||||
@@ -47,6 +47,17 @@ class Model_View_Base(BaseModel, ABC):
|
||||
ATTR_VALUE_PREVIOUS: ClassVar[str] = 'previous-value'
|
||||
COMPANY_ADDRESS_SHORT: ClassVar[str] = '53 Alfred Green Close, Rugby, United Kingdom, CV22 6DN'
|
||||
COMPANY_NUMBER: ClassVar[str] = '13587499'
|
||||
ENDPOINT_GET_ALTCHA_CHALLENGE: ClassVar[str] = 'routes_core.create_altcha_challenge'
|
||||
ENDPOINT_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = 'routes_legal.accessibility_report'
|
||||
ENDPOINT_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = 'routes_legal.accessibility_statement'
|
||||
ENDPOINT_PAGE_CONTACT: ClassVar[str] = 'routes_core.contact'
|
||||
ENDPOINT_PAGE_CONTACT_SUCCESS: ClassVar[str] = 'routes_core.contact_success'
|
||||
ENDPOINT_PAGE_DATA_RETENTION_SCHEDULE: ClassVar[str] = 'routes_legal.retention_schedule'
|
||||
ENDPOINT_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = 'routes_core.error_no_permission'
|
||||
ENDPOINT_PAGE_HOME: ClassVar[str] = 'routes_core.home'
|
||||
ENDPOINT_PAGE_LICENSE: ClassVar[str] = 'routes_legal.license'
|
||||
ENDPOINT_PAGE_PRIVACY_POLICY: ClassVar[str] = 'routes_legal.privacy_policy'
|
||||
ENDPOINT_POST_CONTACT_FORM: ClassVar[str] = 'routes_core.contact_post'
|
||||
FLAG_ACCESS_LEVEL: ClassVar[str] = 'access_level'
|
||||
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = Base.FLAG_ACCESS_LEVEL_REQUIRED
|
||||
FLAG_ACTIVE: ClassVar[str] = Base.FLAG_ACTIVE
|
||||
@@ -62,6 +73,7 @@ class Model_View_Base(BaseModel, ABC):
|
||||
FLAG_BUTTON_PRIMARY: ClassVar[str] = 'button-primary'
|
||||
FLAG_CANCEL: ClassVar[str] = 'button-cancel'
|
||||
FLAG_CALLBACK: ClassVar[str] = 'callback'
|
||||
FLAG_CAPTCHA: ClassVar[str] = 'captcha'
|
||||
FLAG_CARD: ClassVar[str] = 'card'
|
||||
FLAG_CITY: ClassVar[str] = Base.FLAG_CITY
|
||||
FLAG_CLOSE_TEMPORARY_ELEMENT: ClassVar[str] = 'button-temporary-element-close'
|
||||
@@ -109,31 +121,12 @@ class Model_View_Base(BaseModel, ABC):
|
||||
FLAG_NAME_ATTR_OPTION_VALUE: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_VALUE
|
||||
FLAG_NAME_PLURAL: ClassVar[str] = Base.FLAG_NAME_PLURAL
|
||||
# FLAG_NAME_SINGULAR: ClassVar[str] = Base.FLAG_NAME_SINGULAR
|
||||
FLAG_NAV_ADMIN_HOME: ClassVar[str] = 'navAdminHome'
|
||||
FLAG_NAV_ADMIN_STORE_STRIPE_PRICES: ClassVar[str] = 'navAdminStoreStripePrices'
|
||||
FLAG_NAV_ADMIN_STORE_STRIPE_PRODUCTS: ClassVar[str] = 'navAdminStoreStripeProducts'
|
||||
FLAG_NAV_CONTACT: ClassVar[str] = 'navContact'
|
||||
FLAG_NAV_HOME: ClassVar[str] = 'navHome'
|
||||
FLAG_NAV_SERVICES: ClassVar[str] = 'navServices'
|
||||
FLAG_NAV_STORE_HOME: ClassVar[str] = 'navStoreHome'
|
||||
FLAG_NAV_STORE_MANUFACTURING_PURCHASE_ORDERS: ClassVar[str] = 'navStoreManufacturingPurchaseOrders'
|
||||
FLAG_NAV_STORE_PRODUCTS: ClassVar[str] = 'navStoreProducts'
|
||||
FLAG_NAV_STORE_PRODUCT_CATEGORIES: ClassVar[str] = 'navStoreProductCategories'
|
||||
FLAG_NAV_STORE_PRODUCT_PERMUTATIONS: ClassVar[str] = 'navStoreProductPermutations'
|
||||
FLAG_NAV_STORE_PRODUCT_PRICES: ClassVar[str] = 'navStoreProductPrices'
|
||||
FLAG_NAV_STORE_PRODUCT_VARIATIONS: ClassVar[str] = 'navStoreProductVariations'
|
||||
FLAG_NAV_STORE_STOCK_ITEMS: ClassVar[str] = 'navStoreStockItems'
|
||||
FLAG_NAV_STORE_SUPPLIERS: ClassVar[str] = 'navStoreSuppliers'
|
||||
FLAG_NAV_STORE_SUPPLIER_PURCHASE_ORDERS: ClassVar[str] = 'navStoreSupplierPurchaseOrders'
|
||||
FLAG_NAV_USER_ACCOUNT: ClassVar[str] = 'navUserAccount'
|
||||
FLAG_NAV_USER_ADMIN: ClassVar[str] = 'navUserAdmin'
|
||||
FLAG_NAV_USER_LOGIN: ClassVar[str] = 'navUserLogin'
|
||||
FLAG_NAV_USER_LOGOUT: ClassVar[str] = 'navUserLogout'
|
||||
FLAG_OVERLAY: ClassVar[str] = 'overlay'
|
||||
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
|
||||
FLAG_PHONE_NUMBER: ClassVar[str] = Base.FLAG_PHONE_NUMBER
|
||||
FLAG_POSTCODE: ClassVar[str] = Base.FLAG_POSTCODE
|
||||
FLAG_CAPTCHA: ClassVar[str] = 'recaptcha'
|
||||
FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
|
||||
FLAG_ROW: ClassVar[str] = 'row'
|
||||
FLAG_ROW_NEW: ClassVar[str] = 'row-new'
|
||||
@@ -148,25 +141,16 @@ class Model_View_Base(BaseModel, ABC):
|
||||
FLAG_TEMPORARY_ELEMENT: ClassVar[str] = 'temporary-element'
|
||||
FLAG_USER: ClassVar[str] = User.FLAG_USER
|
||||
FLAG_WEBSITE: ClassVar[str] = Base.FLAG_WEBSITE
|
||||
# flagIsDatePicker: ClassVar[str] = 'is-date-picker'
|
||||
HASH_ALTCHA_CREATE_CHALLENGE: ClassVar[str] = '/altcha/create-challenge'
|
||||
# HASH_ALTCHA_VERIFY_SOLUTION: ClassVar[str] = '/altcha/verify-solution'
|
||||
HASH_APPLY_FILTERS_STORE_PRODUCT_PERMUTATION: ClassVar[str] = '/store/permutation_filter'
|
||||
HASH_CALLBACK_LOGIN: ClassVar[str] = '/callback-login'
|
||||
HASH_GET_ALTCHA_CHALLENGE: ClassVar[str] = '/altcha/create-challenge'
|
||||
HASH_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = '/accessibility-report'
|
||||
HASH_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = '/accessibility-statement'
|
||||
HASH_PAGE_ADMIN_HOME: ClassVar[str] = '/admin'
|
||||
HASH_PAGE_CONTACT: ClassVar[str] = '/contact'
|
||||
HASH_PAGE_CONTACT_SUCCESS: ClassVar[str] = '/contact-success'
|
||||
HASH_PAGE_DATA_RETENTION_SCHEDULE: ClassVar[str] = '/retention-schedule'
|
||||
HASH_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = '/error'
|
||||
HASH_PAGE_HOME: ClassVar[str] = '/'
|
||||
HASH_PAGE_LICENSE: ClassVar[str] = '/license'
|
||||
HASH_PAGE_PRIVACY_POLICY: ClassVar[str] = '/privacy-policy'
|
||||
HASH_PAGE_SERVICES: ClassVar[str] = '/services'
|
||||
HASH_PAGE_USER_ACCOUNT: ClassVar[str] = '/user'
|
||||
HASH_PAGE_USER_ADMIN: ClassVar[str] = '/user/admin'
|
||||
HASH_PAGE_USER_LOGIN: ClassVar[str] = '/login'
|
||||
HASH_PAGE_USER_LOGOUT: ClassVar[str] = '/logout'
|
||||
ID_BUTTON_ADD: ClassVar[str] = 'buttonAdd'
|
||||
ID_BUTTON_APPLY_FILTERS: ClassVar[str] = 'buttonApplyFilters'
|
||||
ID_BUTTON_CANCEL: ClassVar[str] = 'buttonCancel'
|
||||
@@ -174,24 +158,8 @@ class Model_View_Base(BaseModel, ABC):
|
||||
ID_BUTTON_SAVE: ClassVar[str] = 'buttonSave'
|
||||
ID_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
||||
ID_FORM_CONTACT: ClassVar[str] = 'formContact'
|
||||
ID_FORM_CURRENCY: ClassVar[str] = 'formCurrency'
|
||||
ID_FORM_DELIVERY_REGION: ClassVar[str] = 'formDeliveryRegion'
|
||||
ID_FORM_FILTERS: ClassVar[str] = 'formFilters'
|
||||
ID_FORM_IS_INCLUDED_VAT: ClassVar[str] = 'formIsIncludedVAT'
|
||||
ID_LABEL_ERROR: ClassVar[str] = 'labelError'
|
||||
"""
|
||||
ID_MODAL_SERVICES: ClassVar[str] = 'modalServices'
|
||||
ID_MODAL_TECHNOLOGIES: ClassVar[str] = 'modalTechnologies'
|
||||
ID_BUTTON_NAV_ADMIN_HOME: ClassVar[str] = 'navAdminHome'
|
||||
ID_BUTTON_NAV_ADMIN_STORE_STRIPE_PRICE: ClassVar[str] = 'navAdminStoreStripePrice'
|
||||
ID_BUTTON_NAV_ADMIN_STORE_STRIPE_PRODUCT: ClassVar[str] = 'navAdminStoreStripeProduct'
|
||||
# ID_BUTTON_NAV_CONTACT: ClassVar[str] = 'navContact'
|
||||
ID_BUTTON_NAV_HOME: ClassVar[str] = 'navHome'
|
||||
ID_BUTTON_NAV_SERVICES: ClassVar[str] = 'navServices'
|
||||
ID_BUTTON_NAV_USER_ADMIN: ClassVar[str] = 'navUserAdmin'
|
||||
ID_BUTTON_NAV_USER_LOGIN: ClassVar[str] = 'navUserLogin'
|
||||
ID_BUTTON_NAV_USER_LOGOUT: ClassVar[str] = 'navUserLogout'
|
||||
"""
|
||||
ID_OVERLAY_CONFIRM: ClassVar[str] = 'overlayConfirm'
|
||||
ID_OVERLAY_ERROR: ClassVar[str] = 'overlayError'
|
||||
ID_OVERLAY_HAMBURGER: ClassVar[str] = 'overlayHamburger'
|
||||
@@ -201,23 +169,10 @@ class Model_View_Base(BaseModel, ABC):
|
||||
NAME_COMPANY: ClassVar[str] = 'Precision And Research Technology Systems Limited'
|
||||
NAME_COMPANY_SHORT: ClassVar[str] = 'PARTS Ltd'
|
||||
NAME_CSRF_TOKEN: ClassVar[str] = 'csrf-token'
|
||||
# URL_HOST: ClassVar[str] = os.env() 'http://127.0.0.1:5000' # 'https://www.partsltd.co.uk'
|
||||
URL_GITHUB: ClassVar[str] = 'https://github.com/Teddy-1024'
|
||||
URL_LINKEDIN: ClassVar[str] = 'https://uk.linkedin.com/in/lordteddyms'
|
||||
URL_LINKEDIN: ClassVar[str] = 'https://uk.linkedin.com/in/teddyms'
|
||||
|
||||
# Attributes
|
||||
"""
|
||||
is_user_logged_in: bool
|
||||
id_user: str
|
||||
form_is_included_VAT: Form_Is_Included_VAT
|
||||
form_delivery_region: Form_Delivery_Region
|
||||
form_currency: Form_Currency
|
||||
# app: Flask
|
||||
db: SQLAlchemy
|
||||
"""
|
||||
# """
|
||||
hash_page_current: str
|
||||
# """
|
||||
app: Flask = None
|
||||
session: None = None
|
||||
is_page_store: bool = None
|
||||
@@ -232,48 +187,18 @@ class Model_View_Base(BaseModel, ABC):
|
||||
def title(self):
|
||||
pass
|
||||
|
||||
"""
|
||||
def __new__(cls, db, info_user, app): # , *args, **kwargs
|
||||
# Initialiser - validation
|
||||
_m = 'Model_View_Base.__new__'
|
||||
v_arg_type = 'class attribute'
|
||||
Helper_App.console_log(f'{_m}\nstarting')
|
||||
# return super().__new__(cls, *args, **kwargs)
|
||||
av.val_instance(db, 'db', _m, SQLAlchemy, v_arg_type=v_arg_type)
|
||||
return super(Model_View_Base, cls).__new__(cls)
|
||||
"""
|
||||
def __init__(self, hash_page_current, **kwargs):
|
||||
# Constructor
|
||||
"""
|
||||
_m = 'Model_View_Base.__init__'
|
||||
v_arg_type = 'class attribute'
|
||||
Helper_App.console_log(f'{_m}\nstarting')
|
||||
av.val_instance(db, 'db', _m, SQLAlchemy, v_arg_type=v_arg_type)
|
||||
"""
|
||||
BaseModel.__init__(self, hash_page_current=hash_page_current, **kwargs)
|
||||
"""
|
||||
self.db = db
|
||||
self.session = session
|
||||
info_user = self.get_info_user()
|
||||
Helper_App.console_log(f'info_user: {info_user}\ntype: {str(type(info_user))}')
|
||||
self.is_user_logged_in = ('sub' in list(info_user.keys()) and not info_user['sub'] == '' and not str(type(info_user['sub'])) == "<class 'NoneType'?")
|
||||
Helper_App.console_log(f'is_user_logged_in: {self.is_user_logged_in}')
|
||||
self.id_user = info_user['sub'] if self.is_user_logged_in else ''
|
||||
self.app = app
|
||||
"""
|
||||
self.app = current_app
|
||||
with self.app.app_context():
|
||||
self.session = session
|
||||
# self.form_is_included_VAT = Form_Is_Included_VAT()
|
||||
# self.form_delivery_region = Form_Delivery_Region()
|
||||
# self.form_currency = Form_Currency()
|
||||
self.is_page_store = False
|
||||
Helper_App.console_log(f'session: {self.session}')
|
||||
|
||||
datastore_user = DataStore_User()
|
||||
self.user = datastore_user.get_user_session()
|
||||
self.is_user_logged_in = self.user.is_logged_in
|
||||
Helper_App.console_log(f'model_view_base init end - model.user: {self.user}')
|
||||
# Helper_App.console_log(f'model_view_base init end - model.user: {self.user}')
|
||||
|
||||
def output_bool(self, boolean):
|
||||
return str(boolean).lower()
|
||||
@@ -284,34 +209,6 @@ class Model_View_Base(BaseModel, ABC):
|
||||
def get_user_session(self):
|
||||
datastore_user = DataStore_User()
|
||||
return datastore_user.get_user_session()
|
||||
|
||||
"""
|
||||
def get_is_admin_store_user(self):
|
||||
datastore_store = DataStore_Store()
|
||||
user = datastore_store.get_user_session()
|
||||
if not user.is_logged_in: return False
|
||||
filters_user = Parameters_User.from_user(user) # get_default(datastore_store)
|
||||
users, errors = datastore_store.get_many_user(filters_user)
|
||||
try:
|
||||
user = users[0]
|
||||
return av.input_bool(user.can_admin_store, 'can_admin_store', 'Model_View_Base.get_is_admin_store_user')
|
||||
except:
|
||||
return False
|
||||
user = self.get_user_session()
|
||||
return user.can_admin_store
|
||||
|
||||
def get_is_admin_user_user(self):
|
||||
datastore_store = DataStore_Store()
|
||||
user = datastore_store.get_user_session()
|
||||
if not user.is_logged_in: return False
|
||||
filters_user = Parameters_User.from_user(user) # .get_default(datastore_store)
|
||||
users, errors = datastore_store.get_many_user(filters_user)
|
||||
try:
|
||||
user = users[0]
|
||||
return av.input_bool(user.can_admin_user, 'can_admin_user', 'Model_View_Base.get_is_admin_user_user')
|
||||
except:
|
||||
return False
|
||||
"""
|
||||
|
||||
def get_many_access_level(self, filters=None):
|
||||
_m = 'Model_View_Store.get_many_access_level'
|
||||
@@ -358,7 +255,6 @@ class Model_View_Base(BaseModel, ABC):
|
||||
if preview_str != '':
|
||||
preview_str += '\n'
|
||||
obj_json = obj.to_json()
|
||||
Helper_App.console_log(f'obj_json: {obj_json}')
|
||||
preview_str += obj_json[obj_json[Base.FLAG_NAME_ATTR_OPTION_TEXT]]
|
||||
return preview_str
|
||||
@staticmethod
|
||||
|
||||
31
models/model_view_contact_success.py
Normal file
31
models/model_view_contact_success.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Project: PARTS Website
|
||||
Author: Edward Middleton-Smith
|
||||
Precision And Research Technology Systems Limited
|
||||
|
||||
Technology: View Models
|
||||
Feature: Contact View Model
|
||||
|
||||
Description:
|
||||
Data model for contact view
|
||||
"""
|
||||
|
||||
# internal
|
||||
from models.model_view_base import Model_View_Base
|
||||
# from routes import bp_home
|
||||
from lib import argument_validation as av
|
||||
# from forms.contact import Form_Contact
|
||||
# external
|
||||
from flask_wtf import FlaskForm
|
||||
from abc import abstractproperty
|
||||
from pydantic import BaseModel
|
||||
from typing import ClassVar
|
||||
|
||||
class Model_View_Contact_Success(Model_View_Base):
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return 'Contact Success'
|
||||
|
||||
def __init__(self, hash_page_current=Model_View_Base.HASH_PAGE_CONTACT_SUCCESS, **kwargs):
|
||||
super().__init__(hash_page_current=hash_page_current, **kwargs)
|
||||
182
pay_stripe.py
182
pay_stripe.py
@@ -1,182 +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
|
||||
# VARIABLE INSTANTIATION
|
||||
# METHODS
|
||||
|
||||
# IMPORTS
|
||||
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
|
||||
|
||||
from config import app_config
|
||||
|
||||
# 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():
|
||||
print(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
|
||||
print(f"Success! Here is your starter subscription product id: {starter_subscription.id}")
|
||||
print(f"Success! Here is your starter subscription price id: {starter_subscription_price.id}")
|
||||
|
||||
return starter_subscription_price.id
|
||||
|
||||
def get_file_str(f_address):
|
||||
f = open(f_address)
|
||||
return f.read()
|
||||
|
||||
# Ensure environment variables are set.
|
||||
price = os.getenv('PRICE')
|
||||
if price is None or price == 'price_12345' or price == '':
|
||||
print('You must set a Price ID in .env. Please see the README.')
|
||||
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"))))
|
||||
# template_dir = str(os.path.abspath(os.path.join(
|
||||
# app_dir, os.getenv("TEMPLATE_DIR"))))
|
||||
app = Flask(__name__) # , static_folder=static_dir,
|
||||
# static_url_path="", template_folder=template_dir)
|
||||
app.config.from_object(app_config)
|
||||
|
||||
@app.route('/', methods=['GET'])
|
||||
def home():
|
||||
# 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('_home.html', title='Home')
|
||||
|
||||
@app.route('/store', methods=['GET'])
|
||||
def store_home():
|
||||
return render_template('_store_home.html', title='Store Home')
|
||||
|
||||
@app.route('/contact')
|
||||
def contact():
|
||||
return render_template('_contact.html', title='Contact Us')
|
||||
|
||||
|
||||
@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')
|
||||
print(f'checkout session id: {id}')
|
||||
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='subscription', # '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']
|
||||
|
||||
print('event ' + event_type)
|
||||
|
||||
if event_type == 'checkout.session.completed':
|
||||
print('🔔 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)
|
||||
@@ -30,4 +30,4 @@ body {
|
||||
position: fixed;
|
||||
top:
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -4,19 +4,23 @@
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
max-width: 800px;
|
||||
max-width: 60vw;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.contact-form textarea {
|
||||
max-width: 40vw;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
@@ -36,13 +40,32 @@ textarea.form-input {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.marketing-consent {
|
||||
margin: 2rem 0;
|
||||
padding-left: 200px;
|
||||
.marketing-consent input {
|
||||
display: inline-block;
|
||||
margin-left: 18vw;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.container.recaptcha {
|
||||
.container.captcha > div:first-child {
|
||||
margin-left: 15vw;
|
||||
margin-right: 15vw;
|
||||
}
|
||||
.container.captcha > div:first-child > label:first-child {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.container.captcha > p:last-child{
|
||||
font-size: 0.9rem;
|
||||
margin: 1vh 0;
|
||||
}
|
||||
|
||||
.container.captcha .altcha-main {
|
||||
padding-left: 1rem;
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.container.captcha .altcha-main > :last-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
@@ -73,7 +96,17 @@ input[type="submit"]:hover {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.data-notice ul li {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contact-form {
|
||||
max-width: 80vw;
|
||||
}
|
||||
.contact-form textarea {
|
||||
max-width: 60vw;
|
||||
}
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
|
||||
45
static/dist/css/core_contact.bundle.css
vendored
45
static/dist/css/core_contact.bundle.css
vendored
@@ -4,19 +4,23 @@
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
max-width: 800px;
|
||||
max-width: 60vw;
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.contact-form textarea {
|
||||
max-width: 40vw;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
@@ -36,13 +40,32 @@ textarea.form-input {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.marketing-consent {
|
||||
margin: 2rem 0;
|
||||
padding-left: 200px;
|
||||
.marketing-consent input {
|
||||
display: inline-block;
|
||||
margin-left: 18vw;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.container.recaptcha {
|
||||
.container.captcha > div:first-child {
|
||||
margin-left: 15vw;
|
||||
margin-right: 15vw;
|
||||
}
|
||||
.container.captcha > div:first-child > label:first-child {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.container.captcha > p:last-child{
|
||||
font-size: 0.9rem;
|
||||
margin: 1vh 0;
|
||||
}
|
||||
|
||||
.container.captcha .altcha-main {
|
||||
padding-left: 1rem;
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.container.captcha .altcha-main > :last-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
@@ -73,7 +96,17 @@ input[type="submit"]:hover {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.data-notice ul li {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contact-form {
|
||||
max-width: 80vw;
|
||||
}
|
||||
.contact-form textarea {
|
||||
max-width: 60vw;
|
||||
}
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
|
||||
1
static/dist/css/main.bundle.css
vendored
1
static/dist/css/main.bundle.css
vendored
@@ -31,6 +31,7 @@ body {
|
||||
top:
|
||||
}
|
||||
*/
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 0.75rem 1.5rem;
|
||||
|
||||
645
static/dist/js/main.bundle.js
vendored
645
static/dist/js/main.bundle.js
vendored
File diff suppressed because one or more lines are too long
104
static/js/api.js
104
static/js/api.js
@@ -56,108 +56,4 @@ export default class API {
|
||||
API.goToUrl(url);
|
||||
}
|
||||
|
||||
|
||||
// specific api calls
|
||||
/* Example:
|
||||
getUsers: () => request('/users'),
|
||||
getUserById: (id) => request(`/users/${id}`),
|
||||
createUser: (userData) => request('/users', 'POST', userData),
|
||||
updateUser: (id, userData) => request(`/users/${id}`, 'PUT', userData),
|
||||
deleteUser: (id) => request(`/users/${id}`, 'DELETE'),
|
||||
*/
|
||||
static async loginUser() {
|
||||
let callback = {};
|
||||
callback[flagCallback] = DOM.getHashPageCurrent();
|
||||
return await API.request(hashPageUserLogin, 'POST', callback);
|
||||
}
|
||||
|
||||
// store
|
||||
// product categories
|
||||
static async saveCategories(categories, formFilters, comment) {
|
||||
let dataRequest = {};
|
||||
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
dataRequest[flagProductCategory] = categories;
|
||||
dataRequest[flagComment] = comment;
|
||||
return await API.request(hashSaveStoreProductCategory, 'POST', dataRequest);
|
||||
}
|
||||
|
||||
// products
|
||||
static async saveProducts(products, formFilters, comment) {
|
||||
let dataRequest = {};
|
||||
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
dataRequest[flagProduct] = products;
|
||||
dataRequest[flagComment] = comment;
|
||||
return await API.request(hashSaveStoreProduct, 'POST', dataRequest);
|
||||
}
|
||||
|
||||
// product permutations
|
||||
static async saveProductPermutations(permutations, formFilters, comment) {
|
||||
let dataRequest = {};
|
||||
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
dataRequest[flagProductPermutation] = permutations;
|
||||
dataRequest[flagComment] = comment;
|
||||
return await API.request(hashSaveStoreProductPermutation, 'POST', dataRequest);
|
||||
}
|
||||
|
||||
// product variations
|
||||
static async saveProductVariations(variationTypes, formFilters, comment) {
|
||||
let dataRequest = {};
|
||||
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
dataRequest[flagProductVariationType] = variationTypes;
|
||||
dataRequest[flagComment] = comment;
|
||||
return await API.request(hashSaveStoreProductVariation, 'POST', dataRequest);
|
||||
}
|
||||
|
||||
// stock items
|
||||
static async saveStockItems(stockItems, formFilters, comment) {
|
||||
let dataRequest = {};
|
||||
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
dataRequest[flagStockItem] = stockItems;
|
||||
dataRequest[flagComment] = comment;
|
||||
return await API.request(hashSaveStoreStockItem, 'POST', dataRequest);
|
||||
}
|
||||
|
||||
// suppliers
|
||||
static async saveSuppliers(suppliers, formFilters, comment) {
|
||||
let dataRequest = {};
|
||||
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
dataRequest[flagSupplier] = suppliers;
|
||||
dataRequest[flagComment] = comment;
|
||||
return await API.request(hashSaveStoreSupplier, 'POST', dataRequest);
|
||||
}
|
||||
|
||||
// supplier purchase orders
|
||||
static async saveSupplierPurchaseOrders(supplierPurchaseOrders, formFilters, comment) {
|
||||
let dataRequest = {};
|
||||
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
dataRequest[flagSupplierPurchaseOrder] = supplierPurchaseOrders;
|
||||
dataRequest[flagComment] = comment;
|
||||
return await API.request(hashSaveStoreSupplierPurchaseOrder, 'POST', dataRequest);
|
||||
}
|
||||
|
||||
// manufacturing purchase orders
|
||||
static async saveManufacturingPurchaseOrders(manufacturingPurchaseOrders, formFilters, comment) {
|
||||
let dataRequest = {};
|
||||
dataRequest[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
dataRequest[flagManufacturingPurchaseOrder] = manufacturingPurchaseOrders;
|
||||
dataRequest[flagComment] = comment;
|
||||
return await API.request(hashSaveStoreManufacturingPurchaseOrder, 'POST', dataRequest);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
const api = new API();
|
||||
export default api;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initializeApp();
|
||||
setupEventListeners();
|
||||
initializeComponents();
|
||||
|
||||
// Example of using the API
|
||||
API.getData('/some-endpoint')
|
||||
.then(data => console.log('Data received:', data))
|
||||
.catch(error => console.error('Error:', error));
|
||||
});
|
||||
*/
|
||||
@@ -1,13 +1,15 @@
|
||||
|
||||
import Utils from '../../lib/utils.js';
|
||||
|
||||
function videoPlay(elemVideo) {
|
||||
if (!_loading) { // elemVideo.paused &&
|
||||
elemVideo.play();
|
||||
if (_verbose) { console.log("Playing video element: " + elemVideo.name)};
|
||||
Utils.consoleLogIfNotProductionEnvironment("Playing video element: " + elemVideo.name);
|
||||
}
|
||||
}
|
||||
|
||||
function videoPause(elemVideo) {
|
||||
elemVideo.pause();
|
||||
if (_verbose) { console.log("Pausing video element: " + elemVideo.name)};
|
||||
Utils.consoleLogIfNotProductionEnvironment("Pausing video element: " + elemVideo.name);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
import Utils from "./lib/utils.js";
|
||||
import Validation from "./lib/validation.js";
|
||||
|
||||
export default class DOM {
|
||||
@@ -138,18 +139,10 @@ export default class DOM {
|
||||
debugger;
|
||||
if (Validation.isEmpty(element)) return null;
|
||||
return element.getAttribute(attrValueCurrent);
|
||||
if (!Validation.isEmpty(value) && element.type === "checkbox") {
|
||||
value = (value === 'true');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static getElementAttributeValuePrevious(element) {
|
||||
if (Validation.isEmpty(element)) return null;
|
||||
return element.getAttribute(attrValuePrevious);
|
||||
if (!Validation.isEmpty(value) && element.type === "checkbox") {
|
||||
value = (value === 'true');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/* base_table.handleChangeElementCellTable
|
||||
static updateAndCheckIsTableElementDirty(element) {
|
||||
@@ -158,28 +151,17 @@ export default class DOM {
|
||||
let wasDirtyRow = DOM.hasDirtyChildrenNotDeletedContainer(row);
|
||||
let isDirty = DOM.updateAndCheckIsElementDirty(element);
|
||||
let cell = DOM.getCellFromElement(element);
|
||||
console.log({element, row, cell, isDirty, wasDirty});
|
||||
Utils.consoleLogIfNotProductionEnvironment({element, row, cell, isDirty, wasDirty});
|
||||
if (isDirty != wasDirty) {
|
||||
DOM.handleDirtyElement(cell, isDirty);
|
||||
let isDirtyRow = DOM.hasDirtyChildrenNotDeletedContainer(row);
|
||||
console.log({isDirtyRow, wasDirtyRow});
|
||||
Utils.consoleLogIfNotProductionEnvironment({isDirtyRow, wasDirtyRow});
|
||||
if (isDirtyRow != wasDirtyRow) {
|
||||
DOM.handleDirtyElement(row, isDirtyRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
static updateElement(id, data) {
|
||||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
element.textContent = data;
|
||||
}
|
||||
}
|
||||
*/
|
||||
/* non-static method on page object to use
|
||||
static handleChangeElement(element) {}
|
||||
*/
|
||||
static scrollToElement(parent, element) {
|
||||
// REQUIRED: parent has scroll-bar
|
||||
parent.scrollTop(parent.scrollTop() + (element.offset().top - parent.offset().top));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
import Utils from '../utils.js';
|
||||
|
||||
export default class BusinessObjects {
|
||||
static getOptionJsonFromObjectJsonAndKeys(objectJson, keyText, keyValue, valueSelected = null) {
|
||||
@@ -11,16 +12,9 @@ export default class BusinessObjects {
|
||||
static getOptionJsonFromObjectJson(objectJson, valueSelected = null) {
|
||||
let keyText = objectJson[flagNameAttrOptionText];
|
||||
let keyValue = objectJson[flagNameAttrOptionValue];
|
||||
if (_verbose) { console.log({objectJson, keyText, keyValue}); };
|
||||
Utils.consoleLogIfNotProductionEnvironment({objectJson, keyText, keyValue});
|
||||
return BusinessObjects.getOptionJsonFromObjectJsonAndKeys(objectJson, keyText, keyValue, valueSelected);
|
||||
}
|
||||
/*
|
||||
static getOptionJsonFromProductPermutation(permutation) {
|
||||
return {
|
||||
text: permutation
|
||||
};
|
||||
}
|
||||
*/
|
||||
static getObjectText(objectJson) {
|
||||
return objectJson == null ? '' : objectJson[objectJson[flagNameAttrOptionText]];
|
||||
}
|
||||
|
||||
@@ -16,4 +16,9 @@ export default class Utils {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
static consoleLogIfNotProductionEnvironment(message) {
|
||||
if (!environment.is_production) {
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import Events from "../lib/events.js";
|
||||
import LocalStorage from "../lib/local_storage.js";
|
||||
import API from "../api.js";
|
||||
import DOM from "../dom.js";
|
||||
import Utils from "../lib/utils.js";
|
||||
|
||||
import OverlayConfirm from "../components/common/temporary/overlay_confirm.js";
|
||||
import OverlayError from "../components/common/temporary/overlay_error.js";
|
||||
@@ -14,11 +15,10 @@ export default class BasePage {
|
||||
throw new Error("Router is required");
|
||||
}
|
||||
else {
|
||||
if (_verbose) { console.log("initialising with router: ", router); }
|
||||
Utils.consoleLogIfNotProductionEnvironment("initialising with router: ", router);
|
||||
}
|
||||
this.router = router;
|
||||
this.title = titlePageCurrent;
|
||||
// this.hash = hashPageCurrent;
|
||||
if (this.constructor === BasePage) {
|
||||
throw new Error("Cannot instantiate abstract class");
|
||||
}
|
||||
@@ -38,7 +38,7 @@ export default class BasePage {
|
||||
}
|
||||
|
||||
logInitialisation() {
|
||||
if (_verbose) { console.log('Initializing ' + this.title + ' page'); }
|
||||
Utils.consoleLogIfNotProductionEnvironment('Initializing ' + this.title + ' page');
|
||||
}
|
||||
|
||||
hookupCommonElements() {
|
||||
@@ -58,7 +58,7 @@ export default class BasePage {
|
||||
|
||||
hookupLogos() {
|
||||
this.hookupEventHandler("click", "." + flagImageLogo + "," + "." + flagLogo, (event, element) => {
|
||||
if (_verbose) { console.log('clicking logo'); }
|
||||
Utils.consoleLogIfNotProductionEnvironment('clicking logo');
|
||||
this.router.navigateToHash(hashPageHome);
|
||||
});
|
||||
}
|
||||
@@ -81,15 +81,14 @@ export default class BasePage {
|
||||
Events.initialiseEventHandler('form.' + flagFilter + ' button.' + flagSave, flagInitialised, (button) => {
|
||||
button.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
if (_verbose) { console.log('saving page: ', this.title); }
|
||||
Utils.consoleLogIfNotProductionEnvironment('saving page: ', this.title);
|
||||
OverlayConfirm.show();
|
||||
});
|
||||
// button.classList.add(flagCollapsed);
|
||||
});
|
||||
}
|
||||
|
||||
leave() {
|
||||
if (_verbose) { console.log('Leaving ' + this.title + ' page'); }
|
||||
Utils.consoleLogIfNotProductionEnvironment('Leaving ' + this.title + ' page');
|
||||
if (this.constructor === BasePage) {
|
||||
throw new Error("Must implement leave() method.");
|
||||
}
|
||||
@@ -107,11 +106,11 @@ export default class BasePage {
|
||||
if (show) {
|
||||
buttonCancel.classList.remove(flagCollapsed);
|
||||
buttonSave.classList.remove(flagCollapsed);
|
||||
if (_verbose) { console.log('showing buttons'); }
|
||||
Utils.consoleLogIfNotProductionEnvironment('showing buttons');
|
||||
} else {
|
||||
buttonCancel.classList.add(flagCollapsed);
|
||||
buttonSave.classList.add(flagCollapsed);
|
||||
if (_verbose) { console.log('hiding buttons'); }
|
||||
Utils.consoleLogIfNotProductionEnvironment('hiding buttons');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,4 +119,5 @@ export default class BasePage {
|
||||
if (isDirty) document.querySelectorAll(idTableMain + ' tbody tr').remove();
|
||||
return isDirty;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -122,7 +122,7 @@ export default class TableBasePage extends BasePage {
|
||||
getAndLoadFilteredTableContentSinglePageApp() {
|
||||
this.callFilterTableContent()
|
||||
.then(data => {
|
||||
if (_verbose) { console.log('Table data received:', data); }
|
||||
Utils.consoleLogIfNotProductionEnvironment('Table data received:', data);
|
||||
this.callbackLoadTableContent(data);
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
@@ -144,13 +144,13 @@ export default class TableBasePage extends BasePage {
|
||||
.then(data => {
|
||||
if (data[flagStatus] == flagSuccess) {
|
||||
if (_verbose) {
|
||||
console.log('Records saved!');
|
||||
console.log('Data received:', data);
|
||||
Utils.consoleLogIfNotProductionEnvironment('Records saved!');
|
||||
Utils.consoleLogIfNotProductionEnvironment('Data received:', data);
|
||||
}
|
||||
this.callFilterTableContent();
|
||||
}
|
||||
else {
|
||||
if (_verbose) { console.log("error: ", data[flagMessage]); }
|
||||
Utils.consoleLogIfNotProductionEnvironment("error: ", data[flagMessage]);
|
||||
OverlayError.show(data[flagMessage]);
|
||||
}
|
||||
})
|
||||
@@ -181,13 +181,13 @@ export default class TableBasePage extends BasePage {
|
||||
.then(data => {
|
||||
if (data[flagStatus] == flagSuccess) {
|
||||
if (_verbose) {
|
||||
console.log('Records saved!');
|
||||
console.log('Data received:', data);
|
||||
Utils.consoleLogIfNotProductionEnvironment('Records saved!');
|
||||
Utils.consoleLogIfNotProductionEnvironment('Data received:', data);
|
||||
}
|
||||
this.callbackLoadTableContent(data);
|
||||
}
|
||||
else {
|
||||
if (_verbose) { console.log("error: ", data[flagMessage]); }
|
||||
Utils.consoleLogIfNotProductionEnvironment("error: ", data[flagMessage]);
|
||||
OverlayError.show(data[flagMessage]);
|
||||
}
|
||||
})
|
||||
@@ -236,7 +236,7 @@ export default class TableBasePage extends BasePage {
|
||||
cacheRowBlank() {
|
||||
let selectorRowNew = idTableMain + ' tbody tr.' + flagRowNew;
|
||||
let rowBlankTemp = document.querySelector(selectorRowNew);
|
||||
if (_verbose) { console.log("row blank temp: ", rowBlankTemp); }
|
||||
Utils.consoleLogIfNotProductionEnvironment("row blank temp: ", rowBlankTemp);
|
||||
let countRows = document.querySelectorAll(idTableMain + ' > tbody > tr').length;
|
||||
_rowBlank = rowBlankTemp.cloneNode(true);
|
||||
document.querySelectorAll(selectorRowNew).forEach(function(row) {
|
||||
@@ -257,23 +257,6 @@ export default class TableBasePage extends BasePage {
|
||||
}
|
||||
hookupSlidersDisplayOrderTable() {
|
||||
let selectorDisplayOrder = idTableMain + ' tbody tr td.' + flagDisplayOrder + ' input.' + flagSlider + '.' + flagDisplayOrder;
|
||||
/*
|
||||
Events.initialiseEventHandler(selectorDisplayOrder, flagInitialised, (sliderDisplayOrder) => {
|
||||
/*
|
||||
sliderDisplayOrder.setAttribute('draggable', true);
|
||||
sliderDisplayOrder.addEventListener('dragstart', this.handleDragSliderStart.bind(this), false);
|
||||
sliderDisplayOrder.addEventListener('dragenter', this.handleDragSliderEnter.bind(this), false);
|
||||
sliderDisplayOrder.addEventListener('dragover', this.handleDragSliderOver.bind(this), false);
|
||||
sliderDisplayOrder.addEventListener('dragleave', this.handleDragSliderLeave.bind(this), false);
|
||||
sliderDisplayOrder.addEventListener('drop', this.handleDropSlider.bind(this), false);
|
||||
sliderDisplayOrder.addEventListener('dragend', this.handleDragSliderEnd.bind(this), false);
|
||||
*
|
||||
sliderDisplayOrder.addEventListener('change', (event) => {
|
||||
console.log("slider change event");
|
||||
this.handleChangeNestedElementCellTable(sliderDisplayOrder);
|
||||
});
|
||||
});
|
||||
*/
|
||||
this.hookupChangeHandlerTableCells(selectorDisplayOrder);
|
||||
}
|
||||
hookupChangeHandlerTableCells(inputSelector, handler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
||||
@@ -283,7 +266,6 @@ export default class TableBasePage extends BasePage {
|
||||
});
|
||||
handler(null, input);
|
||||
});
|
||||
// this.hookupEventHandler("change", inputSelector, handler);
|
||||
}
|
||||
/*
|
||||
handleChangeElementCellTable(event, element) {
|
||||
@@ -339,15 +321,15 @@ export default class TableBasePage extends BasePage {
|
||||
let wasDirtyRowTable = DOM.hasDirtyChildrenContainer(rowTable);
|
||||
let wasDirtyElement = element.classList.contains(flagDirty);
|
||||
let isDirtyElement = DOM.updateAndCheckIsElementDirty(element);
|
||||
console.log({isDirtyElement, wasDirtyElement});
|
||||
Utils.consoleLogIfNotProductionEnvironment({isDirtyElement, wasDirtyElement});
|
||||
if (isDirtyElement != wasDirtyElement) {
|
||||
DOM.handleDirtyElement(td, isDirtyElement);
|
||||
let isNowDirtyRowSubtable = DOM.hasDirtyChildrenContainer(rowSubtable);
|
||||
console.log({isNowDirtyRowSubtable, wasDirtyRowSubtable});
|
||||
Utils.consoleLogIfNotProductionEnvironment({isNowDirtyRowSubtable, wasDirtyRowSubtable});
|
||||
if (isNowDirtyRowSubtable != wasDirtyRowSubtable) {
|
||||
DOM.handleDirtyElement(rowSubtable, isNowDirtyRowSubtable);
|
||||
let isNowDirtyRowTable = DOM.hasDirtyChildrenContainer(rowTable);
|
||||
console.log({isNowDirtyRowTable, wasDirtyRowTable});
|
||||
Utils.consoleLogIfNotProductionEnvironment({isNowDirtyRowTable, wasDirtyRowTable});
|
||||
if (isNowDirtyRowTable != wasDirtyRowTable) {
|
||||
DOM.handleDirtyElement(rowTable, isNowDirtyRowTable);
|
||||
let rows = this.getTableRecords(true);
|
||||
@@ -362,7 +344,7 @@ export default class TableBasePage extends BasePage {
|
||||
let wasDirtyParentRows = this.getAllIsDirtyRowsInParentTree(element);
|
||||
let wasDirtyElement = element.classList.contains(flagDirty);
|
||||
let isDirtyElement = DOM.updateAndCheckIsElementDirty(element);
|
||||
if (_verbose) { console.log({isDirtyElement, wasDirtyElement, wasDirtyParentRows}); }
|
||||
Utils.consoleLogIfNotProductionEnvironment({isDirtyElement, wasDirtyElement, wasDirtyParentRows});
|
||||
let td = DOM.getCellFromElement(element);
|
||||
DOM.setElementAttributeValueCurrent(td, DOM.getElementAttributeValueCurrent(element));
|
||||
if (isDirtyElement != wasDirtyElement) {
|
||||
@@ -392,7 +374,7 @@ export default class TableBasePage extends BasePage {
|
||||
let tr = DOM.getRowFromElement(td);
|
||||
let isDirtyRow = isDirtyTd || DOM.hasDirtyChildrenContainer(tr);
|
||||
let wasDirtyRow = wasDirtyParentRows.shift();
|
||||
if (_verbose) { console.log({isDirtyRow, wasDirtyRow}); }
|
||||
Utils.consoleLogIfNotProductionEnvironment({isDirtyRow, wasDirtyRow});
|
||||
if (isDirtyRow != wasDirtyRow) {
|
||||
DOM.handleDirtyElement(tr, isDirtyRow);
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
@@ -404,64 +386,6 @@ export default class TableBasePage extends BasePage {
|
||||
}) {
|
||||
this.hookupEventHandler("change", inputSelector, handler);
|
||||
}
|
||||
/* ToDo: Fix this slider drag and drop functionality
|
||||
handleDragSliderStart(event) {
|
||||
this.dragSrcEl = event.target;
|
||||
event.dataTransfer.effectAllowed = flagMove;
|
||||
/*
|
||||
console.log("setting outer html: ", this.dragSrcEl.outerHTML);
|
||||
event.dataTransfer.setData('text/html', this.dragSrcEl.outerHTML);
|
||||
*
|
||||
this.dragSrcRow = DOM.getRowFromElement(this.dragSrcEl);
|
||||
this.dragSrcEl.classList.add(flagDragging);
|
||||
}
|
||||
handleDragSliderOver(event) {
|
||||
if (event.preventDefault) {
|
||||
event.preventDefault();
|
||||
}
|
||||
event.dataTransfer.dropEffect = flagMove;
|
||||
return false;
|
||||
}
|
||||
handleDragSliderEnter(event) {
|
||||
event.target.closest('tr').classList.add(flagDragOver);
|
||||
}
|
||||
handleDragSliderLeave(event) {
|
||||
event.target.closest('tr').classList.remove(flagDragOver);
|
||||
}
|
||||
handleDropSlider(event) {
|
||||
event.stopPropagation();
|
||||
let targetRow = DOM.getRowFromElement(event.target);
|
||||
if (this.dragSourceRow != targetRow) {
|
||||
targetRow.classList.remove(flagDragOver);
|
||||
this.dragSrcEl.classList.remove(flagDragging);
|
||||
let sourceRowClone = this.dragSrcRow.cloneNode(true);
|
||||
let targetRowClone = targetRow.cloneNode(true);
|
||||
console.log("sourceRowClone: ", sourceRowClone);
|
||||
console.log("targetRowClone: ", targetRowClone);
|
||||
let tbody = targetRow.closest('tbody');
|
||||
tbody.replaceChild(sourceRowClone, targetRow);
|
||||
tbody.replaceChild(targetRowClone, this.dragSrcRow);
|
||||
this.refreshDisplayOrders();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
handleDragSliderEnd(event) {
|
||||
let table = TableBasePage.getTableMain();
|
||||
let rows = table.querySelectorAll('tr');
|
||||
rows.forEach(row => {
|
||||
row.classList.remove(flagDragOver);
|
||||
row.classList.remove(flagDragging);
|
||||
});
|
||||
}
|
||||
refreshDisplayOrders() {
|
||||
console.log("updating display order values");
|
||||
let rows = document.querySelectorAll(idTableMain + 'tbody tr.' + flagRow);
|
||||
rows.forEach((row, indexRow) => {
|
||||
sliderDisplayOrder = row.querySelector('td.' + flagDisplayOrder + ' .' + flagSlider);
|
||||
sliderDisplayOrder.setAttribute(attrValueCurrent, indexRow);
|
||||
});
|
||||
}
|
||||
*/
|
||||
hookupTextareasCodeTable() {
|
||||
this.hookupChangeHandlerTableCells(idTableMain + ' tbody tr td.' + flagCode + ' textarea');
|
||||
}
|
||||
@@ -475,7 +399,7 @@ export default class TableBasePage extends BasePage {
|
||||
let selectorButton = 'table' + (Validation.isEmpty(flagTable) ? '' : '.' + flagTable) + ' > tbody > tr > td.' + flagActive + ' button';
|
||||
let selectorButtonDelete = selectorButton + '.' + flagDelete;
|
||||
let selectorButtonUndelete = selectorButton + ':not(.' + flagDelete + ')';
|
||||
console.log("hookupFieldsActive: ", selectorButtonDelete, selectorButtonUndelete);
|
||||
Utils.consoleLogIfNotProductionEnvironment("hookupFieldsActive: ", selectorButtonDelete, selectorButtonUndelete);
|
||||
this.hookupButtonsRowDelete(selectorButtonDelete, selectorButtonUndelete);
|
||||
this.hookupButtonsRowUndelete(selectorButtonDelete, selectorButtonUndelete);
|
||||
this.hookupEventHandler(
|
||||
@@ -549,7 +473,6 @@ export default class TableBasePage extends BasePage {
|
||||
}
|
||||
handleClickTableCellDdlPreview(event, td, optionObjectList, cellSelector, ddlHookup = (cellSelector) => { this.hookupTableCellDdls(cellSelector); }) {
|
||||
if (td.querySelector('select')) return;
|
||||
// td.removeEventListener("click", ddlHookup);
|
||||
let tdNew = td.cloneNode(true);
|
||||
td.parentNode.replaceChild(tdNew, td);
|
||||
let idSelected = DOM.getElementAttributeValueCurrent(tdNew);
|
||||
@@ -558,8 +481,8 @@ export default class TableBasePage extends BasePage {
|
||||
DOM.setElementValuesCurrentAndPrevious(ddl, idSelected);
|
||||
let optionJson, option;
|
||||
if (_verbose) {
|
||||
console.log("click table cell ddl preview");
|
||||
console.log({optionObjectList, cellSelector});
|
||||
Utils.consoleLogIfNotProductionEnvironment("click table cell ddl preview");
|
||||
Utils.consoleLogIfNotProductionEnvironment({optionObjectList, cellSelector});
|
||||
}
|
||||
option = DOM.createOption(null);
|
||||
ddl.appendChild(option);
|
||||
@@ -572,34 +495,6 @@ export default class TableBasePage extends BasePage {
|
||||
let ddlSelector = cellSelector + ' select';
|
||||
ddlHookup(ddlSelector);
|
||||
}
|
||||
/*
|
||||
handleChangeTableCellDdl(event, ddl) {
|
||||
let row = DOM.getRowFromElement(ddl);
|
||||
let td = DOM.getCellFromElement(ddl);
|
||||
console.log("td: ", td);
|
||||
let wasDirtyRow = DOM.hasDirtyChildrenContainer(row);
|
||||
let wasDirtyElement = ddl.classList.contains(flagDirty);
|
||||
let isDirtyElement = DOM.updateAndCheckIsElementDirty(ddl);
|
||||
console.log("isDirtyElement: ", isDirtyElement);
|
||||
console.log("wasDirtyElement: ", wasDirtyElement);
|
||||
if (isDirtyElement != wasDirtyElement) {
|
||||
DOM.handleDirtyElement(td, isDirtyElement);
|
||||
let optionSelected = ddl.options[ddl.selectedIndex];
|
||||
DOM.setElementAttributeValueCurrent(td, optionSelected.value);
|
||||
let isNowDirtyRow = DOM.hasDirtyChildrenContainer(row);
|
||||
console.log("isNowDirtyRow: ", isNowDirtyRow);
|
||||
console.log("wasDirtyRow: ", wasDirtyRow);
|
||||
if (isNowDirtyRow != wasDirtyRow) {
|
||||
DOM.handleDirtyElement(row, isNowDirtyRow);
|
||||
let rows = this.getTableRecords(true);
|
||||
let existsDirtyRecord = rows.length > 0;
|
||||
console.log("dirty records:", rows);
|
||||
console.log("existsDirtyRecord:", existsDirtyRecord);
|
||||
this.toggleShowButtonsSaveCancel(existsDirtyRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
hookupTableCellDDlPreviewsWhenNotCollapsed(cellSelector, optionList, ddlHookup = (event, element) => { this.hookupTableCellDdls(event, element); }) {
|
||||
this.hookupEventHandler("click", cellSelector, (event, td) => {
|
||||
let div = td.querySelector('div');
|
||||
@@ -607,299 +502,13 @@ export default class TableBasePage extends BasePage {
|
||||
this.handleClickTableCellDdlPreview(event, td, optionList, cellSelector, (event, element) => { ddlHookup(event, element); });
|
||||
});
|
||||
}
|
||||
hookupProductCategoryDdls(ddlSelector) {
|
||||
this.hookupChangeHandlerTableCells(ddlSelector, (event, element) => { this.handleChangeProductCategoryDdl(event, element); });
|
||||
}
|
||||
handleChangeProductCategoryDdl(event, ddlCategory) {
|
||||
this.handleChangeNestedElementCellTable(event, ddlCategory);
|
||||
let idProductCategorySelected = DOM.getElementAttributeValueCurrent(ddlCategory);
|
||||
let row = DOM.getRowFromElement(ddlCategory);
|
||||
let tdProduct = row.querySelector('td.' + flagProduct);
|
||||
tdProduct.dispatchEvent(new Event('click'));
|
||||
let ddlProduct = row.querySelector('td.' + flagProduct + ' select');
|
||||
ddlProduct.innerHTML = '';
|
||||
ddlProduct.appendChild(DOM.createOption(null));
|
||||
let optionJson, option;
|
||||
Utils.getListFromDict(products).forEach((product) => {
|
||||
if (idProductCategorySelected != '0' && product[attrIdProductCategory] != idProductCategorySelected) return;
|
||||
optionJson = BusinessObjects.getOptionJsonFromObjectJson(product);
|
||||
option = DOM.createOption(optionJson);
|
||||
ddlProduct.appendChild(option);
|
||||
});
|
||||
this.handleChangeNestedElementCellTable(event, ddlProduct);
|
||||
}
|
||||
hookupFieldsProductPermutationVariation() {
|
||||
this.hookupPreviewsProductPermutationVariation();
|
||||
this.hookupDdlsProductPermutationVariationType();
|
||||
this.hookupDdlsProductPermutationVariation();
|
||||
this.hookupButtonsProductPermutationVariationAddDelete();
|
||||
}
|
||||
hookupPreviewsProductPermutationVariation() {
|
||||
this.hookupEventHandler("click", idTableMain + ' td.' + flagProductVariations, (event, element) => this.handleClickProductPermutationVariationsPreview(event, element));
|
||||
}
|
||||
handleClickProductPermutationVariationsPreview(event, element) {
|
||||
let tblVariations = element.querySelector('table.' + flagProductVariations);
|
||||
if (!Validation.isEmpty(tblVariations)) return;
|
||||
this.toggleColumnCollapsed(flagProductVariations, false);
|
||||
let permutationVariations = this.getElementProductVariations(element);
|
||||
tblVariations = document.createElement("table");
|
||||
tblVariations.classList.add(flagProductVariations);
|
||||
let thead = document.createElement("thead");
|
||||
let tr = document.createElement("tr");
|
||||
let thVariationType = document.createElement("th");
|
||||
thVariationType.classList.add(flagProductVariationType);
|
||||
thVariationType.textContent = 'Type';
|
||||
let thNameVariation = document.createElement("th");
|
||||
thNameVariation.classList.add(flagProductVariation);
|
||||
thNameVariation.textContent = 'Name';
|
||||
let buttonAdd = document.createElement("button");
|
||||
buttonAdd.classList.add(flagAdd);
|
||||
buttonAdd.textContent = '+';
|
||||
let thAddDelete = document.createElement("th");
|
||||
thAddDelete.classList.add(flagAdd);
|
||||
thAddDelete.appendChild(buttonAdd);
|
||||
tr.appendChild(thVariationType);
|
||||
tr.appendChild(thNameVariation);
|
||||
tr.appendChild(thAddDelete);
|
||||
thead.appendChild(tr);
|
||||
tblVariations.appendChild(thead);
|
||||
let tbody = document.createElement("tbody");
|
||||
if (!Validation.isEmpty(permutationVariations)) {
|
||||
permutationVariations.forEach((permutationVariation, index) => {
|
||||
this.addProductPermutationVariationRow(tbody, permutationVariation);
|
||||
});
|
||||
}
|
||||
tblVariations.appendChild(tbody);
|
||||
if (_verbose) {
|
||||
console.log("click product permutation variations preview");
|
||||
console.log('variations:', permutationVariations);
|
||||
console.log("tblVariations: ", tblVariations);
|
||||
}
|
||||
|
||||
let cellParent = element.closest(idTableMain + ' tbody tr td.' + flagProductVariations);
|
||||
cellParent.innerHTML = '';
|
||||
cellParent.appendChild(tblVariations);
|
||||
|
||||
this.hookupFieldsProductPermutationVariation();
|
||||
}
|
||||
toggleColumnCollapsed(flagColumn, isCollapsed) {
|
||||
this.toggleColumnHasClassnameFlag(flagColumn, isCollapsed, flagCollapsed);
|
||||
}
|
||||
toggleColumnHeaderCollapsed(flagColumn, isCollapsed) {
|
||||
this.toggleColumnHasClassnameFlag(flagColumn, isCollapsed, flagCollapsed);
|
||||
}
|
||||
getElementProductVariations(element) {
|
||||
let permutationVariations = element.getAttribute(attrValueCurrent);
|
||||
let objVariations = [];
|
||||
let parts, new_variation, new_variation_type;
|
||||
if (!Validation.isEmpty(permutationVariations)) {
|
||||
permutationVariations = permutationVariations.split(',');
|
||||
permutationVariations.forEach((variation) => {
|
||||
parts = variation.split(':');
|
||||
if (parts.length == 2) {
|
||||
if (_verbose) { console.log("parts: ", parts); }
|
||||
new_variation_type = productVariationTypes[parts[0].trim()];
|
||||
new_variation = productVariations[parts[1].trim()];
|
||||
objVariations.push({
|
||||
[flagProductVariationType]: new_variation_type,
|
||||
[flagProductVariation]: new_variation,
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (_verbose) { console.log("error: invalid variation: ", variation); }
|
||||
}
|
||||
});
|
||||
}
|
||||
return objVariations;
|
||||
}
|
||||
static createOptionUnselectedProductVariation() {
|
||||
return {
|
||||
[flagProductVariationType]: {
|
||||
[flagNameAttrOptionText]: [flagName],
|
||||
[flagNameAttrOptionValue]: [attrIdProductVariationType],
|
||||
[flagName]: 'Select Variation Type',
|
||||
[attrIdProductVariationType]: 0,
|
||||
},
|
||||
[flagProductVariation]: {
|
||||
[flagNameAttrOptionText]: [flagName],
|
||||
[flagNameAttrOptionValue]: [attrIdProductVariation],
|
||||
[flagName]: 'Select Variation',
|
||||
[attrIdProductVariation]: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
addProductPermutationVariationRow(tbody, permutationVariation) {
|
||||
if (_verbose) { console.log("permutationVariation: ", permutationVariation); }
|
||||
let productVariationType, optionProductVariationTypeJson, optionProductVariationType, productVariation, optionProductVariationJson, optionProductVariation;
|
||||
/*
|
||||
if (Validation.isEmpty(variations)) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
let productVariationKeys = Object.keys(productVariations);
|
||||
let productVariationTypeKeys = Object.keys(productVariationTypes);
|
||||
|
||||
let ddlsProductVariationType = tbody.querySelectorAll('select.' + flagProductVariationType);
|
||||
let productVariationTypeKeysSelected = new Set();
|
||||
let valueSelected;
|
||||
let doFilterProductVariationKeys = permutationVariation[attrIdProductVariationType] != 0;
|
||||
ddlsProductVariationType.forEach((ddlProductVariationType) => {
|
||||
valueSelected = DOM.getElementValueCurrent(ddlProductVariationType);
|
||||
productVariationTypeKeysSelected.add(valueSelected);
|
||||
});
|
||||
productVariationTypeKeys = productVariationTypeKeys.filter(typeKey => !productVariationTypeKeysSelected.has(typeKey));
|
||||
if (productVariationTypeKeys.length == 0) return;
|
||||
if (doFilterProductVariationKeys) {
|
||||
productVariationKeys = productVariationKeys.filter(variationKey => !productVariationTypeKeysSelected.has(productVariations[variationKey][attrIdProductVariationType]));
|
||||
}
|
||||
|
||||
let permutationVariationJson = permutationVariation[flagProductVariation];
|
||||
let permutationVariationTypeJson = permutationVariation[flagProductVariationType];
|
||||
|
||||
let tdVariationType = document.createElement("td");
|
||||
tdVariationType.classList.add(flagProductVariationType);
|
||||
DOM.setElementAttributesValuesCurrentAndPrevious(tdVariationType, permutationVariationTypeJson[attrIdProductVariationType]);
|
||||
|
||||
let ddlVariationType = document.createElement("select");
|
||||
ddlVariationType.classList.add(flagProductVariationType);
|
||||
DOM.setElementAttributesValuesCurrentAndPrevious(ddlVariationType, permutationVariationTypeJson[attrIdProductVariationType]);
|
||||
|
||||
optionProductVariationType = DOM.createOption(null);
|
||||
if (_verbose) { console.log("optionProductVariationType: ", optionProductVariationType); }
|
||||
ddlVariationType.appendChild(optionProductVariationType);
|
||||
|
||||
productVariationTypeKeys.forEach((productVariationTypeKey) => {
|
||||
/*
|
||||
optionProductVariationType = document.createElement('option');
|
||||
optionProductVariationType.value = optionVariationType.value;
|
||||
optionProductVariationType.text = optionVariationType.text;
|
||||
*/
|
||||
productVariationType = productVariationTypes[productVariationTypeKey];
|
||||
optionProductVariationTypeJson = BusinessObjects.getOptionJsonFromObjectJson(productVariationType, permutationVariationTypeJson[attrIdProductVariationType]);
|
||||
optionProductVariationType = DOM.createOption(optionProductVariationTypeJson);
|
||||
if (_verbose) { console.log("optionProductVariationType: ", optionProductVariationType); }
|
||||
ddlVariationType.appendChild(optionProductVariationType);
|
||||
});
|
||||
|
||||
let tdVariation = document.createElement("td");
|
||||
tdVariation.classList.add(flagProductVariation);
|
||||
DOM.setElementAttributesValuesCurrentAndPrevious(tdVariation, permutationVariationJson[attrIdProductVariation]);
|
||||
|
||||
let ddlVariation = document.createElement("select");
|
||||
ddlVariation.classList.add(flagProductVariation);
|
||||
DOM.setElementAttributesValuesCurrentAndPrevious(ddlVariation, permutationVariationJson[attrIdProductVariation]);
|
||||
|
||||
optionProductVariation = DOM.createOption(null);
|
||||
if (_verbose) { console.log("optionProductVariation: ", optionProductVariation); }
|
||||
ddlVariation.appendChild(optionProductVariation);
|
||||
|
||||
productVariationKeys.forEach((productVariationKey) => {
|
||||
productVariation = productVariations[productVariationKey];
|
||||
optionProductVariationJson = BusinessObjects.getOptionJsonFromObjectJson(productVariation, permutationVariationJson[attrIdProductVariation]);
|
||||
optionProductVariation = DOM.createOption(optionProductVariationJson);
|
||||
if (_verbose) { console.log("optionProductVariation: ", optionProductVariation); }
|
||||
ddlVariation.appendChild(optionProductVariation);
|
||||
});
|
||||
|
||||
let tdDelete = document.createElement("td");
|
||||
tdDelete.classList.add(flagDelete);
|
||||
|
||||
let buttonDelete = document.createElement("button");
|
||||
buttonDelete.classList.add(flagActive);
|
||||
buttonDelete.classList.add(flagDelete);
|
||||
buttonDelete.textContent = 'x';
|
||||
DOM.setElementAttributesValuesCurrentAndPrevious(buttonDelete, true);
|
||||
|
||||
let tr = document.createElement("tr");
|
||||
tr.classList.add(flagProductVariation);
|
||||
tdVariationType.appendChild(ddlVariationType);
|
||||
tr.appendChild(tdVariationType);
|
||||
tdVariation.appendChild(ddlVariation);
|
||||
tr.appendChild(tdVariation);
|
||||
tdDelete.appendChild(buttonDelete);
|
||||
tr.appendChild(tdDelete);
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
hookupDdlsProductPermutationVariationType() {
|
||||
this.hookupTableCellDdls(
|
||||
idTableMain + ' td.' + flagProductVariations + ' td.' + flagProductVariationType + ' select'
|
||||
, (event, ddlVariationType) => {
|
||||
this.handleChangeProductVariationInput(event, ddlVariationType);
|
||||
let idVariationTypeSelected = DOM.getElementValueCurrent(ddlVariationType);
|
||||
let row = DOM.getRowFromElement(ddlVariationType);
|
||||
let tdVariation = row.querySelector('td.' + flagProductVariation);
|
||||
tdVariation.dispatchEvent(new Event('click'));
|
||||
let ddlVariation = row.querySelector('td.' + flagProductVariation + ' select');
|
||||
ddlVariation.innerHTML = '';
|
||||
ddlVariation.appendChild(DOM.createOption(null));
|
||||
let optionJson, option;
|
||||
let variationType = productVariationTypes[idVariationTypeSelected];
|
||||
if (variationType == null) variationType = {
|
||||
[flagProductVariations]: [],
|
||||
};
|
||||
variationType[flagProductVariations].forEach((variation) => {
|
||||
optionJson = BusinessObjects.getOptionJsonFromObjectJson(variation);
|
||||
option = DOM.createOption(optionJson);
|
||||
ddlVariation.appendChild(option);
|
||||
});
|
||||
this.handleChangeProductVariationInput(event, ddlVariation);
|
||||
}
|
||||
);
|
||||
}
|
||||
handleChangeProductVariationInput(event, element) {
|
||||
this.handleChangeNestedElementCellTable(event, element);
|
||||
this.updateProductPermutationVariations(element);
|
||||
}
|
||||
hookupDdlsProductPermutationVariation() {
|
||||
this.hookupTableCellDdls(idTableMain + ' td.' + flagProductVariations + ' td.' + flagProductVariation + ' select', (event, ddlVariation) => { this.handleChangeProductVariationInput(event, ddlVariation); });
|
||||
}
|
||||
hookupButtonsProductPermutationVariationAddDelete() {
|
||||
let selectorButton = idTableMain + ' td.' + flagProductVariations + ' tr.' + flagProductVariation + ' button';
|
||||
let selectorButtonDelete = selectorButton + '.' + flagDelete;
|
||||
let selectorButtonUndelete = selectorButton + '.' + flagAdd;
|
||||
this.hookupButtonsRowDelete(selectorButtonDelete, selectorButtonUndelete, (event, element) => { this.handleChangeProductVariationInput(event, element); });
|
||||
this.hookupButtonsRowUndelete(selectorButtonDelete, selectorButtonUndelete, (event, element) => { this.handleChangeProductVariationInput(event, element); });
|
||||
this.hookupButtonsProductPermutationVariationAdd();
|
||||
}
|
||||
hookupButtonsProductPermutationVariationAdd() {
|
||||
this.hookupEventHandler(
|
||||
"click"
|
||||
, idTableMain + ' td.' + flagProductVariations + ' button.' + flagAdd
|
||||
, (event, element) => { this.handleClickButtonProductPermutationVariationAdd(event, element); }
|
||||
);
|
||||
}
|
||||
handleClickButtonProductPermutationVariationAdd(event, element) {
|
||||
let variationsCell = element.closest('td.' + flagProductVariations);
|
||||
let tbody = variationsCell.querySelector('tbody');
|
||||
let permutationVariation = TableBasePage.createOptionUnselectedProductVariation();
|
||||
this.addProductPermutationVariationRow(tbody, permutationVariation);
|
||||
this.hookupFieldsProductPermutationVariation();
|
||||
}
|
||||
updateProductPermutationVariations(element) {
|
||||
let variationsCell = element.closest('td.' + flagProductVariations);
|
||||
let variationPairsString = this.getProductPermutationVariationsText(variationsCell);
|
||||
DOM.setElementAttributeValueCurrent(variationsCell, variationPairsString);
|
||||
this.handleChangeNestedElementCellTable(null, variationsCell);
|
||||
}
|
||||
getProductPermutationVariationsText(variationsTd) {
|
||||
let rows = variationsTd.querySelectorAll(':scope tbody tr:has(button.' + flagDelete + ')');
|
||||
let variationPairsString = '';
|
||||
let ddlVariationType, ddlVariation, idVariationType, idVariation;
|
||||
rows.forEach((row, index) => {
|
||||
ddlVariationType = row.querySelector(':scope td select.' + flagProductVariationType);
|
||||
ddlVariation = row.querySelector(':scope td select.' + flagProductVariation);
|
||||
idVariationType = DOM.getElementValueCurrent(ddlVariationType);
|
||||
idVariation = DOM.getElementValueCurrent(ddlVariation);
|
||||
if (variationPairsString != '') variationPairsString += ',';
|
||||
variationPairsString += idVariationType + ':' + idVariation;
|
||||
});
|
||||
return variationPairsString;
|
||||
}
|
||||
|
||||
hookupCurrencyFields() {
|
||||
this.hookupTableCellDdlPreviews(idTableMain + ' td.' + flagCurrency, Utils.getListFromDict(currencies));
|
||||
}
|
||||
|
||||
createTdActive(isActive) {
|
||||
let tdActive = document.createElement("td");
|
||||
tdActive.classList.add(flagActive);
|
||||
@@ -921,7 +530,6 @@ export default class TableBasePage extends BasePage {
|
||||
let dataPage = {};
|
||||
dataPage[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
this.setLocalStoragePage(dataPage);
|
||||
// _rowBlank = null;
|
||||
}
|
||||
|
||||
toggleColumnHasClassnameFlag(columnFlag, isRequiredFlag, classnameFlag) {
|
||||
@@ -930,12 +538,6 @@ export default class TableBasePage extends BasePage {
|
||||
let columnThHasFlag = columnTh.classList.contains(classnameFlag);
|
||||
if (isRequiredFlag == columnThHasFlag) return;
|
||||
DOM.toggleElementHasClassnameFlag(columnTh, isRequiredFlag, classnameFlag);
|
||||
/*
|
||||
let columnTds = table.querySelectorAll('td.' + columnFlag);
|
||||
columnTds.forEach((columnTd) => {
|
||||
DOM.toggleElementHasClassnameFlag(columnTd, isRequiredFlag, classnameFlag);
|
||||
});
|
||||
*/
|
||||
}
|
||||
toggleColumnHeaderHasClassnameFlag(columnFlag, isRequiredFlag, classnameFlag) {
|
||||
let table = TableBasePage.getTableMain();
|
||||
@@ -949,26 +551,3 @@ export default class TableBasePage extends BasePage {
|
||||
this.toggleShowButtonsSaveCancel(existsDirtyRecord);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Example of a subclass of TableBasePage
|
||||
import { TableBasePage } from "./page_table_base.js";
|
||||
import API from "../api.js";
|
||||
import DOM from "../dom.js";
|
||||
|
||||
export class PageStoreProductCategories extends TableBasePage {
|
||||
static hash = hashPageStoreProductCategories;
|
||||
static attrIdRowObject = attrIdProductCategory;
|
||||
callSaveTableContent = API.saveCategories;
|
||||
|
||||
constructor() {}
|
||||
initialize() {}
|
||||
hookupFilters() {}
|
||||
loadRowTable(rowJson) {}
|
||||
getJsonRow(row) {}
|
||||
initialiseRowNew(tbody, row) {}
|
||||
hookupTableMain() {}
|
||||
isDirtyRow(row) {}
|
||||
leave() {}
|
||||
}
|
||||
*/
|
||||
16
static/js/pages/core/contact-success.js
Normal file
16
static/js/pages/core/contact-success.js
Normal file
@@ -0,0 +1,16 @@
|
||||
// internal
|
||||
import BasePage from "../base.js";
|
||||
// vendor
|
||||
import { Altcha } from "../../vendor/altcha.js";
|
||||
|
||||
export default class PageContactSuccess extends BasePage {
|
||||
static hash = hashPageContactSuccess;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,17 @@
|
||||
// Core
|
||||
import PageHome from './pages/core/home.js';
|
||||
import PageContact from './pages/core/contact.js';
|
||||
import PageContactSuccess from './pages/core/contact-success.js';
|
||||
// Legal
|
||||
import PageAccessibilityReport from './pages/legal/accessibility_report.js';
|
||||
import PageAccessibilityStatement from './pages/legal/accessibility_statement.js';
|
||||
import PageLicense from './pages/legal/license.js';
|
||||
// User
|
||||
// import PageUserLogin from './pages/user/login.js';
|
||||
// import PageUserLogout from './pages/user/logout.js';
|
||||
// import PageUserAccount from './pages/user/account.js';
|
||||
import PagePrivacyPolicy from './pages/legal/privacy_policy.js';
|
||||
import PageRetentionSchedule from './pages/legal/retention_schedule.js';
|
||||
|
||||
import API from './api.js';
|
||||
import DOM from './dom.js';
|
||||
import PagePrivacyPolicy from './pages/legal/privacy_policy.js';
|
||||
import PageRetentionSchedule from './pages/legal/retention_schedule.js';
|
||||
import Utils from './lib/utils.js';
|
||||
|
||||
|
||||
export default class Router {
|
||||
@@ -23,18 +21,14 @@ export default class Router {
|
||||
// Pages
|
||||
this.pages = {};
|
||||
// Core
|
||||
this.pages[hashPageHome] = { name: 'PageHome', module: PageHome }; // importModule: () => import(/* webpackChunkName: "page_core_home" */ './pages/core/home.js') , pathModule: './pages/core/home.js'
|
||||
this.pages[hashPageContact] = { name: 'PageContact', module: PageContact }; // pathModule: './pages/core/contact.js' };
|
||||
this.pages[hashPageHome] = { name: 'PageHome', module: PageHome };
|
||||
this.pages[hashPageContact] = { name: 'PageContact', module: PageContact };
|
||||
this.pages[hashPageContactSuccess] = { name: 'PageContact', module: PageContactSuccess };
|
||||
// Legal
|
||||
this.pages[hashPageAccessibilityStatement] = { name: 'PageAccessibilityStatement', module: PageAccessibilityStatement }; // pathModule: '../../static/js/pages/legal/accessibility_statement.js' }; // , page: PageAccessibilityStatement
|
||||
this.pages[hashPageDataRetentionSchedule] = { name: 'PageDataRetentionSchedule', module: PageRetentionSchedule }; // pathModule: './pages/legal/data_retention_schedule.js' };
|
||||
this.pages[hashPageLicense] = { name: 'PageLicense', module: PageLicense }; // pathModule: './pages/legal/license.js' };
|
||||
this.pages[hashPagePrivacyPolicy] = { name: 'PagePrivacyPolicy', module: PagePrivacyPolicy }; // pathModule: './pages/legal/privacy_policy.js' }; // importModule: () => {return import(/* webpackChunkName: "page_privacy_policy" */ './pages/legal/privacy_policy.js'); }
|
||||
// User
|
||||
// this.pages[hashPageUserLogin] = { name: 'PageUserLogin', module: PageUserLogin }; // pathModule: './pages/user/login.js' };
|
||||
// this.pages[hashPageUserLogout] = { name: 'PageUserLogout', module: PageUserLogout }; // pathModule: './pages/user/logout.js' };
|
||||
// this.pages[hashPageUserAccount] = { name: 'PageUserAccount', module: PageUserAccount }; // pathModule: './pages/user/account.js' };
|
||||
|
||||
this.pages[hashPageAccessibilityStatement] = { name: 'PageAccessibilityStatement', module: PageAccessibilityStatement };
|
||||
this.pages[hashPageDataRetentionSchedule] = { name: 'PageDataRetentionSchedule', module: PageRetentionSchedule };
|
||||
this.pages[hashPageLicense] = { name: 'PageLicense', module: PageLicense };
|
||||
this.pages[hashPagePrivacyPolicy] = { name: 'PagePrivacyPolicy', module: PagePrivacyPolicy };
|
||||
// Routes
|
||||
this.routes = {};
|
||||
// Core
|
||||
@@ -45,10 +39,6 @@ export default class Router {
|
||||
this.routes[hashPageDataRetentionSchedule] = (isPopState = false) => this.navigateToHash(hashPageDataRetentionSchedule, isPopState);
|
||||
this.routes[hashPageLicense] = (isPopState = false) => this.navigateToHash(hashPageLicense, isPopState);
|
||||
this.routes[hashPagePrivacyPolicy] = (isPopState = false) => this.navigateToHash(hashPagePrivacyPolicy, isPopState);
|
||||
// User
|
||||
// this.routes[hashPageUserLogin] = (isPopState = false) => this.navigateToHash(hashPageUserLogin, isPopState);
|
||||
// this.routes[hashPageUserLogout] = (isPopState = false) => this.navigateToHash(hashPageUserLogout, isPopState);
|
||||
// this.routes[hashPageUserAccount] = (isPopState = false) => this.navigateToHash(hashPageUserAccount, isPopState);
|
||||
this.initialize();
|
||||
}
|
||||
loadPage(hashPage, isPopState = false) {
|
||||
@@ -61,31 +51,17 @@ export default class Router {
|
||||
|
||||
let pageJson = this.pages[hashPage];
|
||||
try {
|
||||
/*
|
||||
const module = await pagesContext(pageJson.pathModule);
|
||||
console.log("module: ", module);
|
||||
return module[pageJson.name];
|
||||
*/
|
||||
// const module = await import(pageJson.pathModule); // pageJson.page;
|
||||
// const module = () => import(pageJson.pathModule);
|
||||
const module = pageJson.module; // importModule;
|
||||
return module; // [pageJson.name];
|
||||
const module = pageJson.module;
|
||||
return module;
|
||||
}
|
||||
catch (error) {
|
||||
if (_verbose) { console.log("this.pages: ", this.pages); };
|
||||
Utils.consoleLogIfNotProductionEnvironment("this.pages: ", this.pages);
|
||||
console.error('Page not found:', hashPage);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
initialize() {
|
||||
/*
|
||||
let pages = Router.getPages();
|
||||
for (const key of Object.keys(pages)) {
|
||||
let page = pages[key];
|
||||
this.addRoute(page.hash, page.initialize);
|
||||
}
|
||||
*/
|
||||
window.addEventListener('popstate', this.handlePopState.bind(this)); // page accessed by history navigation
|
||||
window.addEventListener('popstate', this.handlePopState.bind(this));
|
||||
}
|
||||
handlePopState(event) {
|
||||
this.loadPageCurrent();
|
||||
@@ -95,26 +71,11 @@ export default class Router {
|
||||
this.loadPage(hashPageCurrent);
|
||||
}
|
||||
navigateToHash(hash, data = null, params = null, isPopState = false) {
|
||||
// this.beforeLeave();
|
||||
/*
|
||||
if (this.routes[hash]) {
|
||||
this.routes[hash](isPopState);
|
||||
} else {
|
||||
console.error(`Hash ${hash} not found`);
|
||||
}
|
||||
*/
|
||||
let url = API.getUrlFromHash(hash, params);
|
||||
// if (!isPopState)
|
||||
history.pushState({data: data, params: params}, '', hash);
|
||||
API.goToUrl(url, data);
|
||||
}
|
||||
/* beforeunload listener
|
||||
async beforeLeave() {
|
||||
const ClassPageCurrent = await this.getClassPageFromHash(DOM.getHashPageCurrent());
|
||||
const pageCurrent = new ClassPageCurrent(this);
|
||||
pageCurrent.leave();
|
||||
}
|
||||
*/
|
||||
|
||||
navigateToUrl(url, data = null, appendHistory = true) {
|
||||
// this.beforeLeave();
|
||||
if (appendHistory) history.pushState(data, '', url);
|
||||
@@ -128,25 +89,3 @@ export default class Router {
|
||||
}
|
||||
|
||||
export const router = new Router();
|
||||
|
||||
/*
|
||||
router.addRoute('/', () => {
|
||||
console.log('Home page');
|
||||
// Load home page content
|
||||
});
|
||||
|
||||
router.addRoute('/about', () => {
|
||||
console.log('About page');
|
||||
// Load about page content
|
||||
});
|
||||
|
||||
export function setupNavigationEvents() {
|
||||
document.querySelectorAll('a[data-nav]').forEach(link => {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
const url = e.target.getAttribute('href');
|
||||
router.navigateToUrl(url);
|
||||
});
|
||||
});
|
||||
}
|
||||
*/
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
|
||||
{% set block_id = 'styles' %}
|
||||
{% include 'layouts/_shared_store.html' %}
|
||||
<!-- Include Stylesheet -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/store.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/store/home.css') }}">
|
||||
|
||||
<!-- HTML content -->
|
||||
<div class="model.FLAG_ROW">
|
||||
<div class="leftcolumn">
|
||||
{% for cat in model.category_list.categories %}
|
||||
{% if cat.is_available() %}
|
||||
{% include 'components/store/_product_category.html' %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div id="{{ model.ID_BASKET_CONTAINER}}" class="rightcolumn">
|
||||
{% include 'components/store/_basket.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% set block_id = 'scripts' %}
|
||||
{% include 'layouts/_shared_store.html' %}
|
||||
<!-- Include JavaScript -->
|
||||
<script src="{{ url_for('routes_store.scripts_section_store') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/store/home.js') }}"></script>
|
||||
|
||||
<script>
|
||||
{#
|
||||
var hashPageCurrent = "{{ model.HASH_PAGE_STORE_HOME }}";
|
||||
#}
|
||||
</script>
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or model.currencies | length == 0 or currency is not defined or currency is none) %}
|
||||
{% if not _is_blank_row %}
|
||||
<div
|
||||
class="{{ model.FLAG_CURRENCY }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ currency.id_currency }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ currency.id_currency }}"
|
||||
>{{ currency.symbol }}</div>
|
||||
{% else %}
|
||||
<div
|
||||
class="{{ model.FLAG_CURRENCY }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}=""
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
{% if not is_blank_row %}
|
||||
<div
|
||||
class="{{ model.FLAG_PRODUCT }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ product.id_product }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ product.id_product }}"
|
||||
>{{ product.name }}</div>
|
||||
{% else %}
|
||||
<select class="{{ model.FLAG_PRODUCT }}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}="0">
|
||||
{% include 'components/common/inputs/_option_blank.html' %}
|
||||
{% for product in model.category_list_filters.categories[0].products %}
|
||||
<option value="{{ product.id_product }}">{{ product.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% endif %}
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
{% if not is_blank_row %}
|
||||
<div
|
||||
class="{{ model.FLAG_PRODUCT_CATEGORY }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ category.id_category }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ category.id_category }}"
|
||||
>{{ category.name }}</div>
|
||||
{% else %}
|
||||
<select class="{{ model.FLAG_PRODUCT_CATEGORY}}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}="0">
|
||||
{% include 'components/common/inputs/_option_blank.html' %}
|
||||
{% for cat in model.category_list_filters.categories %}
|
||||
<option value="{{ cat.id_category }}">{{ cat.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% endif %}
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or units_measurement_time_dict | length == 0 or permutation.id_unit_measurement_interval_expiration_unsealed is none) %}
|
||||
{% if not _is_blank_row %}
|
||||
{% set interval_recurrence = units_measurement_time_dict[permutation.id_unit_measurement_interval_expiration_unsealed] %}
|
||||
<div
|
||||
class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED }} {% if not permutation.does_expire_faster_once_unsealed %}{{ model.FLAG_COLLAPSED }}{% endif %}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_unit_measurement_interval_expiration_unsealed }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_unit_measurement_interval_expiration_unsealed }}"
|
||||
>{{ interval_recurrence.name_singular }}</div>
|
||||
{% else %}
|
||||
<div
|
||||
class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED }} {{ model.FLAG_COLLAPSED }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}=""
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,19 +0,0 @@
|
||||
{#
|
||||
<select class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }}" value="{{ permutation.id_unit_measurement_interval_recurrence }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_unit_measurement_interval_recurrence }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_unit_measurement_interval_recurrence }}"></select>
|
||||
#}
|
||||
{% with _is_blank_row = (is_blank_row or units_measurement_time | length == 0 or permutation.id_unit_measurement_interval_recurrence is none) %}
|
||||
{% if not _is_blank_row %}
|
||||
{% set interval_recurrence = units_measurement_time[permutation.id_unit_measurement_interval_recurrence] | console_log %}
|
||||
<div
|
||||
class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }} {% if not permutation.is_subscription %}{{ model.FLAG_COLLAPSED }}{% endif %}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_unit_measurement_interval_recurrence }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_unit_measurement_interval_recurrence }}"
|
||||
>{{ interval_recurrence.name_singular }}</div>
|
||||
{% else %}
|
||||
<div
|
||||
class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }} {{ model.FLAG_COLLAPSED }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}=""
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
{#
|
||||
<select class="{{ model.FLAG_UNIT_MEASUREMENT_QUANTITY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_unit_measurement_quantity }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_unit_measurement_quantity }}"></select>
|
||||
#}
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or units_measurement_dict | length == 0 or permutation.id_unit_measurement_quantity is none) %}
|
||||
{% if not _is_blank_row %}
|
||||
{% set interval_recurrence = units_measurement_dict[permutation.id_unit_measurement_quantity] | console_log %}
|
||||
<div
|
||||
class="{{ model.FLAG_UNIT_MEASUREMENT_QUANTITY }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_unit_measurement_quantity }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_unit_measurement_quantity }}"
|
||||
>{{ interval_recurrence.name_singular }}</div>
|
||||
{% else %}
|
||||
<div
|
||||
class="{{ model.FLAG_UNIT_MEASUREMENT_QUANTITY }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}=""
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or storage_location is not defined or storage_location is none or is_blank_row is not defined) %}
|
||||
{% if not _is_blank_row %}
|
||||
{% set name = storage_location.get_full_name() %}
|
||||
<div
|
||||
class="{{ model.FLAG_STORAGE_LOCATION }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ name }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ name }}"
|
||||
>{{ name }}</div>
|
||||
{% else %}
|
||||
<div class="{{ model.FLAG_STORAGE_LOCATION }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or model.suppliers | length == 0 or supplier is not defined or supplier is none) %}
|
||||
{% if not _is_blank_row %}
|
||||
<div
|
||||
class="{{ model.FLAG_SUPPLIER }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ supplier.id_supplier }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.id_supplier }}"
|
||||
>{{ supplier.name_company }}</div>
|
||||
{% else %}
|
||||
<div
|
||||
class="{{ model.FLAG_SUPPLIER }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}=""
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or address is not defined or address is none or is_blank_row is not defined) %}
|
||||
{% if not _is_blank_row %}
|
||||
{% set json_str = address.to_json_str() %}
|
||||
<div
|
||||
class="{{ model.FLAG_ADDRESS }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ json_str }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ json_str }}"
|
||||
>{{ address.postcode }}</div>
|
||||
{% else %}
|
||||
<div class="{{ model.FLAG_ADDRESS }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or order_items is not defined or order_items is none or is_blank_row is not defined) %}
|
||||
{% if not _is_blank_row %}
|
||||
{% set str_items = model.convert_list_objects_to_preview_str(order_items) %}
|
||||
<div
|
||||
class="{{ model.FLAG_ITEMS }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ json_str_items }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ json_str_items }}"
|
||||
>{{ str_items }}</div>
|
||||
{% else %}
|
||||
<div class="{{ model.FLAG_ITEMS }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or order_items is not defined or order_items is none or is_blank_row is not defined) %}
|
||||
{% if not _is_blank_row %}
|
||||
{% set str_items = model.convert_list_objects_to_preview_str(order_items) %}
|
||||
<div
|
||||
class="{{ model.FLAG_ORDER_ITEMS }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ json_str_items }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ json_str_items }}"
|
||||
>{{ str_items }}</div>
|
||||
{% else %}
|
||||
<div class="{{ model.FLAG_ORDER_ITEMS }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or variation_tree is not defined or variation_tree is none or is_blank_row is not defined) %}
|
||||
{% if not _is_blank_row %}
|
||||
{% set str_ids_variations = variation_tree.to_variation_id_pairs_str() %}
|
||||
{% set str_variations = variation_tree.to_preview_str() %}
|
||||
<div
|
||||
class="{{ model.FLAG_PRODUCT_VARIATIONS }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ str_ids_variations }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ str_ids_variations }}"
|
||||
>{{ str_variations }}</div>
|
||||
{% else %}
|
||||
<div class="{{ model.FLAG_PRODUCT_VARIATIONS }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or variation_type is not defined or variation_type.variations is none or variation_type.variations == [] or is_blank_row is not defined) %}
|
||||
{% if not _is_blank_row %}
|
||||
{# {% set ids_variation = variation_type.get_str_list_ids_variation() %} #}
|
||||
<div class="{{ model.FLAG_PRODUCT_VARIATIONS }}"
|
||||
{#
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ ids_variation }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ ids_variation }}"
|
||||
#}
|
||||
>
|
||||
{#
|
||||
{{ variation_type.get_preview_variations() }}
|
||||
#}
|
||||
{% for variation in variation_type.variations %}
|
||||
{{ variation.name }}<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="{{ model.FLAG_PRODUCT_VARIATIONS }}"></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
{% with _is_blank_row = (is_blank_row or variation_tree is not defined or is_blank_row is not defined) %}
|
||||
{% if not _is_blank_row %}
|
||||
{# % set json_str_variation_types = product.get_json_str_types_variation_trees() % #}
|
||||
{% set names_variation_type = product.get_variation_types_unique() %}
|
||||
{% set json_str_variation_types = jsonify(names_variation_type) %}
|
||||
<div
|
||||
class="{{ model.FLAG_PRODUCT_VARIATIONS }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ json_str_variation_types }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ json_str_variation_types }}"
|
||||
>{{ model.join_with_linebreaks(names_variation_type) }}</div>
|
||||
{% else %}
|
||||
<div class="{{ model.FLAG_PRODUCT_VARIATIONS }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
@@ -1,79 +0,0 @@
|
||||
|
||||
<!-- Address form
|
||||
<div class="card"> -->
|
||||
<form id="{{ form.output_id() }}" class="{{ model.flag_container }}">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
{% if form.form_type_billing_not_delivery %}
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.identical.label }}
|
||||
{{ form.identical(checked=True) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.region.label }}
|
||||
{{ form.region() }}
|
||||
{% for error in form.region.errors %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.name_full.label }}
|
||||
{{ form.name_full(size=100) }}
|
||||
{% for error in form.name_full.errors %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.phone_number.label }}
|
||||
{{ form.phone_number(size=20) }}
|
||||
{% for error in form.phone_number.errors %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.postcode.label }}
|
||||
{{ form.postcode(size=10) }}
|
||||
{% for error in form.postcode.errors %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.address_1.label }}
|
||||
{{ form.address_1(size=254) }}
|
||||
{% for error in form.address_1.errors %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.address_2.label }}
|
||||
{{ form.address_2(size=254) }}
|
||||
</div>
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.city.label }}
|
||||
{{ form.city(size=100) }}
|
||||
{% for error in form.city.errors %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.county.label }}
|
||||
{{ form.county(size=100) }}
|
||||
{% for error in form.county.errors %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ form.submit() }}
|
||||
</div>
|
||||
</form>
|
||||
<!--</div>-->
|
||||
@@ -1,18 +0,0 @@
|
||||
<!-- Basket -->
|
||||
{% set show_delivery_option = False %}
|
||||
<div id="{{ model.ID_BASKET }}" class="{{ model.FLAG_CARD }} {{ model.FLAG_SCROLLABLE }}">
|
||||
<div class="container column">
|
||||
<div class="container row">
|
||||
<h2>Basket</h2>
|
||||
<img class="img-icon" src="{{ url_for('static', filename='images/icon_basket.png')}}" alt="Basket icon">
|
||||
</div>
|
||||
{% for basket_item in model.basket.items %}
|
||||
{% include 'components/store/_basket_item.html' %}
|
||||
{% endfor %}
|
||||
<h3 id="{{ model.ID_BASKET_TOTAL }}">Total: {{ model.output_basket_total() }}</h3>{% if not model.app.is_included_VAT %}<h4> + VAT </h4>{% endif %}
|
||||
<p id="{{ model.ID_LABEL_BASKET_EMPTY }}" style="margin: 1vh;">Buy some shit dawg!</p>
|
||||
<!-- <div id="{{ model.id_basket_notices }}"> include line above
|
||||
</div> -->
|
||||
<button id="{{ model.ID_BUTTON_CHECKOUT }}" type="submit">Checkout</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,42 +0,0 @@
|
||||
<!-- Basket Item -->
|
||||
<!-- requires:
|
||||
Basket_Item basket_item
|
||||
bool show_delivery_option
|
||||
-->
|
||||
<div class="container row">
|
||||
{% set product = basket_item.product %}
|
||||
{% set permutation = product.get_permutation_selected() %}
|
||||
<div class="container">
|
||||
<img class="img-thumbnail" src="{{ product.get_image_from_index(0).url }}" alt="Basket icon"> <!-- model.get_many_product_image_src(product.id_product, '', True, 'THUMBNAIL') -->
|
||||
</div>
|
||||
{% set form = product.form_basket_edit %}
|
||||
<!-- <form {{ model.attr_form_type }}="{{ form.form_type }}" {{ model.attr_id_product }}="{{ product.id }}" class="container column" action="{{ url_for('basket_add') }}" method="POST"> -->
|
||||
<form {{ model.attr_form_type }}="{{ form.form_type }}" class="{{ model.flag_container }} {{ model.flag_column }}" {{ model.attr_id_product }}="{{ product.id_product}}" {{ model.attr_id_permutation }}="{{ permutation.id_permutation }}"> <!-- id="form_basket_item_id_{{ basket_item.product.id }}" -->
|
||||
{{ form.hidden_tag() }}
|
||||
<h2>{{ product.name }}</h2>
|
||||
{% if permutation.is_available %}
|
||||
<h3 style="white-space: nowrap;">{{ basket_item.quantity }} x {{ product.output_price(model.app.is_included_VAT) }} = {{ basket_item.output_subtotal() }}</h3>
|
||||
{% set tmp_quantity = basket_item.quantity %}
|
||||
{% include 'components/common/inputs/_input_number_plus_minus.html' %}
|
||||
{% elif permutation.is_unavailable_in_currency_or_region %}
|
||||
<h3 style="white-space: nowrap;">Product not available in currency and region</h3>
|
||||
{% else %}
|
||||
<h3 style="white-space: nowrap;">Product not available</h3>
|
||||
{% endif %}
|
||||
<a class="{{ model.FLAG_DELETE }}">Delete</a>
|
||||
{% if show_delivery_option %}
|
||||
<div class="{{ model.flag_container_input }}">
|
||||
{{ product.form_delivery_option.label }}
|
||||
{{ product.form_delivery_option() }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<script>
|
||||
if (_verbose) {
|
||||
console.log('creating basket item for:');
|
||||
console.log('product id: {{ product.id_product }}');
|
||||
console.log('permutation id: {{ product.get_id_permutation() }}');
|
||||
console.log('quantity: {{ basket_item.quantity }}');
|
||||
}
|
||||
</script>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,84 +0,0 @@
|
||||
|
||||
{% if is_blank_row %}
|
||||
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_MANUFACTURING_PURCHASE_ORDER }}" {{ model.ATTR_ID_MANUFACTURING_PURCHASE_ORDER }}>
|
||||
<td class="{{ model.FLAG_ORDER_ITEMS }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}="">
|
||||
{% include 'components/store/_preview_order_items.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CURRENCY }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}="">
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}">
|
||||
<div
|
||||
class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_INCL }}">
|
||||
<div
|
||||
class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL }}">
|
||||
<input type="number" min="0" step="0.001" class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}=""/>
|
||||
<div
|
||||
class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_INCL }}">
|
||||
<input type="number" min="0" step="0.001" class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_INCL }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}=""/>
|
||||
<div
|
||||
class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_INCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
</td>
|
||||
{% set active = true %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="{{ model.FLAG_MANUFACTURING_PURCHASE_ORDER }}" {{ model.ATTR_ID_MANUFACTURING_PURCHASE_ORDER }}="{{ order.id_order }}">
|
||||
{% set order_items = order.items %}
|
||||
{% set json_str_items = model.jsonify(model.convert_list_objects_to_list_options(order_items)) %}
|
||||
<td class="{{ model.FLAG_ORDER_ITEMS }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_VALUE_CURRENT }}="{{ json_str_items }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ json_str_items }}">
|
||||
{#
|
||||
{% include 'components/store/_preview_manufacturing_purchase_order_items.html' %}
|
||||
#}
|
||||
{% include 'components/store/_preview_order_items.html' %}
|
||||
</td>
|
||||
{% set currency = order.currency %}
|
||||
<td class="{{ model.FLAG_CURRENCY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ currency.id_currency }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ currency.id_currency }}">
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}">
|
||||
<div
|
||||
class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ order.cost_total_local_VAT_excl }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ order.cost_total_local_VAT_excl }}"
|
||||
></div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_INCL }}">
|
||||
<div
|
||||
class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_INCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ order.cost_total_local_VAT_incl }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ order.cost_total_local_VAT_incl }}"
|
||||
></div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL }}">
|
||||
<div
|
||||
class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_EXCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ order.price_total_local_VAT_excl }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ order.price_total_local_VAT_excl }}"
|
||||
></div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_INCL }}">
|
||||
<div
|
||||
class="{{ model.FLAG_PRICE_TOTAL_LOCAL_VAT_INCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ order.price_total_local_VAT_incl }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ order.price_total_local_VAT_incl }}"
|
||||
></div>
|
||||
</td>
|
||||
{% set active = order.active %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -1,60 +0,0 @@
|
||||
{% if is_blank_row %}
|
||||
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_PRODUCT }}" {{ model.ATTR_ID_PRODUCT }}>
|
||||
<td class="{{ model.FLAG_DISPLAY_ORDER }}">
|
||||
{% include 'components/common/buttons/_slider_display_order.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT_CATEGORY }}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}="0">
|
||||
{% include 'components/store/_preview_DDL_product_category.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME }}">
|
||||
<textarea class="{{ model.FLAG_NAME }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
{#
|
||||
<td class="{{ model.FLAG_PRODUCT_VARIATIONS }}">
|
||||
<textarea class="{{ model.FLAG_PRODUCT_VARIATIONS }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
#}
|
||||
<td class="{{ model.FLAG_HAS_VARIATIONS }}">
|
||||
<input class="{{ model.FLAG_HAS_VARIATIONS }}" type="checkbox" {{ model.ATTR_VALUE_CURRENT }}="{{ model.FLAG_BOOL_FALSE }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ model.FLAG_BOOL_FALSE }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_ACCESS_LEVEL }}"
|
||||
{{ model.ATTR_ID_ACCESS_LEVEL }}="1" {{ model.FLAG_ACCESS_LEVEL_REQUIRED }}="View"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}="1"
|
||||
>
|
||||
<div class="{{ model.FLAG_ACCESS_LEVEL}}" {{ model.ATTR_ID_ACCESS_LEVEL }}="1">View</div>
|
||||
</td>
|
||||
{% set active = true %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="{{ model.FLAG_PRODUCT }}" {{ model.ATTR_ID_PRODUCT }}="{{ product.id_product }}">
|
||||
<td class="{{ model.FLAG_DISPLAY_ORDER }}">
|
||||
{% set display_order = category.display_order %}
|
||||
{% include 'components/common/buttons/_slider_display_order.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT_CATEGORY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ product.id_category }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ product.id_category }}">
|
||||
{% include 'components/store/_preview_DDL_product_category.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME }}">
|
||||
<textarea class="{{ model.FLAG_NAME }}" {{ model.ATTR_VALUE_CURRENT }}="{{ product.name }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ product.name }}">{{ product.name }}</textarea>
|
||||
</td>
|
||||
{#
|
||||
<td class="{{ model.FLAG_PRODUCT_VARIATIONS }}">
|
||||
{% include 'components/common/inputs/_textarea_product_variation_types.html' %}
|
||||
<textarea class="{{ model.FLAG_PRODUCT_VARIATIONS }}" {{ model.ATTR_VALUE_CURRENT }}="{{ product.description }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ product.description }}">{{ product.description }}</textarea>
|
||||
</td>
|
||||
#}
|
||||
<td class="{{ model.FLAG_HAS_VARIATIONS }}">
|
||||
<input class="{{ model.FLAG_HAS_VARIATIONS }}" type="checkbox" {% if product.has_variations %}checked{% endif %}
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ product.has_variations | lower }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ product.has_variations | lower }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_ACCESS_LEVEL }}"
|
||||
{{ model.ATTR_ID_ACCESS_LEVEL }}="{{ product.id_access_level_required }}" {{ model.FLAG_ACCESS_LEVEL_REQUIRED }}="{{ product.name_access_level_required }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ product.id_access_level_required }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ product.id_access_level_required }}"
|
||||
>
|
||||
<div class="{{ model.FLAG_ACCESS_LEVEL}}" {{ model.ATTR_ID_ACCESS_LEVEL }}="{{ product.id_access_level_required }}" {{ model.ATTR_VALUE_CURRENT }}="{{ product.id_access_level_required }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ product.id_access_level_required }}">{{ product.name_access_level_required }}</div>
|
||||
</td>
|
||||
{% set active = product.active %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -1,42 +0,0 @@
|
||||
{% if is_blank_row %}
|
||||
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_PRODUCT_CATEGORY }}" {{ model.ATTR_ID_PRODUCT_CATEGORY }}>
|
||||
<td class="{{ model.FLAG_DISPLAY_ORDER }}">
|
||||
{% include 'components/common/buttons/_slider_display_order.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CODE }}">
|
||||
<textarea class="{{ model.FLAG_CODE }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME }}">
|
||||
<textarea class="{{ model.FLAG_NAME }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DESCRIPTION }}">
|
||||
<textarea class="{{ model.FLAG_DESCRIPTION }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_ACCESS_LEVEL }}" {{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}="1">
|
||||
<div class="{{ model.FLAG_ACCESS_LEVEL}}" {{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}="1">View</div>
|
||||
</td>
|
||||
{% set active = true %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="{{ model.FLAG_PRODUCT_CATEGORY }}" {{ model.ATTR_ID_PRODUCT_CATEGORY }}="{{ category.id_category }}">
|
||||
<td class="{{ model.FLAG_DISPLAY_ORDER }}">
|
||||
{% set display_order = category.display_order %}
|
||||
{% include 'components/common/buttons/_slider_display_order.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CODE }}">
|
||||
<textarea class="{{ model.FLAG_CODE }}" {{ model.ATTR_VALUE_CURRENT }}="{{ category.code }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ category.code }}">{{ category.code }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME }}">
|
||||
<textarea class="{{ model.FLAG_NAME }}" {{ model.ATTR_VALUE_CURRENT }}="{{ category.name }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ category.name }}">{{ category.name }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DESCRIPTION }}">
|
||||
<textarea class="{{ model.FLAG_DESCRIPTION }}" {{ model.ATTR_VALUE_CURRENT }}="{{ category.description }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ category.description }}">{{ category.description }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_ACCESS_LEVEL }}" {{ model.ATTR_VALUE_CURRENT }}="{{ category.id_access_level_required }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ category.id_access_level_required }}">
|
||||
<div class="{{ model.FLAG_ACCESS_LEVEL}}" {{ model.ATTR_VALUE_CURRENT }}="{{ category.id_access_level_required }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ category.id_access_level_required }}">{{ category.name_access_level_required }}</div>
|
||||
</td>
|
||||
{% set active = category.active %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -1,183 +0,0 @@
|
||||
|
||||
{% if is_blank_row %}
|
||||
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_PRODUCT_PERMUTATION }}" {{ model.ATTR_ID_PERMUTATION }}>
|
||||
<td class="{{ model.FLAG_PRODUCT_CATEGORY }}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}="0">
|
||||
{% include 'components/store/_preview_DDL_product_category.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT }}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}="0">
|
||||
{% include 'components/store/_preview_DDL_product.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT_VARIATIONS }} {{ model.FLAG_COLLAPSED}}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
{% include 'components/store/_preview_product_permutation_variations.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DESCRIPTION}}">
|
||||
<textarea class="{{ model.FLAG_DESCRIPTION }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_QUANTITY_STOCK }}">
|
||||
<input class="{{ model.FLAG_QUANTITY_STOCK }}" type="number" min="0" value="0" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}="0">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_QUANTITY_MIN }}">
|
||||
<input class="{{ model.FLAG_QUANTITY_MIN }}" type="number" min="0" value="1" {{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}="1">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_QUANTITY_MAX }}">
|
||||
<input class="{{ model.FLAG_QUANTITY_MAX }}" type="number" min="0" value="1" {{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}="1">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP }}">
|
||||
<input class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP }}"
|
||||
type="number" min="0" value="1" {{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}="1">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_UNIT_MEASUREMENT_QUANTITY }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
{% include 'components/store/_preview_DDL_product_permutation_unit_measurement_quantity.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_IS_SUBSCRIPTION }}">
|
||||
<input class="{{ model.FLAG_IS_SUBSCRIPTION }}" type="checkbox" {{ model.ATTR_VALUE_CURRENT }}="{{ model.FLAG_BOOL_FALSE }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ model.FLAG_BOOL_FALSE }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }}">
|
||||
<input class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }} {{ model.FLAG_COLLAPSED }}"
|
||||
type="number" min="0" value="1" {{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}="1">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
{% include 'components/store/_preview_DDL_product_permutation_interval_recurrence.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_ID_STRIPE_PRODUCT }}">
|
||||
<input class="{{ model.FLAG_ID_STRIPE_PRODUCT }}" type="text" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED }}">
|
||||
<input class="{{ model.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED }}" type="checkbox" {{ model.ATTR_VALUE_CURRENT }}="{{ model.FLAG_BOOL_FALSE }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ model.FLAG_BOOL_FALSE }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED }}">
|
||||
<input class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED }} {{ model.FLAG_COLLAPSED }}"
|
||||
type="number" min="0" value="1" {{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}="1">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
{% include 'components/store/_preview_DDL_product_permutation_interval_expiration_unsealed.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}">
|
||||
<!--
|
||||
<input class="{{ model.FLAG_COST_LOCAL }}" type="number" min="0" step="0.01"
|
||||
-->
|
||||
<div class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
0
|
||||
</div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_INCL }}">
|
||||
<div class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
0
|
||||
</div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CURRENCY_COST }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PROFIT_LOCAL_MIN }}">
|
||||
<input class="{{ model.FLAG_PROFIT_LOCAL_MIN }}" type="number" min="0" step="0.01"
|
||||
value="0" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_LATENCY_MANUFACTURE }}">
|
||||
<input class="{{ model.FLAG_LATENCY_MANUFACTURE }}" type="number" min="0" value="1" {{ model.ATTR_VALUE_CURRENT }}="1" {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
</td>
|
||||
{% set active = true %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="{{ model.FLAG_PRODUCT_PERMUTATION }}" {{ model.ATTR_ID_PRODUCT_PERMUTATION }}="{{ permutation.id_permutation }}">
|
||||
<td class="{{ model.FLAG_PRODUCT_CATEGORY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_category }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_category }}">
|
||||
{% include 'components/store/_preview_DDL_product_category.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_product }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_product }}">
|
||||
{% include 'components/store/_preview_DDL_product.html' %}
|
||||
</td>
|
||||
|
||||
{% set variation_tree = permutation.variation_tree %}
|
||||
{% set str_ids_variations = variation_tree.to_variation_id_pairs_str() if not (variation_tree is none) else '' %}
|
||||
<td class="{{ model.FLAG_PRODUCT_VARIATIONS }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_VALUE_CURRENT }}="{{ str_ids_variations }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ str_ids_variations }}">
|
||||
{% include 'components/store/_preview_product_permutation_variations.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DESCRIPTION}}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.description }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.description }}">
|
||||
<textarea class="{{ model.FLAG_DESCRIPTION }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.description }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.description }}">{{ permutation.description }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_QUANTITY_STOCK }}">
|
||||
<input class="{{ model.FLAG_QUANTITY_STOCK }}" type="number" min="0" value="{{ permutation.quantity_stock }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.quantity_stock }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.quantity_stock }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_QUANTITY_MIN }}">
|
||||
<input class="{{ model.FLAG_QUANTITY_MIN }}" type="number" min="0" value="{{ permutation.quantity_min }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.quantity_min }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.quantity_min }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_QUANTITY_MAX }}">
|
||||
<input class="{{ model.FLAG_QUANTITY_MAX }}" type="number" min="0" value="{{ permutation.quantity_max }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.quantity_max }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.quantity_max }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP }}">
|
||||
<input class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_PER_QUANTITY_STEP }}" type="number" min="0" value="{{ permutation.count_unit_measurement_per_quantity_step }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.count_unit_measurement_per_quantity_step }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.count_unit_measurement_per_quantity_step }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_UNIT_MEASUREMENT_QUANTITY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_unit_measurement_quantity }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_unit_measurement_quantity }}">
|
||||
{% include 'components/store/_preview_DDL_product_permutation_unit_measurement_quantity.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_IS_SUBSCRIPTION }}">
|
||||
<input type="checkbox" {% if permutation.is_subscription %}checked{% endif %}
|
||||
class="{{ model.FLAG_IS_SUBSCRIPTION }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ permutation.is_subscription | lower }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.is_subscription | lower }}"
|
||||
/>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }}">
|
||||
{% set value = permutation.count_interval_recurrence if permutation.count_interval_recurrence is not none else 1 %}
|
||||
<input class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }} {% if not permutation.is_subscription %}{{ model.FLAG_COLLAPSED }}{% endif %}"
|
||||
type="number" min="0"
|
||||
value="{% if value is not none %}{{ value }}{% else %}{{ 1 }}{% endif %}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{% if value is not none %}{{ value }}{% else %}{{ 1 }}{% endif %}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ value }}"
|
||||
/>
|
||||
</td>
|
||||
|
||||
{% set value = permutation.id_unit_measurement_interval_recurrence if permutation.id_unit_measurement_interval_recurrence is not none else '' %}
|
||||
<td class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_RECURRENCE }}" {{ model.ATTR_VALUE_CURRENT }}="{{ value }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ value }}">
|
||||
{% include 'components/store/_preview_DDL_product_permutation_interval_recurrence.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_ID_STRIPE_PRODUCT }}">
|
||||
{% set value = permutation.id_stripe_product if permutation.id_stripe_product is not none else '' %}
|
||||
<input class="{{ model.FLAG_ID_STRIPE_PRODUCT }}" type="text" value="{{ value }}" {{ model.ATTR_VALUE_CURRENT }}="{{ value }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ value }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED }}">
|
||||
<input type="checkbox" {% if permutation.does_expire_faster_once_unsealed %}checked{% endif %}
|
||||
class="{{ model.FLAG_DOES_EXPIRE_FASTER_ONCE_UNSEALED }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ permutation.does_expire_faster_once_unsealed | lower }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.does_expire_faster_once_unsealed | lower }}"
|
||||
/>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED }}">
|
||||
{% set value = permutation.count_interval_expiration_unsealed if permutation.count_interval_expiration_unsealed is not none else 1 %}
|
||||
<input class="{{ model.FLAG_COUNT_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED }} {% if not permutation.does_expire_faster_once_unsealed %}{{ model.FLAG_COLLAPSED }}{% endif %}"
|
||||
type="number" min="0"
|
||||
value="{% if value is not none %}{{ value }}{% else %}{{ 1 }}{% endif %}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{% if value is not none %}{{ value }}{% else %}{{ 1 }}{% endif %}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ value }}"
|
||||
/>
|
||||
</td>
|
||||
|
||||
{% set value = permutation.id_unit_measurement_interval_expiration_unsealed if permutation.id_unit_measurement_interval_expiration_unsealed is not none else '' %}
|
||||
<td class="{{ model.FLAG_UNIT_MEASUREMENT_INTERVAL_EXPIRATION_UNSEALED }}" {{ model.ATTR_VALUE_CURRENT }}="{{ value }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ value }}">
|
||||
{% include 'components/store/_preview_DDL_product_permutation_interval_expiration_unsealed.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}">
|
||||
<div class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.cost_local_VAT_excl }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.cost_local_VAT_excl }}">
|
||||
{{ permutation.cost_local_VAT_excl }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_INCL }}">
|
||||
<div class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_INCL }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.cost_local_VAT_incl }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.cost_local_VAT_incl }}">
|
||||
{{ permutation.cost_local_VAT_incl }}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
{% set currency = permutation.currency_cost %}
|
||||
<td class="{{ model.FLAG_CURRENCY_COST }}" {{ model.ATTR_VALUE_CURRENT }}="{{ currency.id_currency }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ currency.id_currency }}">
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PROFIT_LOCAL_MIN }}">
|
||||
<input class="{{ model.FLAG_PROFIT_LOCAL_MIN }}" type="number" min="0" value="{{ permutation.profit_local_min }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.profit_local_min }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.profit_local_min }}">
|
||||
</td>
|
||||
<td class="{{ model.FLAG_LATENCY_MANUFACTURE }}">
|
||||
<input class="{{ model.FLAG_LATENCY_MANUFACTURE }}" type="number" min="0" value="{{ permutation.latency_manufacture }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.latency_manufacture }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.latency_manufacture }}">
|
||||
</td>
|
||||
{% set active = permutation.active %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -1,51 +0,0 @@
|
||||
{% if is_blank_row %}
|
||||
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_PRODUCT_VARIATION_TYPE }}" {{ model.ATTR_ID_PRODUCT_VARIATION_TYPE }}>
|
||||
<td class="{{ model.FLAG_DISPLAY_ORDER }}">
|
||||
{% include 'components/common/buttons/_slider_display_order.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CODE }}">
|
||||
<textarea class="{{ model.FLAG_CODE }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME }}">
|
||||
<textarea class="{{ model.FLAG_NAME }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME_PLURAL }}">
|
||||
<textarea class="{{ model.FLAG_NAME_PLURAL }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT_VARIATIONS}} {{ model.FLAG_COLLAPSED }}">
|
||||
{% include 'components/store/_preview_product_variation_type_variations.html' %}
|
||||
</td>
|
||||
{% set active = true %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="{{ model.FLAG_PRODUCT_VARIATION_TYPE }}" {{ model.ATTR_ID_PRODUCT_VARIATION_TYPE }}="{{ variation_type.id_type }}">
|
||||
<td class="{{ model.FLAG_DISPLAY_ORDER }}">
|
||||
{% set display_order = variation_type.display_order %}
|
||||
{% include 'components/common/buttons/_slider_display_order.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CODE }}">
|
||||
<textarea class="{{ model.FLAG_CODE }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ variation_type.code }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ variation_type.code }}"
|
||||
>{{ variation_type.code }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME }}">
|
||||
<textarea class="{{ model.FLAG_NAME }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ variation_type.name_singular }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ variation_type.name_singular }}"
|
||||
>{{ variation_type.name_singular }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME_PLURAL }}">
|
||||
<textarea class="{{ model.FLAG_NAME_PLURAL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ variation_type.name_plural }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ variation_type.name_plural }}"
|
||||
>{{ variation_type.name_plural }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT_VARIATIONS}} {{ model.FLAG_COLLAPSED }}">
|
||||
{% include 'components/store/_preview_product_variation_type_variations.html' %}
|
||||
</td>
|
||||
{% set active = variation_type.active %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -1,147 +0,0 @@
|
||||
{% if date_time_now is not defined %}
|
||||
{% set date_time_now = model.format_date(datetime.now()) %}
|
||||
{% endif %}
|
||||
{% if is_blank_row %}
|
||||
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_STOCK_ITEM }}" {{ model.ATTR_ID_STOCK_ITEM }}>
|
||||
<td class="{{ model.FLAG_PRODUCT_CATEGORY }}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}="0">
|
||||
{% include 'components/store/_preview_DDL_product_category.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT }}" {{ model.ATTR_VALUE_CURRENT }}="0" {{ model.ATTR_VALUE_PREVIOUS }}="0">
|
||||
{% include 'components/store/_preview_DDL_product.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT_VARIATIONS }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_ID_PRODUCT_PERMUTATION }}="0">
|
||||
{% include 'components/store/_preview_product_permutation_variations.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CURRENCY_COST }}">
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}">
|
||||
<input class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}" type="number" min="0" value="" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_INCL }}">
|
||||
<input class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_INCL }}" type="number" min="0" value="" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_PURCHASED }}">
|
||||
<input class="{{ model.FLAG_DATE_PURCHASED }}" type="datetime-local" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }} />
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_RECEIVED }}">
|
||||
<input type="datetime-local" class="{{ model.FLAG_DATE_RECEIVED }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }} />
|
||||
</td>
|
||||
<td class="{{ model.FLAG_STORAGE_LOCATION }}">
|
||||
{% include 'components/store/_preview_DDL_stock_item_storage_location.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_IS_SEALED }}">
|
||||
<input type="checkbox" class="{{ model.FLAG_IS_SEALED }}" checked
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ model.FLAG_BOOL_TRUE }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ model.FLAG_BOOL_TRUE }}" />
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_UNSEALED }}">
|
||||
<input type="datetime-local" class="{{ model.FLAG_DATE_UNSEALED }} {{ model.FLAG_COLLAPSED }}"
|
||||
value = "{{ date_time_now }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }} = "{{ date_time_now }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}
|
||||
/>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_EXPIRATION }}">
|
||||
<input type="datetime-local" class="{{ model.FLAG_DATE_EXPIRATION }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }} />
|
||||
</td>
|
||||
<td class="{{ model.FLAG_IS_CONSUMED }}">
|
||||
<input type="checkbox" class="{{ model.FLAG_IS_CONSUMED }}" {{ model.ATTR_VALUE_CURRENT }}="{{ model.FLAG_BOOL_FALSE }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ model.FLAG_BOOL_FALSE }}" />
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_CONSUMED }}">
|
||||
<input type="datetime-local" class="{{ model.FLAG_DATE_CONSUMED }} {{ model.FLAG_COLLAPSED }}"
|
||||
value = "{{ date_time_now }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }} = "{{ date_time_now }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}
|
||||
/>
|
||||
</td>
|
||||
{% set active = true %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="{{ model.FLAG_STOCK_ITEM }}" {{ model.ATTR_ID_STOCK_ITEM }}="{{ stock_item.id_stock }}">
|
||||
<td class="{{ model.FLAG_PRODUCT_CATEGORY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_category }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_category }}">
|
||||
{% include 'components/store/_preview_DDL_product_category.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PRODUCT }}" {{ model.ATTR_VALUE_CURRENT }}="{{ permutation.id_product }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ permutation.id_product }}">
|
||||
{% include 'components/store/_preview_DDL_product.html' %}
|
||||
</td>
|
||||
{% set variation_tree = permutation.variation_tree %}
|
||||
{% set str_ids_variations = variation_tree.to_variation_id_pairs_str() if not (variation_tree is none) else '' %}
|
||||
<td class="{{ model.FLAG_PRODUCT_VARIATIONS }} {{ model.FLAG_COLLAPSED }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ str_ids_variations }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ str_ids_variations }}"
|
||||
{{ model.ATTR_ID_PRODUCT_PERMUTATION }}="{{ permutation.id_permutation }}"
|
||||
>
|
||||
{% include 'components/store/_preview_product_permutation_variations.html' %}
|
||||
</td>
|
||||
{% set currency = stock_item.currency_cost %}
|
||||
<td class="{{ model.FLAG_CURRENCY_COST }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ currency.id_currency }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ currency.id_currency }}"
|
||||
>
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}">
|
||||
<input class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_EXCL }}" type="number" step="0.001"
|
||||
value="{{ stock_item.cost_local_VAT_excl }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ stock_item.cost_local_VAT_excl }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ stock_item.cost_local_VAT_excl }}"
|
||||
>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_INCL }}">
|
||||
<input class="{{ model.FLAG_COST_UNIT_LOCAL_VAT_INCL }}" type="number" step="0.001"
|
||||
value="{{ stock_item.cost_local_VAT_incl }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ stock_item.cost_local_VAT_incl }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ stock_item.cost_local_VAT_incl }}"
|
||||
>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_PURCHASED }}">
|
||||
<input type="datetime-local" value="{{ model.format_datetime(stock_item.date_purchased) }}" {{ model.ATTR_VALUE_CURRENT }}="{{ model.format_datetime(stock_item.date_purchased) }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ model.format_datetime(stock_item.date_purchased) }}" />
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_RECEIVED }}">
|
||||
<input type="datetime-local"
|
||||
class="{{ model.FLAG_DATE_RECEIVED }} {% if stock_item.date_purchased is none %}{{ model.FLAG_COLLAPSED }}{% endif %}"
|
||||
value="{{ model.format_datetime(stock_item.date_received) }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ model.format_datetime(stock_item.date_received) }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ model.format_datetime(stock_item.date_received) }}"
|
||||
/>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_STORAGE_LOCATION }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ stock_item.id_location_storage }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ stock_item.id_location_storage }}"
|
||||
>
|
||||
{% set storage_location = stock_item.storage_location %}
|
||||
{% include 'components/store/_preview_DDL_stock_item_storage_location.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_IS_SEALED }}">
|
||||
<input type="checkbox" {{ "checked" if stock_item.is_sealed else "" }}
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ stock_item.is_sealed | lower }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ stock_item.is_sealed | lower }}"
|
||||
/>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_UNSEALED }}">
|
||||
<input type="datetime-local"
|
||||
class="{{ model.FLAG_DATE_UNSEALED }} {% if stock_item.is_sealed %}{{ model.FLAG_COLLAPSED }}{% endif %}"
|
||||
value="{{ model.format_datetime(stock_item.date_unsealed) }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ model.format_datetime(stock_item.date_unsealed) }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ model.format_datetime(stock_item.date_unsealed) }}"
|
||||
/>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_EXPIRATION }}">
|
||||
<input type="datetime-local" value="{{ model.format_datetime(stock_item.date_expiration) }}" {{ model.ATTR_VALUE_CURRENT }}="{{ model.format_datetime(stock_item.date_expiration) }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ model.format_datetime(stock_item.date_expiration) }}" />
|
||||
</td>
|
||||
<td class="{{ model.FLAG_IS_CONSUMED }}">
|
||||
<input type="checkbox" {{ "checked" if stock_item.is_consumed else "" }} {{ model.ATTR_VALUE_CURRENT }}="{{ stock_item.is_consumed | lower }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ stock_item.is_consumed | lower }}" />
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DATE_CONSUMED }}">
|
||||
<input type="datetime-local"
|
||||
class="{{ model.FLAG_DATE_CONSUMED }} {% if not stock_item.is_consumed %}{{ model.FLAG_COLLAPSED }}{% endif %}"
|
||||
value="{{ model.format_datetime(stock_item.date_consumed) }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ model.format_datetime(stock_item.date_consumed) }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ model.format_datetime(stock_item.date_consumed) }}"
|
||||
/>
|
||||
</td>
|
||||
{% set active = stock_item.active %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -1,67 +0,0 @@
|
||||
{% if is_blank_row %}
|
||||
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_SUPPLIER }}" {{ model.ATTR_ID_SUPPLIER }}>
|
||||
<td class="{{ model.FLAG_NAME_COMPANY }}">
|
||||
<textarea class="{{ model.FLAG_NAME_COMPANY }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME_CONTACT }}">
|
||||
<textarea class="{{ model.FLAG_NAME_CONTACT }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DEPARTMENT_CONTACT }}">
|
||||
<textarea class="{{ model.FLAG_DEPARTMENT_CONTACT }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_ADDRESS }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}="">
|
||||
{% include 'components/store/_preview_address.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PHONE_NUMBER }}">
|
||||
<textarea class="{{ model.FLAG_PHONE_NUMBER }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_FAX }}">
|
||||
<textarea class="{{ model.FLAG_FAX }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_EMAIL }}">
|
||||
<textarea class="{{ model.FLAG_EMAIL }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_WEBSITE }}">
|
||||
<textarea class="{{ model.FLAG_WEBSITE }}" {{ model.ATTR_VALUE_CURRENT }} {{ model.ATTR_VALUE_PREVIOUS }}></textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CURRENCY }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}="">
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
{% set active = true %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="{{ model.FLAG_SUPPLIER }}" {{ model.ATTR_ID_SUPPLIER }}="{{ supplier.id_supplier }}">
|
||||
<td class="{{ model.FLAG_NAME_COMPANY }}">
|
||||
<textarea class="{{ model.FLAG_NAME_COMPANY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ supplier.name_company }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.name_company }}">{{ supplier.name_company }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_NAME_CONTACT }}">
|
||||
<textarea class="{{ model.FLAG_NAME_CONTACT }}" {{ model.ATTR_VALUE_CURRENT }}="{{ supplier.name_contact }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.name_contact }}">{{ supplier.name_contact }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_DEPARTMENT_CONTACT }}">
|
||||
<textarea class="{{ model.FLAG_DEPARTMENT_CONTACT }}" {{ model.ATTR_VALUE_CURRENT }}="{{ supplier.department_contact }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.department_contact }}">{{ supplier.department_contact }}</textarea>
|
||||
</td>
|
||||
{% set address = supplier.get_address_active() %}
|
||||
<td class="{{ model.FLAG_ADDRESS }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_VALUE_CURRENT }}="{{ address.id_address }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ address.id_address }}">
|
||||
{% include 'components/store/_preview_address.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_PHONE_NUMBER }}">
|
||||
<textarea class="{{ model.FLAG_PHONE_NUMBER }}" {{ model.ATTR_VALUE_CURRENT }}="{{ supplier.name_company }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.phone_number }}">{{ supplier.phone_number }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_FAX }}">
|
||||
<textarea class="{{ model.FLAG_FAX }}" {{ model.ATTR_VALUE_CURRENT }}="{{ supplier.name_company }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.fax }}">{{ supplier.fax }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_EMAIL }}">
|
||||
<textarea class="{{ model.FLAG_EMAIL }}" {{ model.ATTR_VALUE_CURRENT }}="{{ supplier.name_company }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.email }}">{{ supplier.email }}</textarea>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_WEBSITE }}">
|
||||
<textarea class="{{ model.FLAG_WEBSITE }}" {{ model.ATTR_VALUE_CURRENT }}="{{ supplier.website }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.website }}">{{ supplier.website }}</textarea>
|
||||
</td>
|
||||
{% set currency = supplier.currency %}
|
||||
<td class="{{ model.FLAG_CURRENCY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ currency.id_currency }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ currency.id_currency }}">
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
{% set active = supplier.active %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -1,66 +0,0 @@
|
||||
|
||||
{% if is_blank_row %}
|
||||
<tr class="{{ model.FLAG_ROW_NEW }} {{ model.FLAG_SUPPLIER_PURCHASE_ORDER }}" {{ model.ATTR_ID_SUPPLIER_PURCHASE_ORDER }}>
|
||||
<td class="{{ model.FLAG_SUPPLIER }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}="">
|
||||
{% include 'components/store/_preview_DDL_supplier.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_ORDER_ITEMS }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}="">
|
||||
{% include 'components/store/_preview_order_items.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_CURRENCY }}" {{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}="">
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}">
|
||||
<div
|
||||
class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_INCL }}">
|
||||
<div
|
||||
class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="" {{ model.ATTR_VALUE_PREVIOUS }}=""
|
||||
></div>
|
||||
</td>
|
||||
{% set active = true %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="{{ model.FLAG_SUPPLIER_PURCHASE_ORDER }}" {{ model.ATTR_ID_SUPPLIER_PURCHASE_ORDER }}="{{ order.id_order }}">
|
||||
{% set supplier = order.supplier %}
|
||||
<td class="{{ model.FLAG_SUPPLIER }}" {{ model.ATTR_VALUE_CURRENT }}="{{ supplier.id_supplier }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ supplier.id_supplier }}">
|
||||
{% include 'components/store/_preview_DDL_supplier.html' %}
|
||||
</td>
|
||||
{% set order_items = order.items %}
|
||||
{% set json_str_items = model.jsonify(model.convert_list_objects_to_list_options(order_items)) %}
|
||||
<td class="{{ model.FLAG_ORDER_ITEMS }} {{ model.FLAG_COLLAPSED }}" {{ model.ATTR_VALUE_CURRENT }}="{{ json_str_items }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ json_str_items }}">
|
||||
{% include 'components/store/_preview_order_items.html' %}
|
||||
</td>
|
||||
{% set currency = order.currency %}
|
||||
<td class="{{ model.FLAG_CURRENCY }}" {{ model.ATTR_VALUE_CURRENT }}="{{ currency.id_currency }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ currency.id_currency }}">
|
||||
{% include 'components/store/_preview_DDL_currency.html' %}
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}">
|
||||
{#
|
||||
<input type="number" min="0" step="0.001" >
|
||||
#}
|
||||
<div
|
||||
class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_EXCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ order.cost_total_local_VAT_excl }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ order.cost_total_local_VAT_excl }}"
|
||||
></div>
|
||||
</td>
|
||||
<td class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_INCL }}">
|
||||
{#
|
||||
<input type="number" min="0" step="0.001" >
|
||||
#}
|
||||
<div
|
||||
class="{{ model.FLAG_COST_TOTAL_LOCAL_VAT_INCL }}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ order.cost_total_local_VAT_incl }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ order.cost_total_local_VAT_incl }}"
|
||||
></div>
|
||||
</td>
|
||||
{% set active = order.active %}
|
||||
{% include 'components/store/_td_active.html' %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
|
||||
{% with _active = (active is not defined or active or active is none) %}
|
||||
<td class="{{ model.FLAG_ACTIVE }}">
|
||||
{#
|
||||
<input class="{{ model.FLAG_ACTIVE }}" type="checkbox" {% if active %}checked{% endif %} {{ model.ATTR_VALUE_CURRENT }}="{{ active | lower }}" {{ model.ATTR_VALUE_PREVIOUS }}="{{ active | lower }}">
|
||||
#}
|
||||
<button type="button" class="{{ model.FLAG_ACTIVE }} {% if active %}{{ model.FLAG_DELETE }}{% endif %}"
|
||||
{{ model.ATTR_VALUE_CURRENT }}="{{ active | lower }}"
|
||||
{{ model.ATTR_VALUE_PREVIOUS }}="{{ active | lower }}"
|
||||
>{% if active %}x{% else %}+{% endif %}</button>
|
||||
</td>
|
||||
{% endwith %}
|
||||
@@ -1,31 +0,0 @@
|
||||
{% if block_id == 'block1' %}
|
||||
<div class="common-block" id="block1">
|
||||
<h1>Feckin common block boi</h1>
|
||||
</div>
|
||||
{% elif block_id == 'checkout' %}
|
||||
<!-- Variables from Model_View_Store + model-->
|
||||
<script>
|
||||
var hashPageStoreCheckout = "{{ model.HASH_PAGE_STORE_CHECKOUT }}";
|
||||
var hashPageStoreCheckoutSession = "{{ model.HASH_PAGE_STORE_CHECKOUT_SESSION }}";
|
||||
var hashStoreBasketInfo = "{{ model.HASH_STORE_BASKET_INFO }}";
|
||||
var idOverlayInfoBilling = "#{{ model.ID_OVERLAY_INFO_BILLING }}";
|
||||
var idOverlayInfoDelivery = "#{{ model.ID_OVERLAY_INFO_DELIVERY }}";
|
||||
var idContainerInfoBilling = "#{{ model.ID_CONTAINER_INFO_BILLING }}";
|
||||
var idContainerInfoDelivery = "#{{ model.ID_CONTAINER_INFO_DELIVERY }}";
|
||||
var keyIdCheckout = "{{ model.KEY_ID_CHECKOUT }}";
|
||||
var keyInfoBilling = "{{ model.KEY_INFO_BILLING }}";
|
||||
var keyInfoDelivery = "{{ model.KEY_INFO_DELIVERY }}";
|
||||
var keyInfoIdentical = "{{ model.KEY_INFO_IDENTICAL }}";
|
||||
var keyInfoType = "{{ model.KEY_INFO_TYPE }}";
|
||||
var keyIsSubscription = "{{ model.KEY_IS_SUBSCRIPTION }}";
|
||||
var keyAddress1 = "{{ model.KEY_ADDRESS1 }}";
|
||||
var keyAddress2 = "{{ model.KEY_ADDRESS2 }}";
|
||||
var keyCity = "{{ model.KEY_CITY }}";
|
||||
var keyCounty = "{{ model.KEY_COUNTY }}";
|
||||
var keyNameFull = "{{ model.KEY_NAME_FULL }}";
|
||||
var keyPhoneNumber = "{{ model.KEY_PHONE_NUMBER }}";
|
||||
var keyPostcode = "{{ model.KEY_POSTCODE }}";
|
||||
var keyRegion = "{{ model.KEY_REGION }}";
|
||||
var keyUrlCheckout = "{{ model.KEY_URL_CHECKOUT }}";
|
||||
</script>
|
||||
{% endif %}
|
||||
@@ -47,6 +47,11 @@
|
||||
var attrValueCurrent = "{{ model.ATTR_VALUE_CURRENT }}";
|
||||
var attrValuePrevious = "{{ model.ATTR_VALUE_PREVIOUS }}";
|
||||
var attrValueNew = "{{ model.ATTR_VALUE_NEW }}";
|
||||
var environment = {
|
||||
"name": "{{ model.app.app_config.FLASK_ENV }}",
|
||||
"is_production": "{{ model.app.app_config.is_production }}",
|
||||
"is_development": "{{ model.app.app_config.is_development }}",
|
||||
};
|
||||
var flagAccessLevel = "{{ model.FLAG_ACCESS_LEVEL }}";
|
||||
var flagAccessLevelRequired = "{{ model.FLAG_ACCESS_LEVEL_REQUIRED }}";
|
||||
var flagActive = "{{ model.FLAG_ACTIVE }}";
|
||||
@@ -132,23 +137,16 @@
|
||||
var flagTemporaryElement = "{{ model.FLAG_TEMPORARY_ELEMENT }}";
|
||||
var flagUser = "{{ model.FLAG_USER }}";
|
||||
var flagWebsite = "{{ model.FLAG_WEBSITE }}";
|
||||
var hashALTCHACreateChallenge = "{{ model.HASH_ALTCHA_CREATE_CHALLENGE }}";
|
||||
var hashApplyFiltersStoreProductPermutation = "{{ model.HASH_APPLY_FILTERS_STORE_PRODUCT_PERMUTATION }}";
|
||||
var hashGetALTCHAChallenge = "{{ model.HASH_ALTCHA_CREATE_CHALLENGE }}";
|
||||
var hashPageAccessibilityReport = "{{ model.HASH_PAGE_ACCESSIBILITY_REPORT }}";
|
||||
var hashPageAccessibilityStatement = "{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}";
|
||||
var hashPageAdminHome = "{{ model.HASH_PAGE_ADMIN_HOME }}";
|
||||
var hashPageContact = "{{ model.HASH_PAGE_CONTACT }}";
|
||||
var hashPageContactSuccess = "{{ model.HASH_PAGE_CONTACT_SUCCESS }}";
|
||||
var hashPageDataRetentionSchedule = "{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}";
|
||||
// var hashPageCurrent = "{{ model.hash_page_current }}";
|
||||
var hashPageErrorNoPermission = "{{ model.HASH_PAGE_ERROR_NO_PERMISSION }}";
|
||||
var hashPageHome = "{{ model.HASH_PAGE_HOME }}";
|
||||
var hashPageLicense = "{{ model.HASH_PAGE_LICENSE }}";
|
||||
var hashPagePrivacyPolicy = "{{ model.HASH_PAGE_PRIVACY_POLICY }}";
|
||||
var hashPageServices = "{{ model.HASH_PAGE_SERVICES }}";
|
||||
var hashPageUserAccount = "{{ model.HASH_PAGE_USER_ACCOUNT }}";
|
||||
var hashPageUserAdmin = "{{ model.HASH_PAGE_USER_ADMIN }}";
|
||||
var hashPageUserLogin = "{{ model.HASH_PAGE_USER_LOGIN }}";
|
||||
var hashPageUserLogout = "{{ model.HASH_PAGE_USER_LOGOUT }}";
|
||||
var idButtonApplyFilters = "#{{ model.ID_BUTTON_APPLY_FILTERS }}";
|
||||
var idButtonHamburger = "#{{ model.ID_BUTTON_HAMBURGER }}";
|
||||
var idCSRFToken = "#{{ model.ID_CSRF_TOKEN }}";
|
||||
@@ -168,10 +166,6 @@
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Stylesheets
|
||||
<link href="{{ url_for('static', filename='css/main.css') }}" rel="stylesheet" type="text/css"/>
|
||||
<link rel="stylesheet" loading="eager" href="{{ url_for('static', filename='dist/css/main.bundle.css') }}">
|
||||
-->
|
||||
<link rel="preload" as="style" href="{{ url_for('static', filename='dist/css/main.bundle.css') }}" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="{{ url_for('static', filename='dist/css/main.bundle.css') }}"></noscript>
|
||||
|
||||
@@ -182,7 +176,7 @@
|
||||
<header>
|
||||
<div class="container">
|
||||
<nav class="navbar">
|
||||
<div class="{{ model.FLAG_LOGO }}" href="/">{{ model.NAME_COMPANY }}</div>
|
||||
<div class="{{ model.FLAG_LOGO }}" href="{{ model.HASH_PAGE_HOME }}">{{ model.NAME_COMPANY }}</div>
|
||||
<div class="nav-links">
|
||||
{% block page_nav_links %}{% endblock %}
|
||||
</div>
|
||||
@@ -209,8 +203,8 @@
|
||||
<div class="footer-section">
|
||||
<h3>Legal</h3>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('routes_legal.privacy_policy') }}">Privacy Policy</a></li>
|
||||
<li><a href="{{ url_for('routes_legal.accessibility_statement') }}">Accessibility Statement</a></li>
|
||||
<li><a href="{{ model.HASH_PAGE_PRIVACY_POLICY }}">Privacy Policy</a></li>
|
||||
<li><a href="{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}">Accessibility Statement</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -225,24 +219,11 @@
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© {{ current_year }} {{ model.NAME_COMPANY }}. <a href="{{ url_for('routes_legal.license') }}" alt="License" aria-label="License">All rights reserved.</a></p>
|
||||
<p>© {{ current_year }} {{ model.NAME_COMPANY }}. <a href="{{ model.HASH_PAGE_LICENSE }}" alt="License" aria-label="License">All rights reserved.</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- JavaScript -->
|
||||
<!--<script type="module" src="{{ url_for('static', filename='js/pages/base.js') }}"></script>
|
||||
<script type="module" src="{{ url_for('static', filename='js/app.js') }}"></script>-->
|
||||
<script src="{{ url_for('static', filename='dist/js/main.bundle.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!--
|
||||
<script>
|
||||
|
||||
$(document).ready(function() {
|
||||
// alert("naughty boy");
|
||||
hookupShared();
|
||||
});
|
||||
</script>
|
||||
-->
|
||||
|
||||
@@ -2,25 +2,6 @@
|
||||
|
||||
{% block page_head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_contact.bundle.css') }}">
|
||||
{#
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@altcha/browser@latest/dist/index.js" defer></script>
|
||||
#}
|
||||
{# with CDN
|
||||
<script src="https://cdn.jsdelivr.net/npm/@altcha/browser@1.1.0/dist/altcha.min.js"></script>
|
||||
<style>
|
||||
.altcha-widget {
|
||||
margin: 15px 0;
|
||||
}
|
||||
</style>
|
||||
#}
|
||||
{# with locally stored vendor project - this is imported into contact.js
|
||||
<script type="module" src="{{ url_for('static', filename='js/vendor/altcha.js')}}"></script>
|
||||
#}
|
||||
<style>
|
||||
.altcha-widget {
|
||||
margin: 15px 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block page_nav_links %}
|
||||
@@ -31,36 +12,14 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block page_body %}
|
||||
{#
|
||||
<script>
|
||||
function loadRecaptcha() {
|
||||
var script = document.createElement('script');
|
||||
script.src = "https://www.google.com/recaptcha/enterprise.js?render=6Lf8Q8cpAAAAAFAawGu4-ma60bvbEixNVTVvRzKe";
|
||||
script.async = true;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
||||
window.addEventListener('load', loadRecaptcha);
|
||||
</script>
|
||||
#}
|
||||
|
||||
{% set form = model.form_contact %}
|
||||
<section class="contact-section">
|
||||
<div class="contact-form">
|
||||
<h1>Contact Us</h1>
|
||||
<p>Please fill in the form below and we'll get back to you as soon as possible.</p>
|
||||
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<ul class="flashes">
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<form id="{{ model.ID_CONTACT_FORM }}" method="POST" action="{{ url_for('routes_core.contact') }}">
|
||||
<form id="{{ model.ID_CONTACT_FORM }}" method="POST" action="{{ model.HASH_POST_CONTACT_FORM }}">
|
||||
{{ form.csrf_token }}
|
||||
|
||||
<div class="form-grid">
|
||||
@@ -90,27 +49,17 @@
|
||||
{{ model.form_contact.receive_marketing.label }}
|
||||
</div>
|
||||
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_CAPTCHA }}">
|
||||
{# {{ model.form_contact.recaptcha() }} #}
|
||||
{#
|
||||
<altcha-widget
|
||||
challengeurl="https://eu.altcha.org/api/v1/challenge?apiKey={{ model.app.app_config.ALTCHA_API_KEY }}"
|
||||
spamfilter
|
||||
></altcha-widget>
|
||||
#}
|
||||
<div>
|
||||
{{ form.altcha.label }}
|
||||
{#
|
||||
{{ form.altcha }}
|
||||
{{ form.altcha.hidden() }}
|
||||
#}
|
||||
<altcha-widget
|
||||
class="altcha-widget"
|
||||
challengeurl="{{ url_for('routes_core.create_altcha_challenge') }}"
|
||||
challengeurl="{{ model.HASH_GET_ALTCHA_CHALLENGE }}"
|
||||
auto="onload"
|
||||
id="{{ form.altcha.id }}"
|
||||
name="{{ form.altcha.name }}"
|
||||
></altcha-widget>
|
||||
</div>
|
||||
<p>This CAPTCHA mechanism is fully GDPR-compliant with no cookies, no fingerprinting, no tracking, and runs in the background so you don't need to do anything!</p>
|
||||
</div>
|
||||
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
|
||||
{{ model.form_contact.submit() }}
|
||||
@@ -119,74 +68,13 @@
|
||||
|
||||
<div class="data-notice">
|
||||
<h3>How we use your information</h3>
|
||||
<p>We will use the information you provide in this form to:</p>
|
||||
<ul>
|
||||
<li>Respond to your inquiry about our ERP implementation services</li>
|
||||
<li>Create and send you a proposal if requested</li>
|
||||
<li>Contact you regarding your interest in our services</li>
|
||||
</ul>
|
||||
|
||||
<p>If you opt in to marketing communications, we will also use your email address to send you updates about our services, ERPNext features, and relevant industry news. You can unsubscribe from these communications at any time.</p>
|
||||
|
||||
<p>We retain contact form submissions for customer service purposes and retain marketing consent records as required by law. For details about how long we keep your information, please see our <a href="{{ url_for('routes_legal.retention_schedule') }}">data retention schedule</a>.</p>
|
||||
|
||||
<p>For full details about how we handle your personal data, please read our <a href="{{ url_for('routes_legal.privacy_policy') }}">Privacy Policy</a>.</p>
|
||||
<p>We retain contact form submissions for customer service purposes and retain marketing consent records as required by law. For details about how long we keep your information, please see our <a href="{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}">data retention schedule</a>.</p>
|
||||
<p>For full details about how we handle your personal data, please read our <a href="{{ model.HASH_PAGE_PRIVACY_POLICY }}">Privacy Policy</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# included in footer now
|
||||
<section class="contact-details">
|
||||
<div class="{{ model.FLAG_CONTAINER }}">
|
||||
<h2>Our contact details</h2>
|
||||
<div class="expertise-card">
|
||||
<ul>
|
||||
<li>Email: {{ model.get_mail_contact_public() }}</li>
|
||||
<li>LinkedIn: <a href="https://www.linkedin.com/in/teddyms/">linkedin.com/in/teddyms</a></li>
|
||||
<li>GitHub: <a href="https://github.com/Teddy-1024/">github.com/Teddy-1024</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
#}
|
||||
|
||||
{# with CDN
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize ALTCHA widget
|
||||
ALTCHA.init({
|
||||
selector: '.altcha-widget',
|
||||
challenge: {
|
||||
url: '/get-challenge',
|
||||
onSuccess: function(result, element) {
|
||||
// Store the result in the hidden input field
|
||||
const hiddenInput = element.parentNode.querySelector('input[type="hidden"]');
|
||||
hiddenInput.value = JSON.stringify(result);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
#}
|
||||
|
||||
{# with locally stored vendor project - this is now in contact.js
|
||||
<script type="module">
|
||||
import { Altcha } from "{{ url_for('static', filename='js/vendor/altcha.js') }}";
|
||||
window.ALTCHA = { init: (config) => {
|
||||
document.querySelectorAll(config.selector).forEach(el => {
|
||||
new Altcha({
|
||||
target: el,
|
||||
props: {
|
||||
challengeurl: config.challenge.url,
|
||||
auto: 'onload'
|
||||
}
|
||||
}).$on('verified', (e) => {
|
||||
config.challenge.onSuccess(e.detail.payload, el);
|
||||
});
|
||||
});
|
||||
}};
|
||||
</script>
|
||||
#}
|
||||
<script>
|
||||
var flagALTCHAWidget = "{{ model.FLAG_ALTCHA_WIDGET }}";
|
||||
var idContactForm = "#{{ model.ID_CONTACT_FORM }}";
|
||||
|
||||
22
templates/pages/core/_contact_success.html
Normal file
22
templates/pages/core/_contact_success.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% extends 'layouts/layout.html' %}
|
||||
|
||||
{% block page_head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_contact.bundle.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block page_nav_links %}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_body %}
|
||||
|
||||
{% set form = model.form_contact %}
|
||||
<section class="contact-section">
|
||||
<div class="contact-form">
|
||||
<h1>Message Received</h1>
|
||||
<p>Thanks for contacting us! We've received your message and will respond within 48 hours.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -3,10 +3,6 @@
|
||||
{% block title %}{{ model.title }}{% endblock %}
|
||||
|
||||
{% block page_body %}
|
||||
<!-- Include Stylesheet
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/legal.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/legal/accessibility_statement.css') }}">
|
||||
-->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/legal_accessibility_statement.bundle.css') }}">
|
||||
|
||||
<!-- HTML content -->
|
||||
@@ -201,10 +197,9 @@
|
||||
[Note: publishing the test report is optional but doing so may allow you to make your accessibility statement shorter and more focused.]
|
||||
https://www.w3.org/WAI/eval/report-tool/#/
|
||||
-->
|
||||
<p>You can read the full accessibility test report {{ model.URL_HOST }}{{ url_for('routes_legal.accessibility_report') }}.</p>
|
||||
<p>You can read the full accessibility test report {{ model.URL_HOST }}{{ model.HASH_PAGE_ACCESSIBILITY_REPORT }}.</p>
|
||||
</div>
|
||||
|
||||
<!-- Include JavaScript -->
|
||||
<script type="module" src="{{ url_for('static', filename='js/sections/legal.js') }}"></script>
|
||||
<script type="module" src="{{ url_for('static', filename='js/pages/legal/accessibility_statement.js') }}"></script>
|
||||
{% endblock %}
|
||||
@@ -1955,7 +1955,7 @@
|
||||
|
||||
<!--
|
||||
<script>
|
||||
var hashPageCurrent = "{{ model.HASH_PAGE_RETENTION_SCHEDULE }}";
|
||||
var hashPageCurrent = "{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}";
|
||||
|
||||
$(document).ready(function() {
|
||||
hookupPageRetentionSchedule();
|
||||
|
||||
4
todo.txt
4
todo.txt
@@ -1,2 +1,4 @@
|
||||
|
||||
Dark mode / light mode
|
||||
Dark mode / light mode
|
||||
|
||||
git commit -m "Feat: \n 1. Contact Us page form submission success page created. \n 2. Contact Us page styling and CAPTCHA text content. \n 3. Removal of ERP, Google CAPTCHA, and ALTCHA API code and left over comments in JavaScript, Python."
|
||||
Reference in New Issue
Block a user