1. Refactoring form objects and database objects to use inheritance and abstract base class for consistency and reduced redundancy.\n2. Contact us page button links updated to resolve error of missing link causing page refresh instead of expected functionality.

This commit is contained in:
2024-09-10 12:09:50 +01:00
parent c9dda91dc9
commit 6b730bf8e7
709 changed files with 5158 additions and 1512 deletions

View File

@@ -0,0 +1,54 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
<!-- Include Stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/core.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/core/admin_home.css') }}">
<!-- HTML content -->
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_ROW }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<h2>Store</h2>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<button class="{{ model.FLAG_NAV_STORE_PRODUCT_CATEGORIES }}">Product Categories</button>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<button class="{{ model.FLAG_NAV_STORE_PRODUCTS }}">Products</button>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<button class="{{ model.FLAG_NAV_STORE_PRODUCT_PERMUTATIONS }}">Product Permutations</button>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<button class="{{ model.FLAG_NAV_STORE_PRODUCT_PRICES }}">Product Prices</button>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<button class="{{ model.FLAG_NAV_STORE_STOCK_ITEMS }}">Product Stock</button>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<button class="{{ model.FLAG_NAV_STORE_PRODUCT_VARIATIONS }}">Product Variations</button>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<button class="{{ model.FLAG_NAV_ADMIN_STORE_STRIPE_PRODUCTS }}">Add new Stripe products</button>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<button class="{{ model.FLAG_NAV_ADMIN_STORE_STRIPE_PRICES }}">Add new Stripe prices</button>
</div>
</div>
<!-- Include JavaScript -->
<script type="module" src="{{ url_for('static', filename='js/sections/core.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/core/admin_home.js') }}"></script>
<!-- <script type="module" src="{{ url_for('static', filename='js/pages/store/base.js') }}"></script> -->
<!--
<script>
var hashPageCurrent = "{{ model.HASH_PAGE_STORE_ADMIN_HOME }}";
$(document).ready(function() {
hookupPageAdminHome();
});
</script>
-->
{% endblock %}

View File

@@ -0,0 +1,105 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
<!-- Include Stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/core.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/contact.css') }}">
<script src="https://www.google.com/recaptcha/enterprise.js?render=6Lf8Q8cpAAAAAFAawGu4-ma60bvbEixNVTVvRzKe"></script> <!-- reCaptcha Integration -->
<!-- HTML content -->
<div class="card">
<form id="{{ model.ID_FORM_CONTACT }}" class="container" action="{{ url_for('routes_core.contact') }}" method="POST">
<h2 class="label-title">Complete the form or find our details below.</h2>
<!--
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
<label for="sender_email">Email address</label> <!-- class="input-label" --
<input type="email" id="sender_email" name="sender_email" placeholder="Please enter your email address so we can get back to you." style="width: 50%;"/>
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
<label for="sender_CC">
<input type="checkbox" id="sender_CC" name="sender_CC" checked/>Uncheck this box if you do not wish to receive a copy of the email
</label>
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
<label for="sender_name">Name</label> <!-- class="input-label" --
<input type="text" id="sender_name" name="sender_name" placeholder="Please enter your preferred name." style="width: 30%;"/>
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
<label for="sender_message">Message</label> <!-- class="input-label" --
<textarea id="sender_message" name="sender_message" rows="4" cols="80" placeholder="How can we help?"></textarea>
</div>
<button type="submit" id="submit_form_email">Submit request</button>
-->
{{ model.form_contact.hidden_tag() }}
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_contact.email.label }}
{{ model.form_contact.email(size=254) }}
{% for error in model.form_contact.email.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
<!--
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_contact.CC.label }}
{{ model.form_contact.CC(checked=True) }}
{% for error in model.form_contact.name.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
-->
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_contact.name.label }}
{{ model.form_contact.name(size=50) }}
{% for error in model.form_contact.name.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_contact.message.label }}
{{ model.form_contact.message(rows=4, cols=80) }}
{% for error in model.form_contact.name.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_contact.recaptcha() }}
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_contact.submit() }}
</div>
</form>
</div>
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<h3 class="label-title" style="padding-bottom: 0;">Where to find us</h3>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<h4>{{ model.app.MAIL_CONTACT_PUBLIC }}</h4>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}" style="padding-top: 0; width: fit-content;">
<a href="{{ model.URL_LINKEDIN }}" class="container-icon-label"><img class="img-icon" src="{{ url_for('static', filename='images/Logo_LinkedIn.png') }}" alt="LinkedIn" aria-label="LinkedIn"></img><!--<h4>LinkedIn</h4>--></a>
<a href="{{ model.URL_GITHUB }}" class="container-icon-label"><img class="img-icon" src="{{ url_for('static', filename='images/Logo_GitHub.png') }}" alt="GitHub" aria-label="GitHub"></img><!--<h4>GitHub</h4>--></a>
</div>
</div>
<!-- Include JavaScript -->
<script type="module" src="{{ url_for('static', filename='js/sections/core.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/contact.js') }}"></script>
<script>
var idEmail = "#{{ model.ID_EMAIL }}";
var idMessage = "#{{ model.ID_MESSAGE }}";
var idName = "#{{ model.ID_NAME }}";
/*
$(document).ready(function() {
stylePageContact();
hookupPageContact();
});
*/
</script>
{% endblock %}

View File

@@ -0,0 +1,30 @@
<!-- v2a -->
{% extends 'layouts/layout.html' %}
{% block page_body %}
<!-- Include Stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/core.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/home.css') }}" />
<!-- HTML content -->
<div>
<h2 style="font-size: 24px; color: white; font-weight: normal;">We make websites, web apps, and desktop software</h2>
{% set block_id = 'button_get_in_touch' %}
{% include 'layouts/_shared.html' %}
</div>
<!-- Include JavaScript -->
<script type="module" src="{{ url_for('static', filename='js/sections/core.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/home.js') }}"></script>
<!--
<script>
var hashPageCurrent = "{{ model.HASH_PAGE_HOME }}";
$(document).ready(function() {
hookupPageHome();
});
</script>
-->
{% endblock %}

View File

