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
|
# Ignore logs and databases
|
||||||
*.log
|
*.log
|
||||||
|
*.log.*
|
||||||
|
|
||||||
# Ignore logs and databases
|
# Ignore logs and databases
|
||||||
# *.sql
|
# *.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 config import app_config, Config
|
||||||
from controllers.core import routes_core
|
from controllers.core import routes_core
|
||||||
from controllers.legal import routes_legal
|
from controllers.legal import routes_legal
|
||||||
from controllers.user import routes_user
|
|
||||||
from extensions import db, csrf, mail, oauth
|
from extensions import db, csrf, mail, oauth
|
||||||
from helpers.helper_app import Helper_App
|
from helpers.helper_app import Helper_App
|
||||||
# external
|
# external
|
||||||
@@ -109,7 +108,6 @@ with app.app_context():
|
|||||||
|
|
||||||
app.register_blueprint(routes_core)
|
app.register_blueprint(routes_core)
|
||||||
app.register_blueprint(routes_legal)
|
app.register_blueprint(routes_legal)
|
||||||
app.register_blueprint(routes_user)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ class Access_Level(db.Model, Base):
|
|||||||
}
|
}
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, json):
|
def from_json(cls, json):
|
||||||
Helper_App.console_log(f'Access Level.from_json: {json}')
|
|
||||||
access_level = cls()
|
access_level = cls()
|
||||||
access_level.id_access_level = json[cls.ATTR_ID_ACCESS_LEVEL],
|
access_level.id_access_level = json[cls.ATTR_ID_ACCESS_LEVEL],
|
||||||
access_level.code = json[cls.FLAG_CODE],
|
access_level.code = json[cls.FLAG_CODE],
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ class Address(db.Model, Base):
|
|||||||
return jsonify(self.to_json())
|
return jsonify(self.to_json())
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, json):
|
def from_json(cls, json):
|
||||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
|
||||||
address = cls()
|
address = cls()
|
||||||
address.id_address = json[cls.ATTR_ID_ADDRESS],
|
address.id_address = json[cls.ATTR_ID_ADDRESS],
|
||||||
address.region = Region.from_json(json[cls.FLAG_REGION]),
|
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
|
@classmethod
|
||||||
def from_json(cls, json):
|
def from_json(cls, json):
|
||||||
Helper_App.console_log(f'{cls.__name__}.from_json: {json}')
|
|
||||||
plant = cls()
|
plant = cls()
|
||||||
plant.id_region = json[cls.ATTR_ID_REGION]
|
plant.id_region = json[cls.ATTR_ID_REGION]
|
||||||
plant.code = json[cls.FLAG_CODE]
|
plant.code = json[cls.FLAG_CODE]
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ class Unit_Measurement(SQLAlchemy_ABC, Base):
|
|||||||
}
|
}
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, json):
|
def from_json(cls, json):
|
||||||
Helper_App.console_log(f' Unit_Measurement.from_json: {json}')
|
|
||||||
unit = cls()
|
unit = cls()
|
||||||
unit.id_unit_measurement = json[cls.ATTR_ID_UNIT_MEASUREMENT]
|
unit.id_unit_measurement = json[cls.ATTR_ID_UNIT_MEASUREMENT]
|
||||||
unit.name_singular = json[cls.FLAG_NAME_SINGULAR]
|
unit.name_singular = json[cls.FLAG_NAME_SINGULAR]
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ Configuration variables
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# IMPORTS
|
# IMPORTS
|
||||||
from lib import argument_validation as av
|
|
||||||
import os
|
import os
|
||||||
from dotenv import load_dotenv, find_dotenv
|
from dotenv import load_dotenv, find_dotenv
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ Initializes the Flask application, sets the configuration based on the environme
|
|||||||
|
|
||||||
# IMPORTS
|
# IMPORTS
|
||||||
# internal
|
# internal
|
||||||
|
from business_objects.api import API
|
||||||
from datastores.datastore_base import DataStore_Base
|
from datastores.datastore_base import DataStore_Base
|
||||||
from forms.contact import Form_Contact
|
from forms.contact import Form_Contact
|
||||||
from helpers.helper_app import Helper_App
|
from helpers.helper_app import Helper_App
|
||||||
from models.model_view_contact import Model_View_Contact
|
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
|
from models.model_view_home import Model_View_Home
|
||||||
import lib.argument_validation as av
|
import lib.argument_validation as av
|
||||||
# external
|
# external
|
||||||
@@ -51,49 +53,26 @@ def contact():
|
|||||||
form = Form_Contact()
|
form = Form_Contact()
|
||||||
model = Model_View_Contact(form)
|
model = Model_View_Contact(form)
|
||||||
html_body = render_template('pages/core/_contact.html', model = model)
|
html_body = render_template('pages/core/_contact.html', model = model)
|
||||||
except Exception as e:
|
|
||||||
return jsonify(error=str(e)), 403
|
|
||||||
return html_body
|
return html_body
|
||||||
|
|
||||||
@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:
|
except Exception as e:
|
||||||
return f"Error: {e}"
|
return API.get_standard_response(
|
||||||
print(f"Form validation errors: {form.errors}")
|
success = False,
|
||||||
return "Invalid. Failed to submit."
|
status_code = 500,
|
||||||
# html_body = render_template('pages/core/_contact.html', model = model)
|
message = f"Error: {e}",
|
||||||
except Exception as e:
|
data = None,
|
||||||
return jsonify(error=str(e)), 403
|
errors = [str(e)],
|
||||||
|
meta = None
|
||||||
|
)
|
||||||
|
|
||||||
@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():
|
def create_altcha_challenge():
|
||||||
Helper_App.console_log(f'secret key: {current_app.app_config.ALTCHA_SECRET_KEY}')
|
|
||||||
options = ChallengeOptions(
|
options = ChallengeOptions(
|
||||||
expires = datetime.datetime.now() + datetime.timedelta(hours=1),
|
expires = datetime.datetime.now() + datetime.timedelta(hours=1),
|
||||||
max_number = 100000, # The maximum random number
|
max_number = 100000, # The maximum random number
|
||||||
hmac_key = current_app.app_config.ALTCHA_SECRET_KEY,
|
hmac_key = current_app.app_config.ALTCHA_SECRET_KEY,
|
||||||
)
|
)
|
||||||
challenge = create_challenge(options)
|
challenge = create_challenge(options)
|
||||||
print("Challenge created:", challenge)
|
Helper_App.console_log(f"Challenge created: {challenge}")
|
||||||
# return jsonify({"challenge": challenge})
|
# return jsonify({"challenge": challenge})
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"algorithm": challenge.algorithm,
|
"algorithm": challenge.algorithm,
|
||||||
@@ -102,58 +81,64 @@ def create_altcha_challenge():
|
|||||||
"signature": challenge.signature,
|
"signature": challenge.signature,
|
||||||
})
|
})
|
||||||
|
|
||||||
"""
|
@routes_core.route(Model_View_Contact.HASH_PAGE_CONTACT, methods=['POST'])
|
||||||
def verify_altcha_signature(payload):
|
def contact_post():
|
||||||
"" "Verify the ALTCHA signature"" "
|
try:
|
||||||
if 'algorithm' not in payload or 'signature' not in payload or 'verificationData' not in payload:
|
form = Form_Contact()
|
||||||
return False
|
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
|
||||||
|
)
|
||||||
|
|
||||||
algorithm = payload['algorithm']
|
@routes_core.route(Model_View_Contact.HASH_PAGE_CONTACT_SUCCESS, methods=['GET'])
|
||||||
signature = payload['signature']
|
def contact_success():
|
||||||
verification_data = payload['verificationData']
|
try:
|
||||||
|
model = Model_View_Contact_Success()
|
||||||
# Calculate SHA hash of the verification data
|
html_body = render_template('pages/core/_contact_success.html', model = model)
|
||||||
if algorithm == 'SHA-256':
|
return html_body
|
||||||
hash_func = hashlib.sha256
|
except Exception as e:
|
||||||
else:
|
return API.get_standard_response(
|
||||||
# Fallback to SHA-256 if algorithm not specified
|
success = False,
|
||||||
hash_func = hashlib.sha256
|
status_code = 500,
|
||||||
|
message = f"Error: {e}",
|
||||||
# Calculate the hash of verification_data
|
data = None,
|
||||||
data_hash = hash_func(verification_data.encode('utf-8')).digest()
|
errors = [str(e)],
|
||||||
|
meta = None
|
||||||
# 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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
|
|||||||
@@ -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}')
|
Helper_App.console_log(f'result: {result}')
|
||||||
# conn.session.remove()
|
# conn.session.remove()
|
||||||
return result
|
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
|
@staticmethod
|
||||||
def db_cursor_clear(cursor):
|
def db_cursor_clear(cursor):
|
||||||
while cursor.nextset():
|
while cursor.nextset():
|
||||||
Helper_App.console_log(f'new result set: {cursor.fetchall()}')
|
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
|
@staticmethod
|
||||||
def get_user_session():
|
def get_user_session():
|
||||||
Helper_App.console_log('DataStore_Base.get_user_session')
|
Helper_App.console_log('DataStore_Base.get_user_session')
|
||||||
@@ -214,30 +165,6 @@ class DataStore_Base(BaseModel):
|
|||||||
else:
|
else:
|
||||||
expected_columns = set(column.name for column in db.inspect(table_object).columns)
|
expected_columns = set(column.name for column in db.inspect(table_object).columns)
|
||||||
Helper_App.console_log(f'expected_columns: {expected_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
|
max_retries = 3
|
||||||
initial_backoff = 1
|
initial_backoff = 1
|
||||||
for i in range(0, len(records), batch_size):
|
for i in range(0, len(records), batch_size):
|
||||||
@@ -271,17 +198,9 @@ class DataStore_Base(BaseModel):
|
|||||||
filters = Filters_Access_Level()
|
filters = Filters_Access_Level()
|
||||||
av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
||||||
argument_dict = filters.to_json()
|
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)
|
result = cls.db_procedure_execute('p_shop_get_many_access_level', argument_dict)
|
||||||
cursor = result.cursor
|
cursor = result.cursor
|
||||||
Helper_App.console_log('data received')
|
|
||||||
|
|
||||||
# access_levels
|
|
||||||
result_set_1 = cursor.fetchall()
|
result_set_1 = cursor.fetchall()
|
||||||
Helper_App.console_log(f'raw access levels: {result_set_1}')
|
|
||||||
access_levels = []
|
access_levels = []
|
||||||
for row in result_set_1:
|
for row in result_set_1:
|
||||||
new_access_level = Access_Level.from_DB_access_level(row)
|
new_access_level = Access_Level.from_DB_access_level(row)
|
||||||
@@ -290,7 +209,6 @@ class DataStore_Base(BaseModel):
|
|||||||
# Errors
|
# Errors
|
||||||
cursor.nextset()
|
cursor.nextset()
|
||||||
result_set_e = cursor.fetchall()
|
result_set_e = cursor.fetchall()
|
||||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
|
||||||
errors = []
|
errors = []
|
||||||
if len(result_set_e) > 0:
|
if len(result_set_e) > 0:
|
||||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
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()
|
filters = Filters_Unit_Measurement()
|
||||||
av.val_instance(filters, 'filters', _m, Filters_Unit_Measurement)
|
av.val_instance(filters, 'filters', _m, Filters_Unit_Measurement)
|
||||||
argument_dict = filters.to_json()
|
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)
|
result = cls.db_procedure_execute('p_shop_get_many_unit_measurement', argument_dict)
|
||||||
cursor = result.cursor
|
cursor = result.cursor
|
||||||
Helper_App.console_log('data received')
|
|
||||||
|
|
||||||
# units of measurement
|
|
||||||
result_set_1 = cursor.fetchall()
|
result_set_1 = cursor.fetchall()
|
||||||
Helper_App.console_log(f'raw units of measurement: {result_set_1}')
|
|
||||||
units = []
|
units = []
|
||||||
for row in result_set_1:
|
for row in result_set_1:
|
||||||
new_unit = Unit_Measurement.from_DB_unit_measurement(row)
|
new_unit = Unit_Measurement.from_DB_unit_measurement(row)
|
||||||
@@ -327,7 +237,6 @@ class DataStore_Base(BaseModel):
|
|||||||
# Errors
|
# Errors
|
||||||
cursor.nextset()
|
cursor.nextset()
|
||||||
result_set_e = cursor.fetchall()
|
result_set_e = cursor.fetchall()
|
||||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
|
||||||
errors = []
|
errors = []
|
||||||
if len(result_set_e) > 0:
|
if len(result_set_e) > 0:
|
||||||
errors = [SQL_Error.from_DB_record(row) for row in result_set_e] # (row[0], row[1])
|
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
|
'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)
|
result = cls.db_procedure_execute(_m_db_region, argument_dict_list_region)
|
||||||
cursor = result.cursor
|
cursor = result.cursor
|
||||||
Helper_App.console_log('data received')
|
|
||||||
|
|
||||||
# cursor.nextset()
|
|
||||||
result_set_1 = cursor.fetchall()
|
result_set_1 = cursor.fetchall()
|
||||||
regions = []
|
regions = []
|
||||||
for row in result_set_1:
|
for row in result_set_1:
|
||||||
region = Region.from_DB_region(row)
|
region = Region.from_DB_region(row)
|
||||||
regions.append(region)
|
regions.append(region)
|
||||||
Helper_App.console_log(f'regions: {regions}')
|
|
||||||
DataStore_Base.db_cursor_clear(cursor)
|
DataStore_Base.db_cursor_clear(cursor)
|
||||||
cursor.close()
|
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__()
|
super().__init__()
|
||||||
|
|
||||||
def edit_user(self):
|
def edit_user(self):
|
||||||
# redundant argument validation?
|
|
||||||
_m = 'DataStore_User.edit_user'
|
_m = 'DataStore_User.edit_user'
|
||||||
# av.val_instance(filters, 'filters', _m, Filters_Product_Category)
|
|
||||||
|
|
||||||
argument_dict_list = {
|
argument_dict_list = {
|
||||||
'a_id_user': self.info_user.get('sub'),
|
'a_id_user': self.info_user.get('sub'),
|
||||||
@@ -57,12 +55,10 @@ class DataStore_User(DataStore_Base):
|
|||||||
cursor = result.cursor
|
cursor = result.cursor
|
||||||
|
|
||||||
result_set_1 = cursor.fetchall()
|
result_set_1 = cursor.fetchall()
|
||||||
Helper_App.console_log(f'raw user data: {result_set_1}')
|
|
||||||
|
|
||||||
# Errors
|
# Errors
|
||||||
cursor.nextset()
|
cursor.nextset()
|
||||||
result_set_e = cursor.fetchall()
|
result_set_e = cursor.fetchall()
|
||||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
|
||||||
if len(result_set_e) > 0:
|
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]
|
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:
|
for error in errors:
|
||||||
@@ -72,66 +68,11 @@ class DataStore_User(DataStore_Base):
|
|||||||
|
|
||||||
return (result_set_1[0][1] == b'\x01')
|
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):
|
def get_many_user(self, user_filters, user=None):
|
||||||
_m = 'DataStore_User.get_many_user'
|
_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)
|
av.val_instance(user_filters, 'user_filters', _m, Parameters_User)
|
||||||
|
|
||||||
guid = Helper_DB_MySQL.create_guid()
|
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:
|
if user is None:
|
||||||
user = self.get_user_session()
|
user = self.get_user_session()
|
||||||
argument_dict_list = {
|
argument_dict_list = {
|
||||||
@@ -142,92 +83,47 @@ class DataStore_User(DataStore_Base):
|
|||||||
, 'a_debug': 0
|
, 'a_debug': 0
|
||||||
|
|
||||||
}
|
}
|
||||||
# argument_dict_list['a_guid'] = guid
|
|
||||||
result = self.db_procedure_execute('p_get_many_user', argument_dict_list)
|
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
|
cursor = result.cursor
|
||||||
result_set = cursor.fetchall()
|
result_set = cursor.fetchall()
|
||||||
Helper_App.console_log(f'raw users: {result_set}')
|
users = []
|
||||||
Helper_App.console_log(f'type result set: {str(type(result_set))}')
|
if len(result_set) > 0:
|
||||||
Helper_App.console_log(f'len result set: {len(result_set)}')
|
|
||||||
"""
|
|
||||||
user_permission_evals = []
|
|
||||||
for row in result_set:
|
for row in result_set:
|
||||||
user_permission_eval = User_Permission_Evaluation.from_DB_user_eval(row)
|
Helper_App.console_log(f'row: {row}')
|
||||||
user_permission_evals.append(user_permission_eval)
|
user = User.from_DB_user(row)
|
||||||
Helper_App.console_log(f'user_permission_evals: {user_permission_evals}')
|
users.append(user)
|
||||||
"""
|
Helper_App.console_log(f'user {str(type(user))}: {user}')
|
||||||
users = []
|
errors = []
|
||||||
if len(result_set) > 0:
|
cursor.nextset()
|
||||||
for row in result_set:
|
result_set_e = cursor.fetchall()
|
||||||
Helper_App.console_log(f'row: {row}')
|
Helper_App.console_log(f'raw errors: {result_set_e}')
|
||||||
user = User.from_DB_user(row)
|
if len(result_set_e) > 0:
|
||||||
users.append(user)
|
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]
|
||||||
Helper_App.console_log(f'user {str(type(user))}: {user}')
|
for error in errors:
|
||||||
Helper_App.console_log(f'type users: {str(type(users))}\n type user 0: {str(type(None if len(users) == 0 else users[0]))}')
|
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
||||||
# error_list, cursor = self.get_error_list_from_cursor(cursor)
|
|
||||||
errors = []
|
DataStore_User.db_cursor_clear(cursor)
|
||||||
cursor.nextset()
|
|
||||||
result_set_e = cursor.fetchall()
|
return users, errors
|
||||||
Helper_App.console_log(f'raw errors: {result_set_e}')
|
|
||||||
if len(result_set_e) > 0:
|
def get_many_user(self, user_filters, user=None):
|
||||||
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]
|
_m = 'DataStore_User.get_many_user'
|
||||||
for error in errors:
|
av.val_instance(user_filters, 'user_filters', _m, Parameters_User)
|
||||||
Helper_App.console_log(f"Error [{error.code}]: {error.msg}")
|
|
||||||
|
guid = Helper_DB_MySQL.create_guid()
|
||||||
DataStore_User.db_cursor_clear(cursor)
|
if user is None:
|
||||||
|
user = self.get_user_session()
|
||||||
return users, errors
|
argument_dict_list = {
|
||||||
|
# 'a_guid': guid
|
||||||
def get_many_user(self, user_filters, user=None):
|
'a_id_user': user.id_user
|
||||||
_m = 'DataStore_User.get_many_user'
|
, 'a_id_user_auth0': user.id_user_auth0
|
||||||
Helper_App.console_log(_m)
|
, **user_filters.to_json()
|
||||||
# av.val_str(user_filters, 'user_filters', _m)
|
, 'a_debug': 0
|
||||||
# av.val_list(permutations, 'list_permutations', _m, Product_Permutation, 1)
|
|
||||||
av.val_instance(user_filters, 'user_filters', _m, Parameters_User)
|
}
|
||||||
|
result = self.db_procedure_execute('p_get_many_user', argument_dict_list)
|
||||||
guid = Helper_DB_MySQL.create_guid()
|
cursor = result.cursor
|
||||||
# now = datetime.now()
|
result_set = cursor.fetchall()
|
||||||
# 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 = []
|
users = []
|
||||||
if len(result_set) > 0:
|
if len(result_set) > 0:
|
||||||
for row in result_set:
|
for row in result_set:
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from forms.base import Form_Base
|
|||||||
# external
|
# external
|
||||||
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
|
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
|
||||||
from flask_wtf import FlaskForm
|
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
|
from wtforms.validators import DataRequired, Email, ValidationError
|
||||||
import markupsafe
|
import markupsafe
|
||||||
from flask_wtf.recaptcha import RecaptchaField
|
from flask_wtf.recaptcha import RecaptchaField
|
||||||
@@ -76,12 +76,12 @@ class ALTCHAField(Field):
|
|||||||
|
|
||||||
|
|
||||||
class Form_Contact(FlaskForm):
|
class Form_Contact(FlaskForm):
|
||||||
email = StringField('Email')
|
email = EmailField('Email')
|
||||||
contact_name = StringField('Name')
|
contact_name = StringField('Name')
|
||||||
company_name = StringField('Company')
|
company_name = StringField('Company')
|
||||||
message = TextAreaField('Message')
|
message = TextAreaField('Message')
|
||||||
receive_marketing = BooleanField('I would like to receive marketing emails.')
|
receive_marketing = BooleanField('I would like to receive marketing emails.')
|
||||||
# recaptcha = RecaptchaField()
|
# recaptcha = RecaptchaField()
|
||||||
# altcha = HiddenField('ALTCHA') # , validators=[validate_altcha]
|
# altcha = HiddenField('ALTCHA') # , validators=[validate_altcha]
|
||||||
altcha = ALTCHAField('Verification')
|
altcha = ALTCHAField('Verify you are human')
|
||||||
submit = SubmitField('Send Message')
|
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):
|
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)
|
error_msg = error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, "<class 'bool'>", suppress_errors)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return error_msg
|
return error_msg
|
||||||
else:
|
else:
|
||||||
raise ValueError(error_msg)
|
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)
|
error_msg = error_msg_str(method, 'method', my_f, "<class 'str'>", suppress_errors, suppress_console_outputs)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return error_msg
|
return error_msg
|
||||||
else:
|
else:
|
||||||
raise ValueError(error_msg)
|
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)
|
error_msg = error_msg_str(v_name, 'v_name', my_f, "<class 'str'>", suppress_errors, suppress_console_outputs)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return error_msg
|
return error_msg
|
||||||
else:
|
else:
|
||||||
raise ValueError(error_msg)
|
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)
|
error_msg = error_msg_str(v_type, 'v_type', my_f, "<class 'str'>", suppress_errors, suppress_console_outputs)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return error_msg
|
return error_msg
|
||||||
else:
|
else:
|
||||||
raise ValueError(error_msg)
|
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)
|
error_msg = error_msg_str(v_arg_type, 'v_arg_type', my_f, "<class 'str'>", suppress_errors, suppress_console_outputs)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return error_msg
|
return error_msg
|
||||||
else:
|
else:
|
||||||
raise ValueError(error_msg)
|
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:
|
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)
|
error_msg = error_msg_str(suppress_console_outputs, 'suppress_console_outputs', my_f, v_type, suppress_errors)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
v_type = "<class 'str'>"
|
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)
|
error_msg = error_msg_str(method, 'method', my_f, v_type, suppress_errors, suppress_console_outputs)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
my_f = method + '.' + my_f
|
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)
|
error_msg = error_msg_str(v_name, 'v_name', my_f, v_type, suppress_errors, suppress_console_outputs)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
# v_arg_type
|
# 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)
|
error_msg = error_msg_str(v_arg_type, 'v_arg_type', my_f, v_type, suppress_errors, suppress_console_outputs)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
raise ValueError(error_msg)
|
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)
|
error_msg = error_msg_str(v_input, v_name, method, v_type, suppress_errors, suppress_console_outputs)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
# RETURNS
|
# 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)
|
val_bool(suppress_errors, 'suppress_errors', my_f)
|
||||||
# suppress_console_outputs
|
# suppress_console_outputs
|
||||||
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
|
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
|
return False
|
||||||
# method
|
# method
|
||||||
valid = True
|
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)
|
error_msg = error_msg_str(method, 'method', my_f, v_type)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
my_f = method + '.' + my_f
|
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)
|
error_msg = error_msg_str(v_name, 'v_name', my_f, v_type)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
# v_arg_type
|
# 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)
|
error_msg = error_msg_str(v_arg_type, 'v_arg_type', my_f, v_type)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
# min_len
|
# 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)
|
error_msg = error_msg_str(min_len, 'min_len', my_f, v_type)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
# max_len
|
# 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)
|
error_msg = error_msg_str(max_len, 'max_len', my_f, v_type)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
# v_input
|
# 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)
|
L = len(v_input)
|
||||||
if min_len != -1 and L < min_len:
|
if min_len != -1 and L < min_len:
|
||||||
valid = False
|
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:
|
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
|
valid = False
|
||||||
if not valid:
|
if not valid:
|
||||||
error_msg = error_msg_str(v_input, v_name, method, v_type, suppress_errors, suppress_console_outputs, v_arg_type)
|
error_msg = error_msg_str(v_input, v_name, method, v_type, suppress_errors, suppress_console_outputs, v_arg_type)
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
# RETURNS
|
# 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)
|
val_bool(suppress_errors, 'suppress_errors', my_f)
|
||||||
# suppress_console_outputs
|
# suppress_console_outputs
|
||||||
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
|
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
|
return False
|
||||||
# method
|
# method
|
||||||
if not val_str(method, 'method', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
|
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 not mytype == str(type(v_input)):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
if (v_min != None and v_max != None):
|
if (v_min != None and v_max != None):
|
||||||
if (v_min > v_max):
|
if (v_min > v_max):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
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
|
return False
|
||||||
raise ValueError(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
raise ValueError(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
||||||
if (v_min != None):
|
if (v_min != None):
|
||||||
if (v_input < v_min):
|
if (v_input < v_min):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
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
|
return False
|
||||||
raise ValueError(error_msg + f"\nValue less than minimum {v_min}.")
|
raise ValueError(error_msg + f"\nValue less than minimum {v_min}.")
|
||||||
if (v_max != None):
|
if (v_max != None):
|
||||||
if (v_input > v_max):
|
if (v_input > v_max):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
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
|
return False
|
||||||
raise ValueError(error_msg + f"\nValue greater than maximum {v_max}.")
|
raise ValueError(error_msg + f"\nValue greater than maximum {v_max}.")
|
||||||
# RETURNS
|
# 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)
|
val_bool(suppress_errors, 'suppress_errors', my_f)
|
||||||
# suppress_console_outputs
|
# suppress_console_outputs
|
||||||
if not val_bool(suppress_console_outputs, 'suppress_console_outputs', my_f, suppress_errors):
|
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
|
return False
|
||||||
# v_name
|
# v_name
|
||||||
if not val_str(v_name, 'v_name', my_f, 1, -1, suppress_errors, suppress_console_outputs): return False
|
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 not mytype == str(type(v_input)):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return False
|
return False
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
if (v_min != None and v_max != None):
|
if (v_min != None and v_max != None):
|
||||||
if (v_min > v_max):
|
if (v_min > v_max):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
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
|
return False
|
||||||
raise ValueError(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
raise ValueError(error_msg + f"\nInverted minimum and maximum values {v_min} and {v_max}.")
|
||||||
if (v_min != None):
|
if (v_min != None):
|
||||||
if (v_input < v_min):
|
if (v_input < v_min):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
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
|
return False
|
||||||
raise ValueError(error_msg + f"\nValue less than minimum {v_min}.")
|
raise ValueError(error_msg + f"\nValue less than minimum {v_min}.")
|
||||||
if (v_max != None):
|
if (v_max != None):
|
||||||
if (v_input > v_max):
|
if (v_input > v_max):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
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
|
return False
|
||||||
raise ValueError(error_msg + f"\nValue greater than maximum {v_max}.")
|
raise ValueError(error_msg + f"\nValue greater than maximum {v_max}.")
|
||||||
# RETURNS
|
# 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 not val_str(v_input, v_name, my_f, suppress_errors=True, suppress_console_outputs=True):
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return None
|
return None
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
else:
|
else:
|
||||||
@@ -471,7 +471,7 @@ def input_bool(v_input, v_name, method, suppress_errors = False, suppress_consol
|
|||||||
return False
|
return False
|
||||||
if suppress_errors:
|
if suppress_errors:
|
||||||
if not suppress_console_outputs:
|
if not suppress_console_outputs:
|
||||||
print(error_msg)
|
Helper_App.console_log(error_msg)
|
||||||
return None
|
return None
|
||||||
raise ValueError(error_msg)
|
raise ValueError(error_msg)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -47,6 +47,17 @@ class Model_View_Base(BaseModel, ABC):
|
|||||||
ATTR_VALUE_PREVIOUS: ClassVar[str] = 'previous-value'
|
ATTR_VALUE_PREVIOUS: ClassVar[str] = 'previous-value'
|
||||||
COMPANY_ADDRESS_SHORT: ClassVar[str] = '53 Alfred Green Close, Rugby, United Kingdom, CV22 6DN'
|
COMPANY_ADDRESS_SHORT: ClassVar[str] = '53 Alfred Green Close, Rugby, United Kingdom, CV22 6DN'
|
||||||
COMPANY_NUMBER: ClassVar[str] = '13587499'
|
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: ClassVar[str] = 'access_level'
|
||||||
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = Base.FLAG_ACCESS_LEVEL_REQUIRED
|
FLAG_ACCESS_LEVEL_REQUIRED: ClassVar[str] = Base.FLAG_ACCESS_LEVEL_REQUIRED
|
||||||
FLAG_ACTIVE: ClassVar[str] = Base.FLAG_ACTIVE
|
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_BUTTON_PRIMARY: ClassVar[str] = 'button-primary'
|
||||||
FLAG_CANCEL: ClassVar[str] = 'button-cancel'
|
FLAG_CANCEL: ClassVar[str] = 'button-cancel'
|
||||||
FLAG_CALLBACK: ClassVar[str] = 'callback'
|
FLAG_CALLBACK: ClassVar[str] = 'callback'
|
||||||
|
FLAG_CAPTCHA: ClassVar[str] = 'captcha'
|
||||||
FLAG_CARD: ClassVar[str] = 'card'
|
FLAG_CARD: ClassVar[str] = 'card'
|
||||||
FLAG_CITY: ClassVar[str] = Base.FLAG_CITY
|
FLAG_CITY: ClassVar[str] = Base.FLAG_CITY
|
||||||
FLAG_CLOSE_TEMPORARY_ELEMENT: ClassVar[str] = 'button-temporary-element-close'
|
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_ATTR_OPTION_VALUE: ClassVar[str] = Base.FLAG_NAME_ATTR_OPTION_VALUE
|
||||||
FLAG_NAME_PLURAL: ClassVar[str] = Base.FLAG_NAME_PLURAL
|
FLAG_NAME_PLURAL: ClassVar[str] = Base.FLAG_NAME_PLURAL
|
||||||
# FLAG_NAME_SINGULAR: ClassVar[str] = Base.FLAG_NAME_SINGULAR
|
# 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_CONTACT: ClassVar[str] = 'navContact'
|
||||||
FLAG_NAV_HOME: ClassVar[str] = 'navHome'
|
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_OVERLAY: ClassVar[str] = 'overlay'
|
||||||
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
|
FLAG_PAGE_BODY: ClassVar[str] = 'page-body'
|
||||||
FLAG_PHONE_NUMBER: ClassVar[str] = Base.FLAG_PHONE_NUMBER
|
FLAG_PHONE_NUMBER: ClassVar[str] = Base.FLAG_PHONE_NUMBER
|
||||||
FLAG_POSTCODE: ClassVar[str] = Base.FLAG_POSTCODE
|
FLAG_POSTCODE: ClassVar[str] = Base.FLAG_POSTCODE
|
||||||
FLAG_CAPTCHA: ClassVar[str] = 'recaptcha'
|
|
||||||
FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
|
FLAG_RIGHT_HAND_SIDE: ClassVar[str] = 'rhs'
|
||||||
FLAG_ROW: ClassVar[str] = 'row'
|
FLAG_ROW: ClassVar[str] = 'row'
|
||||||
FLAG_ROW_NEW: ClassVar[str] = 'row-new'
|
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_TEMPORARY_ELEMENT: ClassVar[str] = 'temporary-element'
|
||||||
FLAG_USER: ClassVar[str] = User.FLAG_USER
|
FLAG_USER: ClassVar[str] = User.FLAG_USER
|
||||||
FLAG_WEBSITE: ClassVar[str] = Base.FLAG_WEBSITE
|
FLAG_WEBSITE: ClassVar[str] = Base.FLAG_WEBSITE
|
||||||
# flagIsDatePicker: ClassVar[str] = 'is-date-picker'
|
HASH_GET_ALTCHA_CHALLENGE: ClassVar[str] = '/altcha/create-challenge'
|
||||||
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_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = '/accessibility-report'
|
HASH_PAGE_ACCESSIBILITY_REPORT: ClassVar[str] = '/accessibility-report'
|
||||||
HASH_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = '/accessibility-statement'
|
HASH_PAGE_ACCESSIBILITY_STATEMENT: ClassVar[str] = '/accessibility-statement'
|
||||||
HASH_PAGE_ADMIN_HOME: ClassVar[str] = '/admin'
|
|
||||||
HASH_PAGE_CONTACT: ClassVar[str] = '/contact'
|
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_DATA_RETENTION_SCHEDULE: ClassVar[str] = '/retention-schedule'
|
||||||
HASH_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = '/error'
|
HASH_PAGE_ERROR_NO_PERMISSION: ClassVar[str] = '/error'
|
||||||
HASH_PAGE_HOME: ClassVar[str] = '/'
|
HASH_PAGE_HOME: ClassVar[str] = '/'
|
||||||
HASH_PAGE_LICENSE: ClassVar[str] = '/license'
|
HASH_PAGE_LICENSE: ClassVar[str] = '/license'
|
||||||
HASH_PAGE_PRIVACY_POLICY: ClassVar[str] = '/privacy-policy'
|
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_ADD: ClassVar[str] = 'buttonAdd'
|
||||||
ID_BUTTON_APPLY_FILTERS: ClassVar[str] = 'buttonApplyFilters'
|
ID_BUTTON_APPLY_FILTERS: ClassVar[str] = 'buttonApplyFilters'
|
||||||
ID_BUTTON_CANCEL: ClassVar[str] = 'buttonCancel'
|
ID_BUTTON_CANCEL: ClassVar[str] = 'buttonCancel'
|
||||||
@@ -174,24 +158,8 @@ class Model_View_Base(BaseModel, ABC):
|
|||||||
ID_BUTTON_SAVE: ClassVar[str] = 'buttonSave'
|
ID_BUTTON_SAVE: ClassVar[str] = 'buttonSave'
|
||||||
ID_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
ID_CSRF_TOKEN: ClassVar[str] = 'X-CSRFToken'
|
||||||
ID_FORM_CONTACT: ClassVar[str] = 'formContact'
|
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_FILTERS: ClassVar[str] = 'formFilters'
|
||||||
ID_FORM_IS_INCLUDED_VAT: ClassVar[str] = 'formIsIncludedVAT'
|
|
||||||
ID_LABEL_ERROR: ClassVar[str] = 'labelError'
|
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_CONFIRM: ClassVar[str] = 'overlayConfirm'
|
||||||
ID_OVERLAY_ERROR: ClassVar[str] = 'overlayError'
|
ID_OVERLAY_ERROR: ClassVar[str] = 'overlayError'
|
||||||
ID_OVERLAY_HAMBURGER: ClassVar[str] = 'overlayHamburger'
|
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: ClassVar[str] = 'Precision And Research Technology Systems Limited'
|
||||||
NAME_COMPANY_SHORT: ClassVar[str] = 'PARTS Ltd'
|
NAME_COMPANY_SHORT: ClassVar[str] = 'PARTS Ltd'
|
||||||
NAME_CSRF_TOKEN: ClassVar[str] = 'csrf-token'
|
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_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
|
hash_page_current: str
|
||||||
# """
|
|
||||||
app: Flask = None
|
app: Flask = None
|
||||||
session: None = None
|
session: None = None
|
||||||
is_page_store: bool = None
|
is_page_store: bool = None
|
||||||
@@ -232,48 +187,18 @@ class Model_View_Base(BaseModel, ABC):
|
|||||||
def title(self):
|
def title(self):
|
||||||
pass
|
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):
|
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)
|
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
|
self.app = current_app
|
||||||
with self.app.app_context():
|
with self.app.app_context():
|
||||||
self.session = session
|
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
|
self.is_page_store = False
|
||||||
Helper_App.console_log(f'session: {self.session}')
|
Helper_App.console_log(f'session: {self.session}')
|
||||||
|
|
||||||
datastore_user = DataStore_User()
|
datastore_user = DataStore_User()
|
||||||
self.user = datastore_user.get_user_session()
|
self.user = datastore_user.get_user_session()
|
||||||
self.is_user_logged_in = self.user.is_logged_in
|
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):
|
def output_bool(self, boolean):
|
||||||
return str(boolean).lower()
|
return str(boolean).lower()
|
||||||
@@ -285,34 +210,6 @@ class Model_View_Base(BaseModel, ABC):
|
|||||||
datastore_user = DataStore_User()
|
datastore_user = DataStore_User()
|
||||||
return datastore_user.get_user_session()
|
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):
|
def get_many_access_level(self, filters=None):
|
||||||
_m = 'Model_View_Store.get_many_access_level'
|
_m = 'Model_View_Store.get_many_access_level'
|
||||||
# av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
# av.val_instance(filters, 'filters', _m, Filters_Access_Level)
|
||||||
@@ -358,7 +255,6 @@ class Model_View_Base(BaseModel, ABC):
|
|||||||
if preview_str != '':
|
if preview_str != '':
|
||||||
preview_str += '\n'
|
preview_str += '\n'
|
||||||
obj_json = obj.to_json()
|
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]]
|
preview_str += obj_json[obj_json[Base.FLAG_NAME_ATTR_OPTION_TEXT]]
|
||||||
return preview_str
|
return preview_str
|
||||||
@staticmethod
|
@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)
|
|
||||||
@@ -4,19 +4,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.contact-form {
|
.contact-form {
|
||||||
max-width: 800px;
|
max-width: 60vw;
|
||||||
|
width: fit-content;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
|
.contact-form textarea {
|
||||||
|
max-width: 40vw;
|
||||||
|
}
|
||||||
|
|
||||||
.form-grid {
|
.form-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 200px 1fr;
|
grid-template-columns: 200px 1fr;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-label {
|
.form-label {
|
||||||
@@ -36,13 +40,32 @@ textarea.form-input {
|
|||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.marketing-consent {
|
.marketing-consent input {
|
||||||
margin: 2rem 0;
|
display: inline-block;
|
||||||
padding-left: 200px;
|
margin-left: 18vw;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.recaptcha {
|
.container.captcha > div:first-child {
|
||||||
margin-left: 15vw;
|
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"] {
|
input[type="submit"] {
|
||||||
@@ -73,7 +96,17 @@ input[type="submit"]:hover {
|
|||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.data-notice ul li {
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
.contact-form {
|
||||||
|
max-width: 80vw;
|
||||||
|
}
|
||||||
|
.contact-form textarea {
|
||||||
|
max-width: 60vw;
|
||||||
|
}
|
||||||
.form-grid {
|
.form-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 0.5rem;
|
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 {
|
.contact-form {
|
||||||
max-width: 800px;
|
max-width: 60vw;
|
||||||
|
width: fit-content;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
|
.contact-form textarea {
|
||||||
|
max-width: 40vw;
|
||||||
|
}
|
||||||
|
|
||||||
.form-grid {
|
.form-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 200px 1fr;
|
grid-template-columns: 200px 1fr;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-label {
|
.form-label {
|
||||||
@@ -36,13 +40,32 @@ textarea.form-input {
|
|||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.marketing-consent {
|
.marketing-consent input {
|
||||||
margin: 2rem 0;
|
display: inline-block;
|
||||||
padding-left: 200px;
|
margin-left: 18vw;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.recaptcha {
|
.container.captcha > div:first-child {
|
||||||
margin-left: 15vw;
|
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"] {
|
input[type="submit"] {
|
||||||
@@ -73,7 +96,17 @@ input[type="submit"]:hover {
|
|||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.data-notice ul li {
|
||||||
|
list-style-position: inside;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
.contact-form {
|
||||||
|
max-width: 80vw;
|
||||||
|
}
|
||||||
|
.contact-form textarea {
|
||||||
|
max-width: 60vw;
|
||||||
|
}
|
||||||
.form-grid {
|
.form-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 0.5rem;
|
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:
|
top:
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0.75rem 1.5rem;
|
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);
|
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) {
|
function videoPlay(elemVideo) {
|
||||||
if (!_loading) { // elemVideo.paused &&
|
if (!_loading) { // elemVideo.paused &&
|
||||||
elemVideo.play();
|
elemVideo.play();
|
||||||
if (_verbose) { console.log("Playing video element: " + elemVideo.name)};
|
Utils.consoleLogIfNotProductionEnvironment("Playing video element: " + elemVideo.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function videoPause(elemVideo) {
|
function videoPause(elemVideo) {
|
||||||
elemVideo.pause();
|
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";
|
import Validation from "./lib/validation.js";
|
||||||
|
|
||||||
export default class DOM {
|
export default class DOM {
|
||||||
@@ -138,18 +139,10 @@ export default class DOM {
|
|||||||
debugger;
|
debugger;
|
||||||
if (Validation.isEmpty(element)) return null;
|
if (Validation.isEmpty(element)) return null;
|
||||||
return element.getAttribute(attrValueCurrent);
|
return element.getAttribute(attrValueCurrent);
|
||||||
if (!Validation.isEmpty(value) && element.type === "checkbox") {
|
|
||||||
value = (value === 'true');
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
static getElementAttributeValuePrevious(element) {
|
static getElementAttributeValuePrevious(element) {
|
||||||
if (Validation.isEmpty(element)) return null;
|
if (Validation.isEmpty(element)) return null;
|
||||||
return element.getAttribute(attrValuePrevious);
|
return element.getAttribute(attrValuePrevious);
|
||||||
if (!Validation.isEmpty(value) && element.type === "checkbox") {
|
|
||||||
value = (value === 'true');
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
/* base_table.handleChangeElementCellTable
|
/* base_table.handleChangeElementCellTable
|
||||||
static updateAndCheckIsTableElementDirty(element) {
|
static updateAndCheckIsTableElementDirty(element) {
|
||||||
@@ -158,28 +151,17 @@ export default class DOM {
|
|||||||
let wasDirtyRow = DOM.hasDirtyChildrenNotDeletedContainer(row);
|
let wasDirtyRow = DOM.hasDirtyChildrenNotDeletedContainer(row);
|
||||||
let isDirty = DOM.updateAndCheckIsElementDirty(element);
|
let isDirty = DOM.updateAndCheckIsElementDirty(element);
|
||||||
let cell = DOM.getCellFromElement(element);
|
let cell = DOM.getCellFromElement(element);
|
||||||
console.log({element, row, cell, isDirty, wasDirty});
|
Utils.consoleLogIfNotProductionEnvironment({element, row, cell, isDirty, wasDirty});
|
||||||
if (isDirty != wasDirty) {
|
if (isDirty != wasDirty) {
|
||||||
DOM.handleDirtyElement(cell, isDirty);
|
DOM.handleDirtyElement(cell, isDirty);
|
||||||
let isDirtyRow = DOM.hasDirtyChildrenNotDeletedContainer(row);
|
let isDirtyRow = DOM.hasDirtyChildrenNotDeletedContainer(row);
|
||||||
console.log({isDirtyRow, wasDirtyRow});
|
Utils.consoleLogIfNotProductionEnvironment({isDirtyRow, wasDirtyRow});
|
||||||
if (isDirtyRow != wasDirtyRow) {
|
if (isDirtyRow != wasDirtyRow) {
|
||||||
DOM.handleDirtyElement(row, isDirtyRow);
|
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) {
|
static scrollToElement(parent, element) {
|
||||||
// REQUIRED: parent has scroll-bar
|
// REQUIRED: parent has scroll-bar
|
||||||
parent.scrollTop(parent.scrollTop() + (element.offset().top - parent.offset().top));
|
parent.scrollTop(parent.scrollTop() + (element.offset().top - parent.offset().top));
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
import Utils from '../utils.js';
|
||||||
|
|
||||||
export default class BusinessObjects {
|
export default class BusinessObjects {
|
||||||
static getOptionJsonFromObjectJsonAndKeys(objectJson, keyText, keyValue, valueSelected = null) {
|
static getOptionJsonFromObjectJsonAndKeys(objectJson, keyText, keyValue, valueSelected = null) {
|
||||||
@@ -11,16 +12,9 @@ export default class BusinessObjects {
|
|||||||
static getOptionJsonFromObjectJson(objectJson, valueSelected = null) {
|
static getOptionJsonFromObjectJson(objectJson, valueSelected = null) {
|
||||||
let keyText = objectJson[flagNameAttrOptionText];
|
let keyText = objectJson[flagNameAttrOptionText];
|
||||||
let keyValue = objectJson[flagNameAttrOptionValue];
|
let keyValue = objectJson[flagNameAttrOptionValue];
|
||||||
if (_verbose) { console.log({objectJson, keyText, keyValue}); };
|
Utils.consoleLogIfNotProductionEnvironment({objectJson, keyText, keyValue});
|
||||||
return BusinessObjects.getOptionJsonFromObjectJsonAndKeys(objectJson, keyText, keyValue, valueSelected);
|
return BusinessObjects.getOptionJsonFromObjectJsonAndKeys(objectJson, keyText, keyValue, valueSelected);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
static getOptionJsonFromProductPermutation(permutation) {
|
|
||||||
return {
|
|
||||||
text: permutation
|
|
||||||
};
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
static getObjectText(objectJson) {
|
static getObjectText(objectJson) {
|
||||||
return objectJson == null ? '' : objectJson[objectJson[flagNameAttrOptionText]];
|
return objectJson == null ? '' : objectJson[objectJson[flagNameAttrOptionText]];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,9 @@ export default class Utils {
|
|||||||
}
|
}
|
||||||
return list;
|
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 LocalStorage from "../lib/local_storage.js";
|
||||||
import API from "../api.js";
|
import API from "../api.js";
|
||||||
import DOM from "../dom.js";
|
import DOM from "../dom.js";
|
||||||
|
import Utils from "../lib/utils.js";
|
||||||
|
|
||||||
import OverlayConfirm from "../components/common/temporary/overlay_confirm.js";
|
import OverlayConfirm from "../components/common/temporary/overlay_confirm.js";
|
||||||
import OverlayError from "../components/common/temporary/overlay_error.js";
|
import OverlayError from "../components/common/temporary/overlay_error.js";
|
||||||
@@ -14,11 +15,10 @@ export default class BasePage {
|
|||||||
throw new Error("Router is required");
|
throw new Error("Router is required");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (_verbose) { console.log("initialising with router: ", router); }
|
Utils.consoleLogIfNotProductionEnvironment("initialising with router: ", router);
|
||||||
}
|
}
|
||||||
this.router = router;
|
this.router = router;
|
||||||
this.title = titlePageCurrent;
|
this.title = titlePageCurrent;
|
||||||
// this.hash = hashPageCurrent;
|
|
||||||
if (this.constructor === BasePage) {
|
if (this.constructor === BasePage) {
|
||||||
throw new Error("Cannot instantiate abstract class");
|
throw new Error("Cannot instantiate abstract class");
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ export default class BasePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logInitialisation() {
|
logInitialisation() {
|
||||||
if (_verbose) { console.log('Initializing ' + this.title + ' page'); }
|
Utils.consoleLogIfNotProductionEnvironment('Initializing ' + this.title + ' page');
|
||||||
}
|
}
|
||||||
|
|
||||||
hookupCommonElements() {
|
hookupCommonElements() {
|
||||||
@@ -58,7 +58,7 @@ export default class BasePage {
|
|||||||
|
|
||||||
hookupLogos() {
|
hookupLogos() {
|
||||||
this.hookupEventHandler("click", "." + flagImageLogo + "," + "." + flagLogo, (event, element) => {
|
this.hookupEventHandler("click", "." + flagImageLogo + "," + "." + flagLogo, (event, element) => {
|
||||||
if (_verbose) { console.log('clicking logo'); }
|
Utils.consoleLogIfNotProductionEnvironment('clicking logo');
|
||||||
this.router.navigateToHash(hashPageHome);
|
this.router.navigateToHash(hashPageHome);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -81,15 +81,14 @@ export default class BasePage {
|
|||||||
Events.initialiseEventHandler('form.' + flagFilter + ' button.' + flagSave, flagInitialised, (button) => {
|
Events.initialiseEventHandler('form.' + flagFilter + ' button.' + flagSave, flagInitialised, (button) => {
|
||||||
button.addEventListener("click", (event) => {
|
button.addEventListener("click", (event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (_verbose) { console.log('saving page: ', this.title); }
|
Utils.consoleLogIfNotProductionEnvironment('saving page: ', this.title);
|
||||||
OverlayConfirm.show();
|
OverlayConfirm.show();
|
||||||
});
|
});
|
||||||
// button.classList.add(flagCollapsed);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
leave() {
|
leave() {
|
||||||
if (_verbose) { console.log('Leaving ' + this.title + ' page'); }
|
Utils.consoleLogIfNotProductionEnvironment('Leaving ' + this.title + ' page');
|
||||||
if (this.constructor === BasePage) {
|
if (this.constructor === BasePage) {
|
||||||
throw new Error("Must implement leave() method.");
|
throw new Error("Must implement leave() method.");
|
||||||
}
|
}
|
||||||
@@ -107,11 +106,11 @@ export default class BasePage {
|
|||||||
if (show) {
|
if (show) {
|
||||||
buttonCancel.classList.remove(flagCollapsed);
|
buttonCancel.classList.remove(flagCollapsed);
|
||||||
buttonSave.classList.remove(flagCollapsed);
|
buttonSave.classList.remove(flagCollapsed);
|
||||||
if (_verbose) { console.log('showing buttons'); }
|
Utils.consoleLogIfNotProductionEnvironment('showing buttons');
|
||||||
} else {
|
} else {
|
||||||
buttonCancel.classList.add(flagCollapsed);
|
buttonCancel.classList.add(flagCollapsed);
|
||||||
buttonSave.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();
|
if (isDirty) document.querySelectorAll(idTableMain + ' tbody tr').remove();
|
||||||
return isDirty;
|
return isDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ export default class TableBasePage extends BasePage {
|
|||||||
getAndLoadFilteredTableContentSinglePageApp() {
|
getAndLoadFilteredTableContentSinglePageApp() {
|
||||||
this.callFilterTableContent()
|
this.callFilterTableContent()
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (_verbose) { console.log('Table data received:', data); }
|
Utils.consoleLogIfNotProductionEnvironment('Table data received:', data);
|
||||||
this.callbackLoadTableContent(data);
|
this.callbackLoadTableContent(data);
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Error:', error));
|
.catch(error => console.error('Error:', error));
|
||||||
@@ -144,13 +144,13 @@ export default class TableBasePage extends BasePage {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
if (data[flagStatus] == flagSuccess) {
|
if (data[flagStatus] == flagSuccess) {
|
||||||
if (_verbose) {
|
if (_verbose) {
|
||||||
console.log('Records saved!');
|
Utils.consoleLogIfNotProductionEnvironment('Records saved!');
|
||||||
console.log('Data received:', data);
|
Utils.consoleLogIfNotProductionEnvironment('Data received:', data);
|
||||||
}
|
}
|
||||||
this.callFilterTableContent();
|
this.callFilterTableContent();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (_verbose) { console.log("error: ", data[flagMessage]); }
|
Utils.consoleLogIfNotProductionEnvironment("error: ", data[flagMessage]);
|
||||||
OverlayError.show(data[flagMessage]);
|
OverlayError.show(data[flagMessage]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -181,13 +181,13 @@ export default class TableBasePage extends BasePage {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
if (data[flagStatus] == flagSuccess) {
|
if (data[flagStatus] == flagSuccess) {
|
||||||
if (_verbose) {
|
if (_verbose) {
|
||||||
console.log('Records saved!');
|
Utils.consoleLogIfNotProductionEnvironment('Records saved!');
|
||||||
console.log('Data received:', data);
|
Utils.consoleLogIfNotProductionEnvironment('Data received:', data);
|
||||||
}
|
}
|
||||||
this.callbackLoadTableContent(data);
|
this.callbackLoadTableContent(data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (_verbose) { console.log("error: ", data[flagMessage]); }
|
Utils.consoleLogIfNotProductionEnvironment("error: ", data[flagMessage]);
|
||||||
OverlayError.show(data[flagMessage]);
|
OverlayError.show(data[flagMessage]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -236,7 +236,7 @@ export default class TableBasePage extends BasePage {
|
|||||||
cacheRowBlank() {
|
cacheRowBlank() {
|
||||||
let selectorRowNew = idTableMain + ' tbody tr.' + flagRowNew;
|
let selectorRowNew = idTableMain + ' tbody tr.' + flagRowNew;
|
||||||
let rowBlankTemp = document.querySelector(selectorRowNew);
|
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;
|
let countRows = document.querySelectorAll(idTableMain + ' > tbody > tr').length;
|
||||||
_rowBlank = rowBlankTemp.cloneNode(true);
|
_rowBlank = rowBlankTemp.cloneNode(true);
|
||||||
document.querySelectorAll(selectorRowNew).forEach(function(row) {
|
document.querySelectorAll(selectorRowNew).forEach(function(row) {
|
||||||
@@ -257,23 +257,6 @@ export default class TableBasePage extends BasePage {
|
|||||||
}
|
}
|
||||||
hookupSlidersDisplayOrderTable() {
|
hookupSlidersDisplayOrderTable() {
|
||||||
let selectorDisplayOrder = idTableMain + ' tbody tr td.' + flagDisplayOrder + ' input.' + flagSlider + '.' + flagDisplayOrder;
|
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);
|
this.hookupChangeHandlerTableCells(selectorDisplayOrder);
|
||||||
}
|
}
|
||||||
hookupChangeHandlerTableCells(inputSelector, handler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
hookupChangeHandlerTableCells(inputSelector, handler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
||||||
@@ -283,7 +266,6 @@ export default class TableBasePage extends BasePage {
|
|||||||
});
|
});
|
||||||
handler(null, input);
|
handler(null, input);
|
||||||
});
|
});
|
||||||
// this.hookupEventHandler("change", inputSelector, handler);
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
handleChangeElementCellTable(event, element) {
|
handleChangeElementCellTable(event, element) {
|
||||||
@@ -339,15 +321,15 @@ export default class TableBasePage extends BasePage {
|
|||||||
let wasDirtyRowTable = DOM.hasDirtyChildrenContainer(rowTable);
|
let wasDirtyRowTable = DOM.hasDirtyChildrenContainer(rowTable);
|
||||||
let wasDirtyElement = element.classList.contains(flagDirty);
|
let wasDirtyElement = element.classList.contains(flagDirty);
|
||||||
let isDirtyElement = DOM.updateAndCheckIsElementDirty(element);
|
let isDirtyElement = DOM.updateAndCheckIsElementDirty(element);
|
||||||
console.log({isDirtyElement, wasDirtyElement});
|
Utils.consoleLogIfNotProductionEnvironment({isDirtyElement, wasDirtyElement});
|
||||||
if (isDirtyElement != wasDirtyElement) {
|
if (isDirtyElement != wasDirtyElement) {
|
||||||
DOM.handleDirtyElement(td, isDirtyElement);
|
DOM.handleDirtyElement(td, isDirtyElement);
|
||||||
let isNowDirtyRowSubtable = DOM.hasDirtyChildrenContainer(rowSubtable);
|
let isNowDirtyRowSubtable = DOM.hasDirtyChildrenContainer(rowSubtable);
|
||||||
console.log({isNowDirtyRowSubtable, wasDirtyRowSubtable});
|
Utils.consoleLogIfNotProductionEnvironment({isNowDirtyRowSubtable, wasDirtyRowSubtable});
|
||||||
if (isNowDirtyRowSubtable != wasDirtyRowSubtable) {
|
if (isNowDirtyRowSubtable != wasDirtyRowSubtable) {
|
||||||
DOM.handleDirtyElement(rowSubtable, isNowDirtyRowSubtable);
|
DOM.handleDirtyElement(rowSubtable, isNowDirtyRowSubtable);
|
||||||
let isNowDirtyRowTable = DOM.hasDirtyChildrenContainer(rowTable);
|
let isNowDirtyRowTable = DOM.hasDirtyChildrenContainer(rowTable);
|
||||||
console.log({isNowDirtyRowTable, wasDirtyRowTable});
|
Utils.consoleLogIfNotProductionEnvironment({isNowDirtyRowTable, wasDirtyRowTable});
|
||||||
if (isNowDirtyRowTable != wasDirtyRowTable) {
|
if (isNowDirtyRowTable != wasDirtyRowTable) {
|
||||||
DOM.handleDirtyElement(rowTable, isNowDirtyRowTable);
|
DOM.handleDirtyElement(rowTable, isNowDirtyRowTable);
|
||||||
let rows = this.getTableRecords(true);
|
let rows = this.getTableRecords(true);
|
||||||
@@ -362,7 +344,7 @@ export default class TableBasePage extends BasePage {
|
|||||||
let wasDirtyParentRows = this.getAllIsDirtyRowsInParentTree(element);
|
let wasDirtyParentRows = this.getAllIsDirtyRowsInParentTree(element);
|
||||||
let wasDirtyElement = element.classList.contains(flagDirty);
|
let wasDirtyElement = element.classList.contains(flagDirty);
|
||||||
let isDirtyElement = DOM.updateAndCheckIsElementDirty(element);
|
let isDirtyElement = DOM.updateAndCheckIsElementDirty(element);
|
||||||
if (_verbose) { console.log({isDirtyElement, wasDirtyElement, wasDirtyParentRows}); }
|
Utils.consoleLogIfNotProductionEnvironment({isDirtyElement, wasDirtyElement, wasDirtyParentRows});
|
||||||
let td = DOM.getCellFromElement(element);
|
let td = DOM.getCellFromElement(element);
|
||||||
DOM.setElementAttributeValueCurrent(td, DOM.getElementAttributeValueCurrent(element));
|
DOM.setElementAttributeValueCurrent(td, DOM.getElementAttributeValueCurrent(element));
|
||||||
if (isDirtyElement != wasDirtyElement) {
|
if (isDirtyElement != wasDirtyElement) {
|
||||||
@@ -392,7 +374,7 @@ export default class TableBasePage extends BasePage {
|
|||||||
let tr = DOM.getRowFromElement(td);
|
let tr = DOM.getRowFromElement(td);
|
||||||
let isDirtyRow = isDirtyTd || DOM.hasDirtyChildrenContainer(tr);
|
let isDirtyRow = isDirtyTd || DOM.hasDirtyChildrenContainer(tr);
|
||||||
let wasDirtyRow = wasDirtyParentRows.shift();
|
let wasDirtyRow = wasDirtyParentRows.shift();
|
||||||
if (_verbose) { console.log({isDirtyRow, wasDirtyRow}); }
|
Utils.consoleLogIfNotProductionEnvironment({isDirtyRow, wasDirtyRow});
|
||||||
if (isDirtyRow != wasDirtyRow) {
|
if (isDirtyRow != wasDirtyRow) {
|
||||||
DOM.handleDirtyElement(tr, isDirtyRow);
|
DOM.handleDirtyElement(tr, isDirtyRow);
|
||||||
this.updateAndToggleShowButtonsSaveCancel();
|
this.updateAndToggleShowButtonsSaveCancel();
|
||||||
@@ -404,64 +386,6 @@ export default class TableBasePage extends BasePage {
|
|||||||
}) {
|
}) {
|
||||||
this.hookupEventHandler("change", inputSelector, handler);
|
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() {
|
hookupTextareasCodeTable() {
|
||||||
this.hookupChangeHandlerTableCells(idTableMain + ' tbody tr td.' + flagCode + ' textarea');
|
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 selectorButton = 'table' + (Validation.isEmpty(flagTable) ? '' : '.' + flagTable) + ' > tbody > tr > td.' + flagActive + ' button';
|
||||||
let selectorButtonDelete = selectorButton + '.' + flagDelete;
|
let selectorButtonDelete = selectorButton + '.' + flagDelete;
|
||||||
let selectorButtonUndelete = selectorButton + ':not(.' + flagDelete + ')';
|
let selectorButtonUndelete = selectorButton + ':not(.' + flagDelete + ')';
|
||||||
console.log("hookupFieldsActive: ", selectorButtonDelete, selectorButtonUndelete);
|
Utils.consoleLogIfNotProductionEnvironment("hookupFieldsActive: ", selectorButtonDelete, selectorButtonUndelete);
|
||||||
this.hookupButtonsRowDelete(selectorButtonDelete, selectorButtonUndelete);
|
this.hookupButtonsRowDelete(selectorButtonDelete, selectorButtonUndelete);
|
||||||
this.hookupButtonsRowUndelete(selectorButtonDelete, selectorButtonUndelete);
|
this.hookupButtonsRowUndelete(selectorButtonDelete, selectorButtonUndelete);
|
||||||
this.hookupEventHandler(
|
this.hookupEventHandler(
|
||||||
@@ -549,7 +473,6 @@ export default class TableBasePage extends BasePage {
|
|||||||
}
|
}
|
||||||
handleClickTableCellDdlPreview(event, td, optionObjectList, cellSelector, ddlHookup = (cellSelector) => { this.hookupTableCellDdls(cellSelector); }) {
|
handleClickTableCellDdlPreview(event, td, optionObjectList, cellSelector, ddlHookup = (cellSelector) => { this.hookupTableCellDdls(cellSelector); }) {
|
||||||
if (td.querySelector('select')) return;
|
if (td.querySelector('select')) return;
|
||||||
// td.removeEventListener("click", ddlHookup);
|
|
||||||
let tdNew = td.cloneNode(true);
|
let tdNew = td.cloneNode(true);
|
||||||
td.parentNode.replaceChild(tdNew, td);
|
td.parentNode.replaceChild(tdNew, td);
|
||||||
let idSelected = DOM.getElementAttributeValueCurrent(tdNew);
|
let idSelected = DOM.getElementAttributeValueCurrent(tdNew);
|
||||||
@@ -558,8 +481,8 @@ export default class TableBasePage extends BasePage {
|
|||||||
DOM.setElementValuesCurrentAndPrevious(ddl, idSelected);
|
DOM.setElementValuesCurrentAndPrevious(ddl, idSelected);
|
||||||
let optionJson, option;
|
let optionJson, option;
|
||||||
if (_verbose) {
|
if (_verbose) {
|
||||||
console.log("click table cell ddl preview");
|
Utils.consoleLogIfNotProductionEnvironment("click table cell ddl preview");
|
||||||
console.log({optionObjectList, cellSelector});
|
Utils.consoleLogIfNotProductionEnvironment({optionObjectList, cellSelector});
|
||||||
}
|
}
|
||||||
option = DOM.createOption(null);
|
option = DOM.createOption(null);
|
||||||
ddl.appendChild(option);
|
ddl.appendChild(option);
|
||||||
@@ -572,34 +495,6 @@ export default class TableBasePage extends BasePage {
|
|||||||
let ddlSelector = cellSelector + ' select';
|
let ddlSelector = cellSelector + ' select';
|
||||||
ddlHookup(ddlSelector);
|
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); }) {
|
hookupTableCellDDlPreviewsWhenNotCollapsed(cellSelector, optionList, ddlHookup = (event, element) => { this.hookupTableCellDdls(event, element); }) {
|
||||||
this.hookupEventHandler("click", cellSelector, (event, td) => {
|
this.hookupEventHandler("click", cellSelector, (event, td) => {
|
||||||
let div = td.querySelector('div');
|
let div = td.querySelector('div');
|
||||||
@@ -607,298 +502,12 @@ export default class TableBasePage extends BasePage {
|
|||||||
this.handleClickTableCellDdlPreview(event, td, optionList, cellSelector, (event, element) => { ddlHookup(event, element); });
|
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) {
|
toggleColumnCollapsed(flagColumn, isCollapsed) {
|
||||||
this.toggleColumnHasClassnameFlag(flagColumn, isCollapsed, flagCollapsed);
|
this.toggleColumnHasClassnameFlag(flagColumn, isCollapsed, flagCollapsed);
|
||||||
}
|
}
|
||||||
toggleColumnHeaderCollapsed(flagColumn, isCollapsed) {
|
toggleColumnHeaderCollapsed(flagColumn, isCollapsed) {
|
||||||
this.toggleColumnHasClassnameFlag(flagColumn, isCollapsed, flagCollapsed);
|
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) {
|
createTdActive(isActive) {
|
||||||
let tdActive = document.createElement("td");
|
let tdActive = document.createElement("td");
|
||||||
@@ -921,7 +530,6 @@ export default class TableBasePage extends BasePage {
|
|||||||
let dataPage = {};
|
let dataPage = {};
|
||||||
dataPage[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
dataPage[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||||
this.setLocalStoragePage(dataPage);
|
this.setLocalStoragePage(dataPage);
|
||||||
// _rowBlank = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleColumnHasClassnameFlag(columnFlag, isRequiredFlag, classnameFlag) {
|
toggleColumnHasClassnameFlag(columnFlag, isRequiredFlag, classnameFlag) {
|
||||||
@@ -930,12 +538,6 @@ export default class TableBasePage extends BasePage {
|
|||||||
let columnThHasFlag = columnTh.classList.contains(classnameFlag);
|
let columnThHasFlag = columnTh.classList.contains(classnameFlag);
|
||||||
if (isRequiredFlag == columnThHasFlag) return;
|
if (isRequiredFlag == columnThHasFlag) return;
|
||||||
DOM.toggleElementHasClassnameFlag(columnTh, isRequiredFlag, classnameFlag);
|
DOM.toggleElementHasClassnameFlag(columnTh, isRequiredFlag, classnameFlag);
|
||||||
/*
|
|
||||||
let columnTds = table.querySelectorAll('td.' + columnFlag);
|
|
||||||
columnTds.forEach((columnTd) => {
|
|
||||||
DOM.toggleElementHasClassnameFlag(columnTd, isRequiredFlag, classnameFlag);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
toggleColumnHeaderHasClassnameFlag(columnFlag, isRequiredFlag, classnameFlag) {
|
toggleColumnHeaderHasClassnameFlag(columnFlag, isRequiredFlag, classnameFlag) {
|
||||||
let table = TableBasePage.getTableMain();
|
let table = TableBasePage.getTableMain();
|
||||||
@@ -949,26 +551,3 @@ export default class TableBasePage extends BasePage {
|
|||||||
this.toggleShowButtonsSaveCancel(existsDirtyRecord);
|
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
|
// Core
|
||||||
import PageHome from './pages/core/home.js';
|
import PageHome from './pages/core/home.js';
|
||||||
import PageContact from './pages/core/contact.js';
|
import PageContact from './pages/core/contact.js';
|
||||||
|
import PageContactSuccess from './pages/core/contact-success.js';
|
||||||
// Legal
|
// Legal
|
||||||
import PageAccessibilityReport from './pages/legal/accessibility_report.js';
|
import PageAccessibilityReport from './pages/legal/accessibility_report.js';
|
||||||
import PageAccessibilityStatement from './pages/legal/accessibility_statement.js';
|
import PageAccessibilityStatement from './pages/legal/accessibility_statement.js';
|
||||||
import PageLicense from './pages/legal/license.js';
|
import PageLicense from './pages/legal/license.js';
|
||||||
// User
|
import PagePrivacyPolicy from './pages/legal/privacy_policy.js';
|
||||||
// import PageUserLogin from './pages/user/login.js';
|
import PageRetentionSchedule from './pages/legal/retention_schedule.js';
|
||||||
// import PageUserLogout from './pages/user/logout.js';
|
|
||||||
// import PageUserAccount from './pages/user/account.js';
|
|
||||||
|
|
||||||
import API from './api.js';
|
import API from './api.js';
|
||||||
import DOM from './dom.js';
|
import DOM from './dom.js';
|
||||||
import PagePrivacyPolicy from './pages/legal/privacy_policy.js';
|
import Utils from './lib/utils.js';
|
||||||
import PageRetentionSchedule from './pages/legal/retention_schedule.js';
|
|
||||||
|
|
||||||
|
|
||||||
export default class Router {
|
export default class Router {
|
||||||
@@ -23,18 +21,14 @@ export default class Router {
|
|||||||
// Pages
|
// Pages
|
||||||
this.pages = {};
|
this.pages = {};
|
||||||
// Core
|
// 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[hashPageHome] = { name: 'PageHome', module: PageHome };
|
||||||
this.pages[hashPageContact] = { name: 'PageContact', module: PageContact }; // pathModule: './pages/core/contact.js' };
|
this.pages[hashPageContact] = { name: 'PageContact', module: PageContact };
|
||||||
|
this.pages[hashPageContactSuccess] = { name: 'PageContact', module: PageContactSuccess };
|
||||||
// Legal
|
// Legal
|
||||||
this.pages[hashPageAccessibilityStatement] = { name: 'PageAccessibilityStatement', module: PageAccessibilityStatement }; // pathModule: '../../static/js/pages/legal/accessibility_statement.js' }; // , page: PageAccessibilityStatement
|
this.pages[hashPageAccessibilityStatement] = { name: 'PageAccessibilityStatement', module: PageAccessibilityStatement };
|
||||||
this.pages[hashPageDataRetentionSchedule] = { name: 'PageDataRetentionSchedule', module: PageRetentionSchedule }; // pathModule: './pages/legal/data_retention_schedule.js' };
|
this.pages[hashPageDataRetentionSchedule] = { name: 'PageDataRetentionSchedule', module: PageRetentionSchedule };
|
||||||
this.pages[hashPageLicense] = { name: 'PageLicense', module: PageLicense }; // pathModule: './pages/legal/license.js' };
|
this.pages[hashPageLicense] = { name: 'PageLicense', module: PageLicense };
|
||||||
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'); }
|
this.pages[hashPagePrivacyPolicy] = { name: 'PagePrivacyPolicy', module: PagePrivacyPolicy };
|
||||||
// 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' };
|
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
this.routes = {};
|
this.routes = {};
|
||||||
// Core
|
// Core
|
||||||
@@ -45,10 +39,6 @@ export default class Router {
|
|||||||
this.routes[hashPageDataRetentionSchedule] = (isPopState = false) => this.navigateToHash(hashPageDataRetentionSchedule, isPopState);
|
this.routes[hashPageDataRetentionSchedule] = (isPopState = false) => this.navigateToHash(hashPageDataRetentionSchedule, isPopState);
|
||||||
this.routes[hashPageLicense] = (isPopState = false) => this.navigateToHash(hashPageLicense, isPopState);
|
this.routes[hashPageLicense] = (isPopState = false) => this.navigateToHash(hashPageLicense, isPopState);
|
||||||
this.routes[hashPagePrivacyPolicy] = (isPopState = false) => this.navigateToHash(hashPagePrivacyPolicy, 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();
|
this.initialize();
|
||||||
}
|
}
|
||||||
loadPage(hashPage, isPopState = false) {
|
loadPage(hashPage, isPopState = false) {
|
||||||
@@ -61,31 +51,17 @@ export default class Router {
|
|||||||
|
|
||||||
let pageJson = this.pages[hashPage];
|
let pageJson = this.pages[hashPage];
|
||||||
try {
|
try {
|
||||||
/*
|
const module = pageJson.module;
|
||||||
const module = await pagesContext(pageJson.pathModule);
|
return module;
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
if (_verbose) { console.log("this.pages: ", this.pages); };
|
Utils.consoleLogIfNotProductionEnvironment("this.pages: ", this.pages);
|
||||||
console.error('Page not found:', hashPage);
|
console.error('Page not found:', hashPage);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initialize() {
|
initialize() {
|
||||||
/*
|
window.addEventListener('popstate', this.handlePopState.bind(this));
|
||||||
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
|
|
||||||
}
|
}
|
||||||
handlePopState(event) {
|
handlePopState(event) {
|
||||||
this.loadPageCurrent();
|
this.loadPageCurrent();
|
||||||
@@ -95,26 +71,11 @@ export default class Router {
|
|||||||
this.loadPage(hashPageCurrent);
|
this.loadPage(hashPageCurrent);
|
||||||
}
|
}
|
||||||
navigateToHash(hash, data = null, params = null, isPopState = false) {
|
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);
|
let url = API.getUrlFromHash(hash, params);
|
||||||
// if (!isPopState)
|
|
||||||
history.pushState({data: data, params: params}, '', hash);
|
history.pushState({data: data, params: params}, '', hash);
|
||||||
API.goToUrl(url, data);
|
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) {
|
navigateToUrl(url, data = null, appendHistory = true) {
|
||||||
// this.beforeLeave();
|
// this.beforeLeave();
|
||||||
if (appendHistory) history.pushState(data, '', url);
|
if (appendHistory) history.pushState(data, '', url);
|
||||||
@@ -128,25 +89,3 @@ export default class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const router = new 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 attrValueCurrent = "{{ model.ATTR_VALUE_CURRENT }}";
|
||||||
var attrValuePrevious = "{{ model.ATTR_VALUE_PREVIOUS }}";
|
var attrValuePrevious = "{{ model.ATTR_VALUE_PREVIOUS }}";
|
||||||
var attrValueNew = "{{ model.ATTR_VALUE_NEW }}";
|
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 flagAccessLevel = "{{ model.FLAG_ACCESS_LEVEL }}";
|
||||||
var flagAccessLevelRequired = "{{ model.FLAG_ACCESS_LEVEL_REQUIRED }}";
|
var flagAccessLevelRequired = "{{ model.FLAG_ACCESS_LEVEL_REQUIRED }}";
|
||||||
var flagActive = "{{ model.FLAG_ACTIVE }}";
|
var flagActive = "{{ model.FLAG_ACTIVE }}";
|
||||||
@@ -132,23 +137,16 @@
|
|||||||
var flagTemporaryElement = "{{ model.FLAG_TEMPORARY_ELEMENT }}";
|
var flagTemporaryElement = "{{ model.FLAG_TEMPORARY_ELEMENT }}";
|
||||||
var flagUser = "{{ model.FLAG_USER }}";
|
var flagUser = "{{ model.FLAG_USER }}";
|
||||||
var flagWebsite = "{{ model.FLAG_WEBSITE }}";
|
var flagWebsite = "{{ model.FLAG_WEBSITE }}";
|
||||||
var hashALTCHACreateChallenge = "{{ model.HASH_ALTCHA_CREATE_CHALLENGE }}";
|
var hashGetALTCHAChallenge = "{{ model.HASH_ALTCHA_CREATE_CHALLENGE }}";
|
||||||
var hashApplyFiltersStoreProductPermutation = "{{ model.HASH_APPLY_FILTERS_STORE_PRODUCT_PERMUTATION }}";
|
|
||||||
var hashPageAccessibilityReport = "{{ model.HASH_PAGE_ACCESSIBILITY_REPORT }}";
|
var hashPageAccessibilityReport = "{{ model.HASH_PAGE_ACCESSIBILITY_REPORT }}";
|
||||||
var hashPageAccessibilityStatement = "{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}";
|
var hashPageAccessibilityStatement = "{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}";
|
||||||
var hashPageAdminHome = "{{ model.HASH_PAGE_ADMIN_HOME }}";
|
|
||||||
var hashPageContact = "{{ model.HASH_PAGE_CONTACT }}";
|
var hashPageContact = "{{ model.HASH_PAGE_CONTACT }}";
|
||||||
|
var hashPageContactSuccess = "{{ model.HASH_PAGE_CONTACT_SUCCESS }}";
|
||||||
var hashPageDataRetentionSchedule = "{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}";
|
var hashPageDataRetentionSchedule = "{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}";
|
||||||
// var hashPageCurrent = "{{ model.hash_page_current }}";
|
|
||||||
var hashPageErrorNoPermission = "{{ model.HASH_PAGE_ERROR_NO_PERMISSION }}";
|
var hashPageErrorNoPermission = "{{ model.HASH_PAGE_ERROR_NO_PERMISSION }}";
|
||||||
var hashPageHome = "{{ model.HASH_PAGE_HOME }}";
|
var hashPageHome = "{{ model.HASH_PAGE_HOME }}";
|
||||||
var hashPageLicense = "{{ model.HASH_PAGE_LICENSE }}";
|
var hashPageLicense = "{{ model.HASH_PAGE_LICENSE }}";
|
||||||
var hashPagePrivacyPolicy = "{{ model.HASH_PAGE_PRIVACY_POLICY }}";
|
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 idButtonApplyFilters = "#{{ model.ID_BUTTON_APPLY_FILTERS }}";
|
||||||
var idButtonHamburger = "#{{ model.ID_BUTTON_HAMBURGER }}";
|
var idButtonHamburger = "#{{ model.ID_BUTTON_HAMBURGER }}";
|
||||||
var idCSRFToken = "#{{ model.ID_CSRF_TOKEN }}";
|
var idCSRFToken = "#{{ model.ID_CSRF_TOKEN }}";
|
||||||
@@ -168,10 +166,6 @@
|
|||||||
</script>
|
</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'">
|
<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>
|
<noscript><link rel="stylesheet" href="{{ url_for('static', filename='dist/css/main.bundle.css') }}"></noscript>
|
||||||
|
|
||||||
@@ -182,7 +176,7 @@
|
|||||||
<header>
|
<header>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<nav class="navbar">
|
<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">
|
<div class="nav-links">
|
||||||
{% block page_nav_links %}{% endblock %}
|
{% block page_nav_links %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
@@ -209,8 +203,8 @@
|
|||||||
<div class="footer-section">
|
<div class="footer-section">
|
||||||
<h3>Legal</h3>
|
<h3>Legal</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{{ url_for('routes_legal.privacy_policy') }}">Privacy Policy</a></li>
|
<li><a href="{{ model.HASH_PAGE_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_ACCESSIBILITY_STATEMENT }}">Accessibility Statement</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -225,24 +219,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-bottom">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</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>
|
<script src="{{ url_for('static', filename='dist/js/main.bundle.js') }}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
<!--
|
|
||||||
<script>
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
// alert("naughty boy");
|
|
||||||
hookupShared();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
-->
|
|
||||||
|
|||||||
@@ -2,25 +2,6 @@
|
|||||||
|
|
||||||
{% block page_head %}
|
{% block page_head %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/core_contact.bundle.css') }}">
|
<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 %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_nav_links %}
|
{% block page_nav_links %}
|
||||||
@@ -31,18 +12,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_body %}
|
{% 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 %}
|
{% set form = model.form_contact %}
|
||||||
<section class="contact-section">
|
<section class="contact-section">
|
||||||
@@ -50,17 +19,7 @@
|
|||||||
<h1>Contact Us</h1>
|
<h1>Contact Us</h1>
|
||||||
<p>Please fill in the form below and we'll get back to you as soon as possible.</p>
|
<p>Please fill in the form below and we'll get back to you as soon as possible.</p>
|
||||||
|
|
||||||
{% with messages = get_flashed_messages() %}
|
<form id="{{ model.ID_CONTACT_FORM }}" method="POST" action="{{ model.HASH_POST_CONTACT_FORM }}">
|
||||||
{% 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.csrf_token }}
|
{{ form.csrf_token }}
|
||||||
|
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
@@ -90,27 +49,17 @@
|
|||||||
{{ model.form_contact.receive_marketing.label }}
|
{{ model.form_contact.receive_marketing.label }}
|
||||||
</div>
|
</div>
|
||||||
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_CAPTCHA }}">
|
<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>
|
<div>
|
||||||
{{ form.altcha.label }}
|
{{ form.altcha.label }}
|
||||||
{#
|
|
||||||
{{ form.altcha }}
|
|
||||||
{{ form.altcha.hidden() }}
|
|
||||||
#}
|
|
||||||
<altcha-widget
|
<altcha-widget
|
||||||
class="altcha-widget"
|
class="altcha-widget"
|
||||||
challengeurl="{{ url_for('routes_core.create_altcha_challenge') }}"
|
challengeurl="{{ model.HASH_GET_ALTCHA_CHALLENGE }}"
|
||||||
auto="onload"
|
auto="onload"
|
||||||
id="{{ form.altcha.id }}"
|
id="{{ form.altcha.id }}"
|
||||||
name="{{ form.altcha.name }}"
|
name="{{ form.altcha.name }}"
|
||||||
></altcha-widget>
|
></altcha-widget>
|
||||||
</div>
|
</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>
|
||||||
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
|
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
|
||||||
{{ model.form_contact.submit() }}
|
{{ model.form_contact.submit() }}
|
||||||
@@ -119,74 +68,13 @@
|
|||||||
|
|
||||||
<div class="data-notice">
|
<div class="data-notice">
|
||||||
<h3>How we use your information</h3>
|
<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>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="{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}">data retention schedule</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="{{ 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="{{ model.HASH_PAGE_PRIVACY_POLICY }}">Privacy Policy</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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</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>
|
<script>
|
||||||
var flagALTCHAWidget = "{{ model.FLAG_ALTCHA_WIDGET }}";
|
var flagALTCHAWidget = "{{ model.FLAG_ALTCHA_WIDGET }}";
|
||||||
var idContactForm = "#{{ model.ID_CONTACT_FORM }}";
|
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 title %}{{ model.title }}{% endblock %}
|
||||||
|
|
||||||
{% block page_body %}
|
{% 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') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='dist/css/legal_accessibility_statement.bundle.css') }}">
|
||||||
|
|
||||||
<!-- HTML content -->
|
<!-- 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.]
|
[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/#/
|
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>
|
</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/sections/legal.js') }}"></script>
|
||||||
<script type="module" src="{{ url_for('static', filename='js/pages/legal/accessibility_statement.js') }}"></script>
|
<script type="module" src="{{ url_for('static', filename='js/pages/legal/accessibility_statement.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1955,7 +1955,7 @@
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
<script>
|
<script>
|
||||||
var hashPageCurrent = "{{ model.HASH_PAGE_RETENTION_SCHEDULE }}";
|
var hashPageCurrent = "{{ model.HASH_PAGE_DATA_RETENTION_SCHEDULE }}";
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
hookupPageRetentionSchedule();
|
hookupPageRetentionSchedule();
|
||||||
|
|||||||
2
todo.txt
2
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