@@ -0,0 +1,117 @@
<!-- v2a -->
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
<!-- Include Stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/core.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/services.css') }}" />
<!-- HTML content -->
<div class="{{ model.FLAG_CARD }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<h1>Services</h1>
<h2>Website, Web App, & Desktop Software Development</h2>
<ul>
<li>Custom software tailored to your unique business needs</li>
<li>Leverage the latest technologies for seamless, high-performance solutions</li>
<li>Intuitive user interface design to delight your users and boost productivity</li>
</ul>
<h2>Cloud Migration & Architecture Design</h2>
<ul>
<li>Expertise to guide your cloud journey and optimize your architecture</li>
<li>Ensure scalability, security and cost-efficiency in the cloud</li>
<li>Unlock the power of cloud-native services, like AI, to accelerate innovation</li>
</ul>
</div>
</div>
<div class="{{ model.FLAG_CARD }}">
<h1>Technologies</h1>
<p>We are most experienced with these technologies, in case you have any requirements.</p>
<table>
<thead>
<tr>
<th>Database</th>
<th>Server / Application</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://www.mysql.com/" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/MySQL.png')}}" alt="MySQL"></img></a></td>
<td><a href="https://www.python.org/" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/python.png')}}" alt="python"></img></a></td>
</tr>
<tr>
<td><a href="https://www.microsoft.com/en-us/sql-server/sql-server-2019" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/MS_SQL_Server.svg')}}" alt="Microsoft SQL Server"></img></a></td>
<td><a href="https://dotnet.microsoft.com/en-us/languages/csharp" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/Csharp_NET.png')}}" alt="C sharp dot NET"></img></a></td>
</tr>
<tr>
<td><a href="https://firebase.google.com/" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/Firebase.png')}}" alt="Firebase"></img></a></td>
<td><a href="https://nodejs.org/en" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/Node_js.png')}}" alt="Node dot js"></img></a></td>
</tr>
<tr>
<td></td>
<td><a href="https://www.java.com/en/" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/Java.png')}}" alt="Java"></img></a></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Web</th>
<th>Frameworks</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://www.w3.org/html/" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/HTML5.png')}}" alt="HTML5"></img></a></td>
<td><a href="https://react.dev/" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/React.png')}}" alt="React"></img></a></td>
</tr>
<tr>
<td><a href="https://www.w3.org/Style/CSS/" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/CSS3.jpg')}}" alt="CSS3"></img></a></td>
<td><a href="https://flask.palletsprojects.com/en/3.0.x/" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/Flask.png')}}" alt="Flask"></img></a></td>
</tr>
<tr>
<td><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/JavaScript.png')}}" alt="JavaScript"></img></a></td>
<td><a href="https://dotnet.microsoft.com/en-us/apps/aspnet/mvc" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/MVC.png')}}" alt="Model View Controller"></img></a></td>
</tr>
<tr>
<td></td>
<td><a href="https://ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm" target="_blank"><img class="img-icon" src="{{ url_for('static', filename='images/REST.png')}}" alt="REST"></img></a></td>
</tr>
</tbody>
</table>
</div>
<div class="{{ model.FLAG_CARD }}">
<h1>FAQs</h1>
<h2>Websites, Web apps, and Software - what's the difference?</h2>
<ul>
<li>Not much! A web app is a type of website and they are both types of software that are accessed on the internet using web browser software.</li>
<li>Web apps have more complex functionality than simple text and image pages.</li>
<li>For example, this is a website. Google Maps is a web app. Notepad is a piece of desktop sofware.</li>
</ul>
<h2>Why choose us?</h2>
<ul>
<li>Work directly with the person responsible for delivering your project</li>
<li>Faster decision-making process without bureaucratic hurdles</li>
<li>Transparent pricing structure with no hidden fees</li>
</ul>
</div>
<!-- Include JavaScript -->
<script type="module" src="{{ url_for('static', filename='js/sections/core.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/services.js') }}"></script>
<!--
<script>
var hashPageCurrent = "{{ model.HASH_PAGE_SERVICES }}";
$(document).ready(function() {
hookupPageServices();
});
</script>
-->
{% endblock %}

View File

@@ -0,0 +1,208 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
<!-- Include Stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/legal.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/accessibility_statement.css') }}">
<!-- HTML content -->
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_COLUMN }}">
<h2>Accessibility statement for {{ model.NAME_COMPANY }}</h2>
<!--
[Note: you can have a single accessibility statement that covers multiple domains, or a separate statement for each domain or subdomain. As long as the user can access relevant accessibility information easily from any page on your website.
For mobile apps also include the applications version information and publication date.
This wording is legally required and must not be changed.]
-->
<p>This accessibility statement applies to the public website of {{ model.NAME_COMPANY }}.</p>
<!--
[Note: use this section to make a brief, general statement about what the website allows disabled users to do. Base it on the evaluation covered in detail in the Technical information about this websites accessibility section.
It must be specific to your own website. If youre not confident that something is accurate, leave it out. If youre not confident enough to say anything specific here, leave this section out completely.]
-->
<p>This website is run by {{ model.NAME_COMPANY }}. We want as many people as possible to be able to use this website. For example, that means you should be able to:
<ul>
<li>Zoom in up to 400% without the text spilling off the screen</li>
<li>Navigate most of the website using just a keyboard or speech recognition software</li>
<li>Listen to most of the website using a screen reader (including the most recent versions of NVDA and TalkBack)</li>
<li>We've also made the website text as simple as possible to understand.</li>
<a href="https://mcmw.abilitynet.org.uk/">AbilityNet</a> has advice on making your device easier to use if you have a disability.
</p>
<h3>How accessible this website is</h3>
<!--
[Note: use this section to provide a summary of accessibility issues that a disabled user can act on - for example, avoid a particular section of the website, or request an alternative version rather than waste time trying to make it work with their assistive technology. Try to list in order of most impact to least impact.]
-->
<p>We know some parts of this website are not fully accessible:
<ul>
<li>you cannot modify the line height or spacing of text</li>
</ul>
</p>
<h3>Feedback and contact information</h3>
<p>If you find any problems not listed on this page or think were not meeting accessibility requirements, contact: {{ model.app.MAIL_CONTACT_PUBLIC }} or complete our Contact Us form.
If you need information on this website in a different format like accessible PDF, large print, easy read, audio recording or braille:
</p>
{% set block_id = 'button_get_in_touch' %}
{% include 'layouts/_shared.html' %}
<p>
Well consider your request and get back to you in 7 days.
<!-- If you cannot view the map on our contact us page, email us for directions. -->
</p>
<h3>Enforcement procedure</h3>
<p>The Equality and Human Rights Commission (EHRC) is responsible for enforcing the Public Sector Bodies (Websites and Mobile Applications) (No. 2) Accessibility Regulations 2018 (the accessibility regulations). If youre not happy with how we respond to your complaint, contact the <a href="https://www.equalityadvisoryservice.com/">Equality Advisory and Support Service (EASS).</a>
</p>
<!--
[Note: if your organisation is based in Northern Ireland, refer users who want to complain to the Equality Commission for Northern Ireland (ECNI) instead of the EASS and EHRC.
You must link to either the EASS or ECNI websites.]
-->
<br>
<h2>Technical information about this websites accessibility</h2>
<!--
[Note: this wording is legally required and must not be changed.]
-->
<p>{{ model.NAME_COMPANY }} is committed to making its website accessible, in accordance with the Public Sector Bodies (Websites and Mobile Applications) (No. 2) Accessibility Regulations 2018.
</p>
<h3>Compliance status</h3>
<p>The website has been tested against the Web Content Accessibility Guidelines (WCAG) 2.2 AA standard.
</p>
<!--
[Note: say that the website is fully compliant if the website meets the Web Content Accessibility Guidelines (WCAG) [2.1 or 2.2] AA standard in full.
Say that its partially compliant if it meets most requirements of the WCAG [2.1 or 2.2] AA standard.
If it does not meet most requirements of the WCAG [2.1 or 2.2] AA standard, say that its not compliant.
If your website is either partially compliant or not compliant with the WCAG [2.1 or 2.2] AA standard, youll need to explain why. This will be due to one or both of the following:
<ul>
<li>non-compliances - this means the content in question is in scope of the regulations, but theres an accessibility problem with it</li>
<li>an exemption - this means the inaccessible content is out of scope of the regulations, or itd be a disproportionate burden for you to make it accessible</li>
</ul>
Theres a legally required way of expressing the compliance status of your website, so do not change it. Choose one of the options below, for example (a), (b) or (c), and delete those not applicable.
-->
<p><!-- [Select (a) only if all requirements of the technical specification are fully met without exceptions for WCAG 2.1 or WCAG 2.2.] -->
(a) This website is fully compliant with the <!--[Web Content Accessibility Guidelines version 2.1 AA standard or -->Web Content Accessibility Guidelines version 2.2 AA standard.
<!--
[Select (b) if most requirements of the technical specification are met, but with some exceptions. This means not yet fully compliant and that the necessary measures are to be taken in order to reach full compliance.]
(b) This website is partially compliant with the [Web Content Accessibility Guidelines version 2.1 AA standard or Web Content Accessibility Guidelines version 2.2 AA standard], due to [insert one of the following: the non-compliances, the exemptions or the non-compliances and exemptions] listed below.
[Select (c) if most requirements of the technical specification are not met.]
(c) This website is not compliant with the [Web Content Accessibility Guidelines version 2.1 AA standard or Web Content Accessibility Guidelines version 2.2 AA standard]. The [insert one of the following: non-compliances, exemptions or non-compliances and exemptions] are listed below.
-->
</p>
<!--
<h2>Non-accessible content</h2>
<!--
[Note: if the website is fully compliant with the standard, you can leave the Non-accessible content section out.
Otherwise, do not change the Non-accessible content heading or the The content listed below is non-accessible for the following reasons sentence - theyre legally required.
Do not change the Non-compliance with the accessibility regulations, Disproportionate burden and Content thats not within the scope of the accessibility regulations subheadings: theyre also legally required.
But if you need to list a lot of problems, you can break these subsections up with further subheadings - for example, Navigation and accessing information or Interactive tools and transactions.]
--
<p>The content listed below is non-accessible for the following reasons.
</p>
<h3>Non-compliance with the accessibility regulations</h3>
<!--
[Note: In this subsection, list:
<ul>
<li>accessibility problems</li>
<li>which of the WCAG success criteria the problem fails on</li>
<li>when you plan to fix the problem</li>
</ul>
Do not include any problems where youre claiming disproportionate burden, or where the problem is outside the scope of the accessibility regulations (those should go in the subsections below).
These are examples only. Your statement must be specific to your website.]
--
<p>Some images do not have a text alternative, so people using a screen reader cannot access the information. This fails WCAG 2.2 success criterion 1.1.1 (non-text content).
We plan to add text alternatives for all images by September 2022. When we publish new content well make sure our use of images meets accessibility standards.
</p>
<h3>Disproportionate burden</h3>
<!--
[Note: in this subsection list accessibility problems youre claiming would be a disproportionate burden to fix.
You must carry out an assessment before claiming disproportionate burden.
Bear in mind that something which is a disproportionate burden now will not necessarily be a disproportionate burden forever. If the circumstances change, your ability to claim disproportionate burden may change too.
These are examples only. Your statement should be specific to your website.]
--
<p><strong>Navigation and accessing information</strong>
Theres no way to skip the repeated content in the page header (for example, a skip to main content option).
Its not always possible to change the device orientation from horizontal to vertical without making it more difficult to view the content.
Its not possible for users to change text size without some of the content overlapping.
Weve assessed the cost of fixing the issues with navigation and accessing information. We believe that doing so now would be a disproportionate burden within the meaning of the accessibility regulations. We will make another assessment when the supplier contract is up for renewal, likely to be in [rough timing].
</p>
<h3>Content thats not within the scope of the accessibility regulations</h3>
<!--
[Note: in this subsection list accessibility problems that fall outside the scope of the accessibility regulations.]
--
<p><strong>PDFs and other documents</strong>
The accessibility regulations do not require us to fix PDFs or other documents published before 23 September 2018 if theyre not essential to providing our services. For example, we do not plan to fix [example of non-essential document].
Any new PDFs or Word documents we publish will meet accessibility standards.
<strong>Live video</strong>
We do not plan to add captions to live video streams because live video is exempt from meeting the accessibility regulations.
</p>
-->
<!--
<h2>What were doing to improve accessibility</h2>
<!--
[Note: publishing an accessibility roadmap is optional. Its a good idea to publish one if you want to be specific about the order youre planning to tackle accessibility issues, and theres no space to do so in the accessibility statement itself.]
--
<p>Our accessibility roadmap [add link to roadmap] shows how and when we plan to improve accessibility on this website.
</p>
-->
<br>
<h2>Preparation of this accessibility statement</h2>
<!--
[Note: the wording about when the statement was prepared and reviewed is required.
It is recommended that an audit be carried out following a substantial revision to your website. The statement must also be updated.
The statement must be reviewed at least once a year, even if there have not been significant changes to the website. Include the date of the last review.]
-->
<p>This statement was prepared on 30/04/2024<!--[date when it was first published]-->. It was last reviewed on 30/04/2024<!--[date when it was last reviewed]-->.
This website was last tested on 30/04/2024 against the WCAG 2.2 AA standard.
</p>
<!--
[Note: describe how you tested the website to write this statement - such as a self-assessment done by the website team or an assessment carried out by a third party.]
-->
<p>The test was carried out by <!--[add name of organisation that carried out test, or indicate that you did your own testing]-->{{ model.NAME_COMPANY }}. All pages were tested using automated testing tools by our website team. A further audit of the website was carried out to the WCAG 2.2 AA standard.</p>
<!--
[Note: publishing the test report is optional but doing so may allow you to make your accessibility statement shorter and more focused.]
https://www.w3.org/WAI/eval/report-tool/#/
-->
<p>You can read the full accessibility test report {{ model.URL_HOST }}{{ url_for('routes_legal.accessibility_report') }}.</p>
</div>
<!-- Include JavaScript -->
<script type="module" src="{{ url_for('static', filename='js/sections/legal.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/accessibility_statement.js') }}"></script>
{% endblock %}

View File

@@ -0,0 +1,37 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
<!-- Include Stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/legal.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/license.css') }}">
<!-- HTML content -->
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_COLUMN }}">
<p>Copyright &copy; 2024 Precision And Research Technology Systems Limited
</p>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
</p>
<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
</p>
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</p>
</div>
<!-- Include JavaScript -->
<script type="module" src="{{ url_for('static', filename='js/sections/legal.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/license.js') }}"></script>
<!--
<script>
var hashPageCurrent = "{{ model.HASH_PAGE_LICENSE }}";
$(document).ready(function() {
hookupPageLicense();
});
</script>
-->
{% endblock %}

View File

@@ -0,0 +1,96 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
<!-- Include Stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/legal.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/privacy_notice.css') }}">
<!-- HTML content -->
<div class="{{ model.FLAG_CARD }} {{ model.FLAG_COLUMN }}">
<h2>Generated privacy notice - general business</h2>
<h3>Precision and Research Technology Systems Ltd customer privacy notice</h3>
<p>This privacy notice tells you what to expect us to do with your personal information.</p>
<h3>Our contact details</h3>
<p>Email</p>
<p>teddy@partsltd.co.uk</p>
<h3>What information we collect, use, and why</h3>
<p>We collect or use the following information to provide services and goods, including delivery:</p>
<ul>
<li>Names and contact details</li>
</ul>
<h3>Lawful bases</h3>
<p>Our lawful bases for collecting or using personal information to provide services and goods are:</p>
<ul>
<li>Legitimate interest:</li>
<ul>
<li>
We collect the user's name and email address alongside a message they send on our 'Contact Us' form in order to respond to their request. Alternatively, the user has the option to contact us directly by email.
</li>
</ul>
</ul>
<h3>Where we get personal information from</h3>
<ul>
<li>People directly</li>
</ul>
<h3>How long we keep information</h3>
<p>For information on how long we keep personal information, see our retention schedule at <a href="https://www.partsltd.co.uk/retention-schedule" alt="retention schedule" aria-label="retention schedule">https://www.partsltd.co.uk/retention-schedule</a></p>
<h3>Who we share information with</h3>
<p>Data processors</p>
<p><strong>Zume</strong></p>
<p>This data processor does the following activities for us: They host our web and email server, including emails with personal data in body and database storage for database that holds user data.</p>
<h3>Sharing information outside the UK</h3>
<p>Where necessary, we may transfer personal information outside of the UK. When doing so, we comply with the UK GDPR, making sure appropriate safeguards are in place. Please contact us for more information.</p>
<p>Where necessary, our data processors may share personal information outside of the UK. When doing so, they comply with the UK GDPR, making sure appropriate safeguards are in place. Please contact us for more information.</p>
<h3>Your data protection rights</h3>
<p>Under data protection law, you have rights including:</p>
<ul>
<li>Your right of access - You have the right to ask us for copies of your personal data.</li>
<li>Your right to rectification - You have the right to ask us to rectify personal data you think is inaccurate. You also have the right to ask us to complete information you think is incomplete.</li>
<li>Your right to erasure - You have the right to ask us to erase your personal data in certain circumstances.</li>
<li>Your right to restriction of processing - You have the right to ask us to restrict the processing of your personal data in certain circumstances.</li>
<li>Your right to object to processing - You have the right to object to the processing of your personal data in certain circumstances.</li>
<li>Your right to data portability - You have the right to ask that we transfer the personal data you gave us to another organisation, or to you, in certain circumstances.</li>
<li>Your right to withdraw consent When we use consent as our lawful basis you have the right to withdraw your consent.</li>
</ul>
<p>You dont usually need to pay a fee to exercise your rights. If you make a request, we have one calendar month to respond to you.</p>
<p>To make a data protection rights request, please contact us using the contact details at the top of this privacy notice.</p>
<h3>How to complain</h3>
<p>If you have any concerns about our use of your personal data, you can make a complaint to us using the contact details at the top of this privacy notice.</p>
<p>If you remain unhappy with how weve used your data after raising a complaint with us, you can also complain to the ICO.</p>
<h3>The ICOs address:</h3>
<p>Information Commissioners Office</p>
<p>Wycliffe House</p>
<p>Water Lane</p>
<p>Wilmslow</p>
<p>Cheshire</p>
<p>SK9 5AF</p>
<p>Helpline number: 0303 123 1113</p>
<p>Website: <a href="https://www.ico.org.uk/make-a-complaint" alt="ICO make a complaint" aria-label="ICO make a complaint">https://www.ico.org.uk/make-a-complaint</a></p>
<p>Last updated</p>
<p>1 May 2024</p>
</div>
<!-- Include JavaScript -->
<script type="module" src="{{ url_for('static', filename='js/sections/legal.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/privacy_notice.js') }}"></script>
<!--
<script>
var hashPageCurrent = "{{ model.HASH_PAGE_ACCESSIBILITY_STATEMENT }}";
$(document).ready(function() {
hookupPageAccessibilityStatement();
});
</script>
-->
{% endblock %}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
<!doctype HTML><html lang="en"><head><title>public-website-of-precision-and-research-technology-systems-limited-report.html</title><meta charset="utf-8"><style>
table {
border-collapse: collapse;
width: 100%;
}
table,
td,
th {
border: 1px solid #3b3b3b;
}
td:not(:last-child),
th {
padding: 1em;
vertical-align: top;
text-align: left;
}
td:not([class]):last-child {
padding: 0 1em;
}
</style></head><body><div><main> <h1>Report</h1> <div><h2>About the Evaluation</h2> <dl><dt>Report Creator </dt><dd>Lord Edward Middleton-Smith </dd><dt>Evaluation Commissioner </dt><dd>Lord Edward Middleton-Smith </dd><dt>Evaluation date </dt><dd>Tue Apr 30 2024</dd></dl> </div> <div><h2>Executive Summary</h2> <div><span>Not provided</span></div> </div> <div><h2>Scope of the Evaluation</h2> <dl><dt>Website name </dt><dd>Public Website of Precision And Research Technology Systems Limited </dd><dt>Scope of the website </dt><dd>'All web content of the public mobile and desktop website of Precision And Research Technology Systems Limited located at https://www.partsltd.co.uk/ </dd><dt>WCAG Version </dt><dd>2.2 </dd><dt>Conformance target </dt><dd>AA </dd><dt>Accessibility support baseline </dt><dd>Google Chrome with NVDA, FireFox with NVDA, Ecosia mobile browser with TalkBack. </dd><dt>Additional evaluation requirements </dt><dd><span>Not provided</span></dd></dl> </div> <h2>Detailed Audit Results</h2> <h3>Summary</h3> <p>Reported on 55 of 55 WCAG 2.2 AA
Success Criteria.</p> <ul><li><span>41</span> <span>Passed</span></li><li><span>0</span> <span>Failed</span></li><li><span>0</span> <span>Cannot tell</span></li><li><span>14</span> <span>Not present</span></li><li><span>0</span> <span>Not checked</span></li></ul> <h3>All Results</h3> <h4>1 Perceivable</h4> <h5 id="guideline-11">1.1 Text Alternatives</h5> <table aria-labelledby="guideline-11"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-111">1.1.1: Non-text Content</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>All user input controls have descriptive names and v2 Google reCaptcha used with text label to identify to user that they must check the box to prove they are not a bot.</p>
</td> </tr></tbody> </table><h5 id="guideline-12">1.2 Time-based Media</h5> <table aria-labelledby="guideline-12"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-121">1.2.1: Audio-only and Video-only (Prerecorded)</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-122">1.2.2: Captions (Prerecorded)</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-123">1.2.3: Audio Description or Media Alternative (Prerecorded)</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-124">1.2.4: Captions (Live)</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-125">1.2.5: Audio Description (Prerecorded)</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr></tbody> </table><h5 id="guideline-13">1.3 Adaptable</h5> <table aria-labelledby="guideline-13"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-131">1.3.1: Info and Relationships</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Elements change in response to zoom and viewport dimensions properly. Aria-label provided for all images.</p>
</td> </tr><tr><th scope="row" id="criterion-132">1.3.2: Meaningful Sequence</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Flow layout keeps associated sections together but allows dynamic structure depending on size of elements relative to screen.</p>
</td> </tr><tr><th scope="row" id="criterion-133">1.3.3: Sensory Characteristics</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Content reads properly as raw text in default order. Aria-label provided for all images and names for all form input components.</p>
</td> </tr><tr><th scope="row" id="criterion-134">1.3.4: Orientation</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Orientation of content is not locked.</p>
</td> </tr><tr><th scope="row" id="criterion-135">1.3.5: Identify Input Purpose</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Appropriate visible labels used alongside name attributes for form input elements.</p>
</td> </tr></tbody> </table><h5 id="guideline-14">1.4 Distinguishable</h5> <table aria-labelledby="guideline-14"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-141">1.4.1: Use of Color</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Colour only used to convey meaning for text hyperlinks, which have alt-text attributes to identify their purpose and presence.</p>
</td> </tr><tr><th scope="row" id="criterion-142">1.4.2: Audio Control</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-143">1.4.3: Contrast (Minimum)</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Webpage text contrast assessed with tool at this website: <a href="https://accessibleweb.com/color-contrast-checker/">https://accessibleweb.com/color-contrast-checker/</a></p>
</td> </tr><tr><th scope="row" id="criterion-144">1.4.4: Resize text</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>All webpages can be scaled to up to 500% while maintaining structure and visible components.</p>
</td> </tr><tr><th scope="row" id="criterion-145">1.4.5: Images of Text</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-1410">1.4.10: Reflow</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Flex layout forces only vertical scrolling at required viewport dimensions.</p>
</td> </tr><tr><th scope="row" id="criterion-1411">1.4.11: Non-text Contrast</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Strong borders used for form input components.</p>
</td> </tr><tr><th scope="row" id="criterion-1412">1.4.12: Text Spacing</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Content becomes vertically scrollable as necessary.</p>
</td> </tr><tr><th scope="row" id="criterion-1413">1.4.13: Content on Hover or Focus</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Hamburger menu button for navigation overlay used. The button remains stationary with no elements above it, throughout use of navigation.</p>
</td> </tr></tbody> </table><h4>2 Operable</h4> <h5 id="guideline-21">2.1 Keyboard Accessible</h5> <table aria-labelledby="guideline-21"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-211">2.1.1: Keyboard</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Tab indices set to enable correct transition around page by keyboard. Other keyboard shortcuts not changed.</p>
</td> </tr><tr><th scope="row" id="criterion-212">2.1.2: No Keyboard Trap</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Tab indices set to enable correct transition around page by keyboard.</p>
</td> </tr><tr><th scope="row" id="criterion-214">2.1.4: Character Key Shortcuts</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Tab indices set to enable correct transition around page by keyboard. Other keyboard shortcuts not changed, and can be set by user's device settings.</p>
</td> </tr></tbody> </table><h5 id="guideline-22">2.2 Enough Time</h5> <table aria-labelledby="guideline-22"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-221">2.2.1: Timing Adjustable</th> <td> <p><span>Result:</span> Not present</p> </td> <td> <p>Observations:</p> <p>No session time limits imposed on user.</p>
</td> </tr><tr><th scope="row" id="criterion-222">2.2.2: Pause, Stop, Hide</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr></tbody> </table><h5 id="guideline-23">2.3 Seizures and Physical Reactions</h5> <table aria-labelledby="guideline-23"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-231">2.3.1: Three Flashes or Below Threshold</th> <td> <p><span>Result:</span> Passed</p> </td> <td> </td> </tr></tbody> </table><h5 id="guideline-24">2.4 Navigable</h5> <table aria-labelledby="guideline-24"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-241">2.4.1: Bypass Blocks</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-242">2.4.2: Page Titled</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Descriptive titles used on all webpages.</p>
</td> </tr><tr><th scope="row" id="criterion-243">2.4.3: Focus Order</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Keyboard tab indices set for logical navigation around pages.</p>
</td> </tr><tr><th scope="row" id="criterion-244">2.4.4: Link Purpose (In Context)</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Descriptive aria-label provided for all text hyperlinks.</p>
</td> </tr><tr><th scope="row" id="criterion-245">2.4.5: Multiple Ways</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Navigation on all webpages and company logo links to home page.</p>
</td> </tr><tr><th scope="row" id="criterion-246">2.4.6: Headings and Labels</th> <td> <p><span>Result:</span> Passed</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-247">2.4.7: Focus Visible</th> <td> <p><span>Result:</span> Passed</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-2411">2.4.11: Focus Not Obscured (Minimum)</th> <td> <p><span>Result:</span> Passed</p> </td> <td> </td> </tr></tbody> </table><h5 id="guideline-25">2.5 Input Modalities</h5> <table aria-labelledby="guideline-25"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-251">2.5.1: Pointer Gestures</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-252">2.5.2: Pointer Cancellation</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Up event used to trigger events across website.</p>
</td> </tr><tr><th scope="row" id="criterion-253">2.5.3: Label in Name</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Input label for attributes used to associate with input elements.
Aria-label attributes used for text hyperlinks.</p>
</td> </tr><tr><th scope="row" id="criterion-254">2.5.4: Motion Actuation</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-257">2.5.7: Dragging Movements</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-258">2.5.8: Target Size (Minimum)</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Minimum control dimension is 27 CSS pixels.</p>
</td> </tr></tbody> </table><h4>3 Understandable</h4> <h5 id="guideline-31">3.1 Readable</h5> <table aria-labelledby="guideline-31"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-311">3.1.1: Language of Page</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>English - Great Britain on all pages.</p>
</td> </tr><tr><th scope="row" id="criterion-312">3.1.2: Language of Parts</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>No language changes across website.</p>
</td> </tr></tbody> </table><h5 id="guideline-32">3.2 Predictable</h5> <table aria-labelledby="guideline-32"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-321">3.2.1: On Focus</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>No change of context initiated except by button click to navigate to submit a form and/or navigate to a new page.</p>
</td> </tr><tr><th scope="row" id="criterion-322">3.2.2: On Input</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>No change of context initiated except by button click to navigate to submit a form and/or navigate to a new page.</p>
</td> </tr><tr><th scope="row" id="criterion-323">3.2.3: Consistent Navigation</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Navigation component and mechanisms shared across all pages.</p>
</td> </tr><tr><th scope="row" id="criterion-324">3.2.4: Consistent Identification</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Classes and CSS styles used to group collections of elements by purpose and functionality.</p>
</td> </tr><tr><th scope="row" id="criterion-326">3.2.6: Consistent Help</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Contact us button provided in a consistent format.</p>
</td> </tr></tbody> </table><h5 id="guideline-33">3.3 Input Assistance</h5> <table aria-labelledby="guideline-33"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-331">3.3.1: Error Identification</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Each input element has an associated error display label which are triggered when input validation is not met.</p>
</td> </tr><tr><th scope="row" id="criterion-332">3.3.2: Labels or Instructions</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Each user input has a descriptive label.</p>
</td> </tr><tr><th scope="row" id="criterion-333">3.3.3: Error Suggestion</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Text description of incomplete required fields is provided. Description of what caused error is issued when it involves simple regular expression validation.</p>
</td> </tr><tr><th scope="row" id="criterion-334">3.3.4: Error Prevention (Legal, Financial, Data)</th> <td> <p><span>Result:</span> Not present</p> </td> <td> </td> </tr><tr><th scope="row" id="criterion-337">3.3.7: Redundant Entry</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>No redundant data entry required. User's browser cache stores form data for rapid re-entry on crash or any other occasion.</p>
</td> </tr><tr><th scope="row" id="criterion-338">3.3.8: Accessible Authentication (Minimum)</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Alternative sign in methods provided, including recovery by code by phone and email.</p>
</td> </tr></tbody> </table><h4>4 Robust</h4> <h5 id="guideline-41">4.1 Compatible</h5> <table aria-labelledby="guideline-41"><tbody><tr><th scope="col">Success Criterion</th> <th scope="col">Result</th> <th scope="col">Observations</th> </tr> <tr><th scope="row" id="criterion-412">4.1.2: Name, Role, Value</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Aria-label attribute maintained for all images and text hyperlinks. Label for attribute used to associate input elements with descriptive labels.</p>
</td> </tr><tr><th scope="row" id="criterion-413">4.1.3: Status Messages</th> <td> <p><span>Result:</span> Passed</p> </td> <td> <p>Observations:</p> <p>Success feedback provided on form submission, with descriptive errors on failure.</p>
</td> </tr></tbody> </table> <h2>Sample of Audited Web Pages</h2> <ol><li><span>Home</span> - <span>https://www.partsltd.co.uk/</span> </li><li><span>Contact us</span> - <span>https://www.partsltd.co.uk/contact</span> </li><li><span>Services</span> - <span>https://www.partsltd.co.uk/services</span> </li><li><span></span> - <span></span> </li></ol> <h2>Web Technology</h2> <p>HTML,CSS,JavaScript,python Flask</p> <h2>Recording of Evaluation Specifics</h2> <p>Not provided</p> </main></div></body></html>

View File

@@ -0,0 +1,68 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
<!-- Include Stylesheets -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/store.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/store/basket.css') }}">
<!-- HTML content -->
<div class="{{ model.FLAG_CARD }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div id="{{ model.ID_CONTAINER_INFO_DELIVERY }}" class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}" style="border-bottom: 1px black;">
<h2>Delivery Information</h2>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
Valid delivery information not submitted
</div>
</div>
<div id="{{ model.ID_CONTAINER_INFO_BILLING }}" class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}" style="border-bottom: 1px black;">
<h2>Billing Information</h2>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
Valid billing information not submitted
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }}">
<div id="{{ model.ID_BASKET_CONTAINER }}">
{% include 'components/store/_basket.html' %}
</div>
<!-- Comes with basket block
<div class="{{ model.FLAG_CONTAINER }}">
<!-- subtotal --
<h2 id="id_basket_total">Order total: £{{ model.OUTPUT_BASKET_TOTAL() }}</h2>
<!-- checkout button - hidden unless valid details entered everywhere above --
<button type="submit" class="{{ model.FLAG_BTN_SUBMIT }}">Complete Purchase</button>
</div>
-->
</div>
</div>
</div>
{% set form = model.form_delivery %}
{% set overlay_id = model.id_overlay_info_delivery %}
{% set overlay_title = 'Delivery Information' %}
{% include 'components/common/temporary/_overlay_address.html' %}
{% set form = model.form_billing %}
{% set overlay_id = model.id_overlay_info_billing %}
{% set overlay_title = 'Billing Information' %}
{% include 'components/common/temporary/_overlay_address.html' %}
<!-- Include JavaScript -->
<script src="{{ url_for('routes_store.scripts_section_store') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/store/basket.js') }}"></script>
{% set block_id = 'checkout' %}
{% include 'layouts/_shared_store.html' %}
<!--
<script>
var hashPageCurrent = "{{ model.HASH_PAGE_STORE_BASKET }}";
$(document).ready(function() {
console.log('Hooking up store basket review page...');
hookupStorePageBasket();
// hookupStorePageBilling();
});
</script>
-->
{% endblock %}

View File

@@ -0,0 +1,43 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
<!-- Include Stylesheets -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/store.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/store/checkout_success.css') }}">
<!-- HTML content -->
<div class="{{ model.FLAG_CARD }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div id="{{ model.ID_CONTAINER_INFO_DELIVERY }}" class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}" style="border-bottom: 1px black;">
<h2>Order successful!</h2>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<div class="{{ model.FLAG_LABEL }}"><strong>Order reference: {{ model.CHECKOUT_SESSION.ID }}</strong></div>
<div class="{{ model.FLAG_LABEL }}">You will receive an order acknowledgement by email</div>
</div>
{% if model.IS_USER_LOGGED_IN %}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_ROW }}">
<h3>Your order:</h3>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Include JavaScript -->
<script src="{{ url_for('routes_store.scripts_section_store') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/store/checkout_success.js') }}"></script>
{% set block_id = 'checkout' %}
{% include 'layouts/_shared_store.html' %}
<!--
<script>
var hashPageCurrent = "{{ model.HASH_PAGE_STORE_BASKET }}";
$(document).ready(function() {
console.log('Hooking up store checkout success page...');
hookupStorePageCheckoutSuccess();
});
</script>
-->
{% endblock %}

View File

@@ -0,0 +1,7 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
{% include 'components/store/_home_body.html' %}
{% endblock %}

View File

@@ -0,0 +1,96 @@
{% extends 'layouts/layout.html' %}
{% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/store.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/store/product_categories.css') }}">
<form id="{{ model.ID_FORM_FILTERS }}" class="{{ model.FLAG_FILTER }} {{ model.FLAG_ROW }} {{ model.FLAG_CARD }}" action="{{ url_for('routes_store_product_category.save_category') }}" method="POST"> <!-- {{ model.FLAG_CONTAINER }} -->
{{ model.form_filters.hidden_tag() }}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }} {{ model.FLAG_FILTER }}">
{{ model.form_filters.is_not_empty.label }}
{{ model.form_filters.is_not_empty() }}
{% for error in model.form_filters.is_not_empty.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }} {{ model.FLAG_FILTER }}">
{{ model.form_filters.active.label }}
{{ model.form_filters.active() }}
{% for error in model.form_filters.active.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }}">
{% set block_id = 'button_apply_filters' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<!--
-->
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_add' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_save' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_cancel' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<!--
<div class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
</div>
</div>
-->
</form>
<table id="{{ model.ID_TABLE_MAIN }}" class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
<thead>
<tr class="{{ model.FLAG_PRODUCT_CATEGORY }}">
<th class="{{ model.FLAG_DISPLAY_ORDER }}">Display Order</th>
<th class="{{ model.FLAG_CODE }}">Code</th>
<th class="{{ model.FLAG_NAME }}">Name</th>
<th class="{{ model.FLAG_DESCRIPTION }}">Description</th>
<th class="{{ model.FLAG_ACCESS_LEVEL }}">Access Level Required</th>
<th class="{{ model.FLAG_ACTIVE}}">Active</th>
</tr>
</thead>
<tbody>
{% set is_blank_row = False %}
{% for category in model.category_list.categories %}
{% include 'components/store/_row_product_category.html' %}
{% endfor %}
{% set is_blank_row = True %}
{% include 'components/store/_row_product_category.html' %}
</tbody>
</table>
{% include 'components/common/temporary/_overlay_confirm.html' %}
{% include 'components/common/temporary/_overlay_error.html' %}
<!-- Include JavaScript -->
<script src="{{ url_for('routes_store.scripts_section_store') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/store/product_categories.js') }}"></script>
<script>
// pass arguments from model to JS
var flagIsNotEmpty = "{{ model.FLAG_IS_NOT_EMPTY }}";
var optionsAccessLevel = {{ model.convert_list_objects_to_list_options(model.access_levels) | tojson | safe }};
</script>
{% endblock %}

View File

@@ -0,0 +1,155 @@
{% extends 'layouts/layout.html' %}
{% block page_body %}
<!--
{ % set product = model.product %}
{ % set permutation = product.get_permutation_selected() %}
-->
<script>console.log("test 1");</script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/store.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/store/product_permutations.css') }}">
<!-- HTML content -->
<form id="{{ model.ID_FORM_FILTERS }}" class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}" action="{{ url_for('routes_store_product_permutation.permutation_save') }}" method="POST"> <!-- {{ model.FLAG_CONTAINER }} -->
{{ model.form_filters.hidden_tag() }}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_filters.id_category.label }}
{{ model.form_filters.id_category() }}
{% for error in model.form_filters.id_category.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_filters.id_product.label }}
{{ model.form_filters.id_product() }}
{% for error in model.form_filters.id_product.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }}">
{{ model.form_filters.is_out_of_stock.label }}
{{ model.form_filters.is_out_of_stock() }}
{% for error in model.form_filters.is_out_of_stock.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }}">
{{ model.form_filters.quantity_min.label }}
{{ model.form_filters.quantity_min() }}
{% for error in model.form_filters.quantity_min.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }}">
{{ model.form_filters.quantity_max.label }}
{{ model.form_filters.quantity_max() }}
{% for error in model.form_filters.quantity_max.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<!--
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }} {{ model.FLAG_CONTAINER_INPUT }}">
{ { model.form_filters.submit() }}
</div>
-->
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_add' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_save' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_cancel' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<!--
<div class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
</div>
</div>
-->
</form>
<table id="{{ model.ID_TABLE_MAIN }}" class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
<thead>
<tr>
<th class="{{ model.FLAG_PRODUCT_CATEGORY }}">Category</th>
<th class="{{ model.FLAG_PRODUCT }}">Product</th>
<th class="{{ model.FLAG_VARIATIONS }}">Variations</th>
<th class="{{ model.FLAG_QUANTITY_STOCK }}">Quantity Stock</th>
<th class="{{ model.FLAG_QUANTITY_MIN }}">Quantity Min</th>
<th class="{{ model.FLAG_QUANTITY_MAX }}">Quantity Max</th>
<th class="{{ model.FLAG_COST_LOCAL }}">Cost</th>
<!-- <th>Price</th> -->
<th class="{{ model.FLAG_DETAIL }}">Link</th>
</tr>
</thead>
<tbody>
{% set is_blank_row = False %}
{% for category in model.category_list.categories %}
{% for product in category.products %}
{% for permutation in product.permutations %}
{% include 'components/store/_permutation.html' %}
{% endfor %}
{% endfor %}
{% endfor %}
{% set is_blank_row = True %}
{% include 'components/store/_permutation.html' %}
</tbody>
</table>
{% include 'components/common/temporary/_overlay_confirm.html' %}
{% include 'components/common/temporary/_overlay_error.html' %}
<!-- Include JavaScript -->
<script src="{{ url_for('routes_store.scripts_section_store') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/store/product_permutations.js') }}"></script>
<script>
// pass arguments from model to JS
/*
var idFilterCategory = "#{{ model.ID_FILTER_CATEGORY }}";
var idFilterProduct = "#{{ model.ID_FILTER_PRODUCT }}";
var idFilterIsOutOfStock = "#{{ model.ID_FILTER_IS_OUT_OF_STOCK }}";
var idFilterQuantityMin = "#{{ model.ID_FILTER_QUANTITY_MIN }}";
var idFilterQuantityMax = "#{{ model.ID_FILTER_QUANTITY_MAX }}";
*/
// var idFormFiltersPermutations = "#{ { model.ID_FORM_FILTERS_PERMUTATIONS } }";
var keyPermutations = "{{ model.KEY_PERMUTATIONS }}";
var productsByCategory = {{ model.category_list.get_product_option_lists_by_category() | tojson | safe }};
var listCategories = {{ model.category_list.to_list_categories() | tojson | safe }};
var listProducts = {{ model.category_list.to_product_option_list() | tojson | safe }};
var listVariations = {{ model.variations.to_list_variations() | tojson | safe }};
var listVariationTypes = {{ model.variations.to_list_variation_types() | tojson | safe }};
var dictVariations = Object.fromEntries(listVariations.map((variation, index) => [variation[attrIdVariation], variation]));
var dictVariationTypes = Object.fromEntries(listVariationTypes.map((variationType, index) => [variationType[attrIdVariationType], variationType]));
listVariations = listVariations.map((variation, index) => { return variation[attrIdVariation]; });
listVariationTypes = listVariationTypes.map((variationType, index) => { return variationType[attrIdVariationType]; });
/*
// hookup elements
$(document).ready(function() {
console.log('Hooking up store product permutation page...');
hookupStorePageProductPermutation();
});
*/
</script>
{% endblock %}

View File

@@ -0,0 +1,107 @@
{% extends 'layouts/layout.html' %}
{% block page_body %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/store.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/store/products.css') }}">
<form id="{{ model.ID_FORM_FILTERS }}" class="{{ model.FLAG_FILTER }} {{ model.FLAG_ROW }} {{ model.FLAG_CARD }}" action="{{ url_for('routes_store_product.save_product') }}" method="POST"> <!-- {{ model.FLAG_CONTAINER }} -->
{{ model.form_filters.hidden_tag() }}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_filters.id_category.label }}
{{ model.form_filters.id_category() }}
{% for error in model.form_filters.id_category.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }} {{ model.FLAG_FILTER }}">
{{ model.form_filters.is_not_empty.label }}
{{ model.form_filters.is_not_empty() }}
{% for error in model.form_filters.is_not_empty.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }} {{ model.FLAG_FILTER }}">
{{ model.form_filters.active.label }}
{{ model.form_filters.active() }}
{% for error in model.form_filters.active.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }} {{ model.FLAG_ROW }}">
{% set block_id = 'button_apply_filters' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<!--
-->
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_add' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_save' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_cancel' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
<!--
<div class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
</div>
</div>
-->
</form>
<table id="{{ model.ID_TABLE_MAIN }}" class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
<thead>
<tr class="{{ model.FLAG_PRODUCT }}">
<th class="{{ model.FLAG_DISPLAY_ORDER }}">Display Order</th>
<th class="{{ model.FLAG_PRODUCT_CATEGORY }}">Category</th>
<th class="{{ model.FLAG_NAME }}">Name</th>
<th class="{{ model.FLAG_VARIATIONS }}">Variations</th>
<th class="{{ model.FLAG_ACCESS_LEVEL }}">Access Level Required</th>
<th class="{{ model.FLAG_ACTIVE}}">Active</th>
</tr>
</thead>
<tbody>
{% set is_blank_row = False %}
{% for category in model.category_list.categories %}
{% for product in category.products %}
{% include 'components/store/_row_product.html' %}
{% endfor %}
{% endfor %}
{% set is_blank_row = True %}
{% include 'components/store/_row_product.html' %}
</tbody>
</table>
{% include 'components/common/temporary/_overlay_confirm.html' %}
{% include 'components/common/temporary/_overlay_error.html' %}
<!-- Include JavaScript -->
<script src="{{ url_for('routes_store.scripts_section_store') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/store/products.js') }}"></script>
<script>
// pass arguments from model to JS
var flagIsNotEmpty = "{{ model.FLAG_IS_NOT_EMPTY }}";
var optionsAccessLevel = {{ model.convert_list_objects_to_list_options(model.access_levels) | tojson | safe }};
</script>
{% endblock %}

View File

@@ -0,0 +1,141 @@
{% extends 'layouts/layout.html' %}
{% block page_body %}
<script>console.log("test 1");</script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/store.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/store/stock_items.css') }}">
<!-- HTML content -->
<form id="{{ model.ID_FORM_FILTERS_STOCK }}" class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}" action="{{ url_for('routes_store.stock_filter') }}" method="POST"> <!-- {{ model.FLAG_CONTAINER }} -->
{{ model.form_filters.hidden_tag() }}
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_filters.id_category.label }}
{{ model.form_filters.id_category() }}
{% for error in model.form_filters.id_category.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_filters.id_product.label }}
{{ model.form_filters.id_product() }}
{% for error in model.form_filters.id_product.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_filters.is_out_of_stock.label }}
{{ model.form_filters.is_out_of_stock() }}
{% for error in model.form_filters.is_out_of_stock.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_filters.quantity_min.label }}
{{ model.form_filters.quantity_min() }}
{% for error in model.form_filters.quantity_min.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{{ model.form_filters.quantity_max.label }}
{{ model.form_filters.quantity_max() }}
{% for error in model.form_filters.quantity_max.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
</div>
</div>
<!--
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }} {{ model.FLAG_CONTAINER_INPUT }}">
{ { model.form_filters.submit() }}
</div>
-->
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
<div class="{{ model.FLAG_CONTAINER_INPUT }}">
{% set block_id = 'button_save' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
{% set block_id = 'button_cancel' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
{% set block_id = 'button_add' %}
{% include 'components/common/buttons/_buttons_save_cancel.html' %}
</div>
</div>
</form>
<!--
<div class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
<div class="{{ model.FLAG_CONTAINER }} {{ model.FLAG_COLUMN }}">
</div>
</div>
-->
<table id="{{ model.ID_TABLE_MAIN }}" class="{{ model.FLAG_ROW }} {{ model.FLAG_CARD }}">
<thead>
<tr>
<th class="{{ model.FLAG_PRODUCT_CATEGORY }}">Category</th>
<th class="{{ model.FLAG_PRODUCT }}">Product</th>
<th class="{{ model.FLAG_VARIATIONS }}">Variations</th>
<th class="{{ model.FLAG_CURRENCY }}">Currency</th>
<th class="{{ model.FLAG_COST_LOCAL_VAT_INCL }}">Cost Local (VAT incl.)</th>
<th class="{{ model.FLAG_DATE_PURCHASED}}">Date Purchased</th>
<th class="{{ model.FLAG_DATE_RECEIVED }}">Date Received</th>
<th class="{{ model.FLAG_LOCATION_STORAGE }}">Storage Location</th>
<!--<th class="{{ model.FLAG_IS_SEALED }}">Is Sealed</th>-->
<th class="{{ model.FLAG_DATE_UNSEALED }}">Date Unsealed</th>
<th class="{{ model.FLAG_DATE_EXPIRATION }}">Date Expiration</th>
<!--<th class="{{ model.FLAG_IS_CONSUMED }}">Is Consumed</th>-->
<th class="{{ model.FLAG_DATE_CONSUMED }}">Date Consumed</th>
<th class="{{ model.FLAG_ACTIVE }}">Active</th>
</tr>
</thead>
<tbody>
{% set is_blank_row = False %}
{% for category in model.category_list.categories %}
{% for product in category.products %}
{% for permutation in product.permutations %}
{% for stock_item in permutation.stock_items %}
{% set is_blank_row = False %}
{% include 'components/store/_stock_item.html' %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% set is_blank_row = True %}
{% include 'components/store/_stock_item.html' %}
</tbody>
</table>
{% include 'components/common/temporary/_overlay_confirm.html' %}
{% include 'components/common/temporary/_overlay_error.html' %}
<!-- Include JavaScript -->
<script src="{{ url_for('routes_store.scripts_section_store') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/store/stock_items.js') }}"></script>
<script>
// pass arguments from model to JS
/*
var idFilterCategory = "#{{ model.ID_FILTER_CATEGORY }}";
var idFilterProduct = "#{{ model.ID_FILTER_PRODUCT }}";
var idFilterIsOutOfStock = "#{{ model.ID_FILTER_IS_OUT_OF_STOCK }}";
var idFilterQuantityMin = "#{{ model.ID_FILTER_QUANTITY_MIN }}";
var idFilterQuantityMax = "#{{ model.ID_FILTER_QUANTITY_MAX }}";
*/
var idFormFiltersPermutations = "#{{ model.ID_FORM_FILTERS_PERMUTATIONS }}";
var keyPermutations = "{{ model.KEY_PERMUTATIONS }}";
var dictListsProducts = {{ model.category_list.get_product_option_lists_by_category() | tojson | safe }};
var listCategories = {{ model.category_list.to_list_categories() | tojson | safe }};
var listProducts = {{ model.category_list.to_product_option_list() | tojson | safe }};
/*
// hookup elements
$(document).ready(function() {
console.log('Hooking up store stock page...');
hookupStorePageStockItem();
});
*/
</script>
{% endblock %}

View File

@@ -0,0 +1,114 @@
{% extends 'layouts/layout.html' %}
{% block title %}{{ model.title }}{% endblock %}
{% block page_body %}
{% set supplier = model.supplier %}
{% set block_id = 'styles' %}
{% include 'layouts/_shared_store.html' %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/store.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/page_store_supplier.css') }}">
<!-- HTML content -->
<div class="card">
<form id="{{ model.ID_FORM_SUPPLIER }}" class="{{ model.FLAG_CONTAINER }}" action="{{ url_for('routes_store.supplier') }}" method="POST">
<h2 class="label-title">Supplier</h2>
{{ model.form.hidden_tag() }}
<div class="card subcard">
<div class="container-input">
{{ model.form.name_company.label }}
{{ model.form.name_company(size=100) }}
{% for error in model.form.name_company.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
</div>
</div>
<div class="card subcard">
<h3>Contact</h3>
<div class="container-input">
{{ model.form.name_contact.label }}
{{ model.form.name_contact(size=50) }}
{% for error in model.form.name_contact.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
</div>
<div class="container-input">
{{ model.form.department_contact.label }}
{{ model.form.department_contact(size=50) }}
{% for error in model.form.department_contact.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
</div>
<div class="container-input">
{{ model.form.id_address.label }}
{{ model.form.id_address() }}
{% for error in model.form.id_address.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
<button id="{{ model.ID_BUTTON_ADD_SUPPLIER }}">Add new address</button>
</div>
<div class="container-input">
{{ model.form.phone_number.label }}
{{ model.form.phone_number(size=20) }}
{% for error in model.form.phone_number.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
</div>
<div class="container-input">
{{ model.form.fax.label }}
{{ model.form.fax(size=20) }}
{% for error in model.form.fax.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
</div>
<div class="container-input">
{{ model.form.email.label }}
{{ model.form.email(size=254) }}
{% for error in model.form.email.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
</div>
<div class="container-input">
{{ model.form.website.label }}
{{ model.form.website(size=254) }}
{% for error in model.form.website.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
</div>
<div class="container-input">
{{ model.form.id_currency.label }}
{{ model.form.id_currency() }}
{% for error in model.form.id_currency.errors %}
<p class="{{ model.FLAG_ERROR }}">{{ error }}</p>
{% endfor %}
</div>
<div class="container-input">
{{ model.form.recaptcha() }}
</div>
<div class="container-input">
{{ model.form.submit() }}
</div>
</div>
</form>
</div>
<!-- Include JavaScript -->
<script src="{{ url_for('routes_store.scripts_section_store') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/store/supplier.js') }}"></script>
<!--
<script>
// pass arguments from model to JS
var hashPageCurrent = "{{ model.HASH_PAGE_STORE_SUPPLIER }}";
/*
// hookup elements
$(document).ready(function() {
console.log('Hooking up store supplier page...');
hookupStorePageSupplier();
});
*/
</script>
-->
{% endblock %}

View File

@@ -0,0 +1,31 @@
<!-- v2a -->
{% extends 'layouts/layout.html' %}
{% block page_body %}
<!-- Include Stylesheet -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/sections/user.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/pages/user.css') }}" />
<!-- HTML content -->
<div>
{% set firstname = 'new user' if user.firstname is none else user.firstname %}
<h2 style="font-size: 24px; color: white; font-weight: normal;">Welcome, {{ firstname }}</h2>
{% set block_id = 'button_get_in_touch' %}
{% include 'layouts/_shared.html' %}
</div>
<!-- Include JavaScript -->
<script type="module" src="{{ url_for('static', filename='js/sections/user.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/pages/user.js') }}"></script>
<!--
<script>
var hashPageCurrent = "{{ model.HASH_PAGE_USER_ACCOUNT }}";
$(document).ready(function() {
hookupPageUserAccount();
});
</script>
-->
{% endblock %}