The live link can be found here.
This project was created as part of the Full Stack Software Development course offered by Code Institute.
- Candy Care Dublin
- Table of Contents
- Business Model
- Client Briefing
- The challenge
- Business Rules
- Marketing Strategy
- User Experience | UX
- User Interface | UI
- Project Architecture
- Technologies Used
- Testing π
- Deployment
- Credits
- Acknowledgements
- Disclaimer
- Author
B2C is the process of selling products or services from businesses to individual consumers. In this case, Candy Care Dublin is the business and the cakes/sweeties are our products.
Candy Care Dublin is a small company that started in a homely environment, with the idea of ββmaking homemade cakes for the people who lived nearby. However, people liked it and recommended it to other people. The business has expanded and today Candy Care Dublin has clients that go beyond the surroundings, as well as in other cities. The main means of publicizing the business is through a page on social networks (Facebook and Instagram) but, with the exponential growth of the business, there was a need to create a website, where people could access, see the products available, add to cart and finally checkout the purcharse. In this way, it would no longer be necessary to make sales via Instagram or Facebook, which would facilitate the administration of the business.
With this idea in mind, the person in charge of Candy Care Dublin hired me to develop a fullstack web application for the company.
An e-commerce web application is expected to be delivered that meets the following needs:
- A website whose purpose of the company is immediately understood by the user.
- Have a clear information on what the site is about and what it provides
- Have an easy navigation that is consistent throughout the website
- That the user can easily view the list of available products.
- That the user can easily add an specific item to the bag and identity the total cost of the purchase and all items they will receive.
- That the user can easily enter their payment information and be sure their personal and payment information are safe and secure.
For admin
- A functionality where the app admin can easily add one or more products, edit and/or delete an specific product.
The application's administrative functions are intended to manage what each user can do within the system. Permissions such as adding, editing or removing a property, for example, should under no circumstances be given to the user of the application. Such functionalities must be assigned exclusively to the administrator.
In the system, there will be the following user functionalities:
- Admin: has permission in all areas of the system.
- Users: can edit your own profile like change profile picture or change password. The user can list all the available products and sort them by Price and Name, add one or more products to their bag, identity the total cost of their purchase and all items they will receive, edit their bag by removing an specific product from the bag or adding another one, before checkout. The user should be able to receive an e-mail containing all the details about their purchase such as the list of products, the total cost, the delivery address, and so on.
- Admin:
- Add/Edit/Remove products.
- View all screens users can view as well.
- Users:
- Can log in and out of the application.
- Can manage their own profile.
- Can sign up to the newsletter form.
- Can add one or more products to their bag.
- Cover photo matches the Candy Care Dublin site.
- Profile pictute matches the Candy Care Dublin logo.
- Profile pictute matches the Candy Care Dublin logo.
In order to test the user's feeling when using the system, I applied the System Usability Scale test which includes 10 questions (in this case I added 3 more) which users of your website will answer. Participants will rank each question from 1 to 5 based on how much they agree with the statement they are reading. 5 means they agree completely, 1 means they disagree vehemently.
The questionnaire contains the following questions:
- I think I would like to use this system often.
- I found the system unnecessarily complex.
- I found the system easy to use.
- The features of this system were very well integrated.
- I found this system very inconsistent.
- I think most people would learn to use this system quickly.
- I found this website very cumbersome/awkward to use.
- I felt very confident using this system.
- I needed to learn a number of things before I could start using this system.
- It was easy to find the information I was looking for.
- I liked using the system interface.
- The system interface is enjoyable.
- The organization of system information is clear.
The form can be found in this link.
Five people, 3 women and 2 men, participated as volunteers in the survey and I share the result below.
- As a Shopper I want to be able to quickly identify deals, clearance items and special offers so that I can take advantage of special savings on products I would like to purchase.
- As a Shopper I want to be able to easily view the total of my purchases at any time so that be aware of how much I've already spent and avoid spending too much.
- As a Shopper I want to be able to easily register for an account so that I can have a personal account and be able to view my profile.
- As a Shopper I want to be able to easily login or logout from my account so that I can access my personal account information.
- As a Shopper I want to be able to easily recover my password in case I forget it so that I can recover access to my account.
- As a Shopper I want to be able to receive a confirmation email after registering so that I can verify that my account registration was successful.
- As a Shopper I want to be able to have a personalized user profile so that I can view my personal order history and order confirmations, and save my payment information.
- As a Shopper, I want to be able to sort the list of available products so that I can easily identify the best priced and categorically sorted products.
- As a Shopper, I want to be able to sort a specific category of product so that I can find the best-priced product in a specific category, or sort the products in that category by name.
- As a Shopper, I want to be able to sort multiple categories of products simultaneously so that I can find the best-priced or best-rated product across broad categories, such as "vegan" or "best sellers..
- As a Shopper, I want to be able to search for products by occasion, such as "birthdays" or "father's day".
- As a Shopper, I want to be able to easily see what I have searched for and the number of results so that I can quickly decide whether the product I want is available.
- As a Site Admin I want to be able to easily add a product so that I can add new items to my store.
- As a Site Admin I want to be able to see all existing products in a simple and easy manner.
- As a Site Admin I want to be able to edit/update a product so that I can change product prices, descriptions, images and other product criteria.
- As a Site Admin I want to be able to delete a product so that I can remove items that are no longer for sale.
- As a Developer I want to ensure that all application features work as they were implemented to work.
- As a Developer I want to ensure an authenticated user can access all required information correctly.
- As a Developer I want to work together with the administrator of the site for improvements for the user of the same.
As a primary font, I have chosen to use Roboto since Roboto has been designed for screens and includes 12 different font weights, from thin to black. Roboto also allows letters to take up as much space as it needs and ultimately, making for an improved experience for the user.
As a secondary font I have chosen to use Montserrat once Montserrat really shines for short pieces of all caps and the geometric simplicity of the letters. It is classified as a sans serif with 18 styles and 9 weights. This typeface is similar to Proxima Nova, Gotham, Futura, Arial and Helvetica.
The colors used throughout the project were extracted from the logo.
The wireframes were created in Figma which can be explored in details by clicking on the image below π
Due to time constraints I haven't been able to implement some of the changes I had planned.
The configuration file is one of the most important elements in any Django project. Knowing this, I decided to divide the configuration files structure into four files, one of them being the base file, which will contain everything that is needed in any project environment, be it production, development or testing. The other three files are for development, testing and finally production environments.
For that, create a folder called settings
inside the main project folder. Inside it, add the development.py
, testing.py
, production.py
and __init__.py
files. After that, take the base settings.py
file (which is in the root of the main project folder) and move it into the settings folder.
We will do this so that within the settings.py
file there are only elements that will be used in any of the environments, be it production, testing or development. However, whatever we need to create differently for each environment, we will put it in the files we just created.
For this project, both the development and test environments use the sqlite
database locally, while the production environment uses the Postgresql
database. That way, development and testing data doesn't mix with the data that will be in production. To do this kind of separation, we must place the database settings in their respective files.
See below how the project structure should look π
Now, we will need to open each file and add some settings.
from .settings import *
DEBUG = True
SECRET_KEY = os.environ.get("SECRET_KEY_DEVELOPMENT")
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
from .settings import *
DEBUG = True
SECRET_KEY = os.environ.get("SECRET_KEY_TESTING")
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
import os
import dj_database_url
from .settings import *
if os.path.exists("env.py"):
import env
DEBUG = False
SECRET_KEY = os.environ.get("SECRET_KEY_PRODUCTION")
ALLOWED_HOSTS = [os.environ.get("HEROKU_HOST")]
DATABASES = {'default': dj_database_url.parse(os.environ.get("HEROKU_DB"))}
Remembering that it is good programming practices not to leave SECRET_KEYS visible as this will result in the vulnerability of the application. Therefore, generate your own secret keys and configure them through environment variables.
You can use Python os
library to set your environment variables and then import them into the files, as I exemplify below:
import os
# SECRET KEYS
os.environ.setdefault("SECRET_KEY_DEVELOPMENT", "YOUR SECRET KEY")
os.environ.setdefault("SECRET_KEY_PRODUCTION", "YOUR SECRET KEY")
os.environ.setdefault("SECRET_KEY_TESTING", "YOUR SECRET KEY")
Once that's done, don't forget to remove the database settings and secret key from the settings.py
file.
It is worth mentioning that with this change in the project structure, you will need to change some more settings, so that the application works correctly. By default, in the settings.py
file, the BASE_DIR
variable looks like this: BASE_DIR = Path(__file__).resolve().parent.parent
. You will need to add a new .parent
as there has been a subdivision of the main project folder. So the BASE_DIR
variable should look like this: BASE_DIR = Path(__file__).resolve().parent.parent.parent
.
Also, in the wsgi.py
file you will need to notice that by default, the environment variable setting will look like this:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE",
"candycaredublin.settings")
application = get_wsgi_application()
Since three independent environments were created, we need to tell Django which environment we are going to work with. In this way, it is necessary to add, right after settings
, the environment name.
If working in the development environment, add .development
. If working in the testing environment, add .testing
and so on.
The same thing should apply to the manage.py
file which by default appears as
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'candycaredublin.settings')
# The rest of the code was hidden to optimize the page. Do not remove anything after this line.
...
If working in the development environment, add .development
after settings
. If working in the testing environment, add .testing
and so on.
Be sure to change it each time you are working in a different environment.
With the project configured correctly, when running the application, you will see something similar to this.
Title | Key In Database | Form Validation | Data Type |
---|---|---|---|
id | id | auto-increment | Primary Key |
Username | username | max_length 20 | CharField |
First Name | first_name | max_lenght 20 | CharField |
Last Name | last_name | max_lenght 20 | CharField |
E-mail Address | Must contain @ & .com etc | EmailField | |
Password | password | max length 50 | CharField |
Once a user registers in the system, a profile is automatically created for that user.
Title | Key In Database | Form Validation | Data Type |
---|---|---|---|
Id | id | auto-increment | Primary Key |
user | user | max length 50 | Foreign Key |
Default Phone Number | default_phone_number | max_length=20, null=True, blank=True | CharField |
Default Street Address 1 | default_street_address_1 | max_length=80, null=True, blank=True | CharField |
Default Street Address 2 | default_street_address_2 | max_length=80, null=True, blank=True | CharField |
Default Town or City | default_town_or_city | max_length=40, null=True, blank=True | CharField |
Default County | default_county | max_length=80, null=True, blank=True | CharField |
Default PostCode | default_postcode | max_length=20, null=True, blank=True | CharField |
Default Country | default_country | blank_label='Country', null=True, blank=True | CountryField |
Title | Key In Database | Form Validation | Data Type |
---|---|---|---|
Id | id | Auto-increment | Primary Key |
Category | category | 'Category', null=True, unique=True, on_delete=SET_NULL | Foreign Key |
Occasion | occasion | 'Occasion', null=True, unique=True, on_delete=SET_NULL | Foreign Key |
SKU | sku | default=uuid4, editable=False | UUIDField |
Name | name | max_length=254 | CharField |
Slug | slug | max_length=100, null=False, unique=True | SlugField |
Description | description | No validation | TextField |
Price | price | max_digits=6, null=False, unique=True | DecimalField |
Image | image | null=True, blank=True | ImageField |
Title | Key in Database | Form Validation | Data Type |
---|---|---|---|
Id | id | Auto-increment | Primary Key |
Name | name | max length=254 | CharField |
Friendly Name | friendly_name | max_length=254, null=True, blank= | CharField |
Title | Key in Database | Form Validation | Data Type |
---|---|---|---|
Id | id | Auto-increment | Primary Key |
Name | name | max length=254 | CharField |
Friendly Name | friendly_name | max_length=254, null=True, blank=True | CharField |
Title | Key in Database | Form Validation | Data Type |
---|---|---|---|
Id | id | Auto-increment | Primary Key |
Order Number | order_number | max length=32, null=False, editable=False | CharField |
User Profile | user_profile | UserProfile, null=True, blank=True, on_delete=SET_NULL, related_name="orders" | Foreign Key |
Fullname | full_name | max_length=50, null=False, blank=False | CharField |
max_length=254, null=False, blank=False, Must contain @ & .com etc | |||
Phone Number | phone_number | max_length=20, null=True, blank=True | CharField |
Country | country | blank_label='Country', null=False, blank=False | CountryField |
Post Code | postcode | max_length=20, null=False, blank=False | CharField |
Town or City | town_or_city | max_length=40, null=True, blank=True | CharField |
Street Address 1 | street_address_1 | max_length=80, null=True, blank=True | CharField |
Street Address 2 | street_address_2 | max_length=80, null=True, blank=True | CharField |
County | county | max_length=80, null=True, blank=True | CharField |
Date | date | auto_now_add=True | CharField |
Delivery Cost | delivery_cost | max_digits=6, decimal_places=2, null=False, default=0 | DecimalField |
Order Total | order_total | max_digits=10, decimal_places=2, null=False, default=0 | DecimalField |
Grand Total | grand_total | max_digits=10, decimal_places=2, null=False, default=0 | DecimalField |
Original Cart | original_cart | null=False, blank=False, default='' | TextField |
Stripe Payment ID | stripe_payment_id | max_length=254, null=False, blank=False, default='' | CharField |
Title | Key in Database | Form Validation | Data Type |
---|---|---|---|
Id | id | Auto-increment | Primary Key |
Order | order | Order, null=False, blank=False, on_delete=models.CASCADE, related_name='lineitems' | Foreign Key |
Product | product | Product, null=False, blank=False, on_delete=models.CASCADE | Foreign Key |
Quantity | quantity | null=False, blank=False, default=0 | IntegerField |
Line Itam Total | lineitem_total | max_digits=6, decimal_places=2, null=False, editable=False | DecimalField |
Title | Key in Database | Form Validation | Data Type |
---|---|---|---|
Id | id | Auto-increment | Primary Key |
User email | user_email | null=False, blank=False | EmailField |
Created At | created_at | auto_now_add=True | DateTimeField |
-
HTML5, or Hyper Text Markup Language: Used to construct the page within this app -
https://developer.mozilla.org/en-US/docs/Web/HTML -
CSS3, or Cascading Style Sheets: Used to style the various elements on the app's pages via coloring, fonts, spacing, etc. - https://www.w3.org/Style/CSS/Overview.en.html
-
Javascript: Used to create iterations across the page. - https://www.javascript.com/
-
Python 3: Used to develop all application logic. (https://www.python.org/)
Page tested using W3C HTML Checker. No errors or warnings were found.
Stylesheet tested using W3C CSS Validator. No errors or warnings were found.
All Javascript was tested using [JSHint]. No errors were found.
Three warnings related to Javascript version were raised but does not affect the code.
eversion
: This option is used to specify the ECMAScript version to which the code must adhere.
6
- To tell JSHint that your code uses ECMAScript 6 specific syntax. Note that not all browsers implement them.
You can find more explanation at JSHint Docs.
I used the Lighthouse automated tool from Developer Tools to perform site quality tests. The result is shown below.
Performance/Accessibilitycoverage.py v6.4.4, created at 2022-10-26 17:11 +0000
Module | statements | missing | excluded | coverage |
---|---|---|---|---|
candycaredublin/__init__.py | 0 | 0 | 0 | 100% |
candycaredublin/settings/__init__.py | 0 | 0 | 0 | 100% |
candycaredublin/settings/development.py | 8 | 0 | 0 | 100% |
candycaredublin/settings/settings.py | 29 | 0 | 0 | 100% |
candycaredublin/settings/testing.py | 8 | 0 | 0 | 100% |
candycaredublin/urls.py | 3 | 0 | 0 | 100% |
env.py | 8 | 0 | 0 | 100% |
home/__init__.py | 0 | 0 | 0 | 100% |
home/admin.py | 1 | 0 | 0 | 100% |
home/apps.py | 4 | 0 | 0 | 100% |
home/migrations/__init__.py | 0 | 0 | 0 | 100% |
home/models.py | 1 | 0 | 0 | 100% |
home/tests.py | 10 | 0 | 0 | 100% |
home/urls.py | 3 | 0 | 0 | 100% |
home/views.py | 3 | 0 | 0 | 100% |
manage.py | 12 | 2 | 0 | 83% |
products/__init__.py | 0 | 0 | 0 | 100% |
products/admin.py | 9 | 0 | 0 | 100% |
products/apps.py | 4 | 0 | 0 | 100% |
products/migrations/0001_initial.py | 6 | 0 | 0 | 100% |
products/migrations/__init__.py | 0 | 0 | 0 | 100% |
products/models/Models_Category.py | 10 | 1 | 0 | 90% |
products/models/Models_Product.py | 12 | 0 | 0 | 100% |
products/models/__init__.py | 3 | 0 | 0 | 100% |
products/tests/__init__.py | 0 | 0 | 0 | 100% |
products/tests/test_models.py | 29 | 0 | 0 | 100% |
products/tests/test_views.py | 13 | 0 | 0 | 100% |
products/urls.py | 3 | 0 | 0 | 100% |
products/views.py | 41 | 26 | 0 | 37% |
profiles/__init__.py | 0 | 0 | 0 | 100% |
profiles/admin.py | 1 | 0 | 0 | 100% |
profiles/apps.py | 4 | 0 | 0 | 100% |
>profiles/forms.py | 18 | 1 | 0 | 94% |
profiles/migrations/0001_initial.py | 8 | 0 | 0 | 100% |
profiles/migrations/__init__.py | 0 | 0 | 0 | 100% |
profiles/models/Models_Profile.py | 21 | 1 | 0 | 95% |
profiles/tests/__init__.py | 0 | 0 | 0 | 100% |
profiles/tests/test_forms.py | 9 | 0 | 0 | 100% |
profiles/tests/test_models.py | 41 | 0 | 0 | 100% |
profiles/tests/test_views.py | 13 | 0 | 0 | 100% |
profiles/urls.py | 3 | 0 | 0 | 100% |
profiles/views.py | 18 | 11 | 0 | 39% |
shopping_bag/__init__.py | 0 | 0 | 0 | 100% |
shopping_bag/admin.py | 1 | 0 | 0 | 100% |
shopping_bag/apps.py | 4 | 0 | 0 | 100% |
shopping_bag/migrations/__init__.py | 0 | 0 | 0 | 100% |
shopping_bag/models.py | 1 | 0 | 0 | 100% |
shopping_bag/templatetags/__init__.py | 0 | 0 | 0 | 100% |
shopping_bag/templatetags/bag_tools.py | 5 | 1 | 0 | 80% |
shopping_bag/tests/__init__.py | 0 | 0 | 0 | 100% |
shopping_bag/tests/test_views.py | 24 | 0 | 0 | 100% |
shopping_bag/urls.py | 3 | 0 | 0 | 100% |
shopping_bag/views.py | 17 | 11 | 0 | 35% |
Total | 411 | 54 | 0 | 87% |
No items found using the specified filter.
Some manual tests were performed to ensure the correct functioning of the application.
Implementation π¨: When I had set up the products.json and loaded into the database I could then view all available products. That way, I could ensure all ones were loaded as expected and that products information was visible when selected.
-
Test π: To test this, I went through each product and loaded the its information page, then looked at changing the url to ensure each item was loading correctly.
-
Result π: All products were loaded as expected to the main store page. When amending the url all products again loaded as expected. However, if I tried to access an product slug that didn't exist I was presented with a 404 page.
-
Verdict β : This test passed and no amendments were required.
Implementation π¨: The system admin will only be able to access the 'Add product' or 'Edit an existing product' pages if they are properly logged into the system.
-
Test π: To test this, I went through the browser and tried to access the endpoint
/api/add_product
or/api/edit_product
. -
Result π: As a result, I was automatically redirected to the login page and the endpoint that appears in the URL is
auth/login/?next=/api/add_product/
, which means that after being properly logged in I will be redirected to the 'Add product' page. -
Verdict β : This test passed and no amendments were required.
Implementation π¨: What happen if another user (non admin) try to access the 'Add product' or 'Edit an existing product' pages by the URL endpoints even if they are properly logged into the system?
-
Test π: To test this, I went through the browser and tried to access the endpoint
/api/add_product
or/api/edit_product
. Then I was automatically redirected to the login page and the endpoint that appears in the URL isauth/login/?next=/api/add_product/
. -
Result π: As a result, I was automatically redirected to the home page and an error message was shown: It appears you tried to access a page that you do not have permission. Please contact the store owner for assistance..
-
Verdict β : This test passed and no amendments were required.
Implementation π¨: To make sure that the user can navigate the site easily, I have tested the navigation of all items, links, buttons, etc., in order to ensure that the user does not get lost within the application sessions.
-
Test π: This test was performed in a systematic way, so that each page was navigated, clicked on all the links, in order to ensure that the user knew how to "find himself" within the site.
-
Result π: Every page and link was checked and each provided a positive result, in no time was the user sent to an unexpected destination.
-
Verdict β : This test completed as expected without bugs.
Issue ID | User Story | Requirement to be met | Requirement met | Test result |
---|---|---|---|---|
[#1] | View a list of products | As a Shopper I want to be able to view a list of products so that I can select some to purchase. | The list with all products is displayed as soon as the user clicks on "Shop" | Passed β |
[#2] | View individual product details | As a Shopper I want to be able to view individual product details so that I can identify the price, description, and product image. | A product's detail page is displayed once the user clicks on the chosen product. | Passed β |
[#3] | Identify deals | As a Shopper I want to be able to quickly identify deals, clearance items and special offers so that I can take advantage of special savings on products I would like to purchase. | This feature was not implemented in this project. | To be implemented π¨ |
[#4] | View total of my purchase | As a Shopper I want to be able to easily view the total of my purchases at any time so that I can be aware of how much I've already spent and avoid spending too much. | The user can see the total expenses as they add items to the shopping bag | Passed β |
[#5] | Register for an account | As a Site user I want to be able to easily register for an account so that I can have a personal account and be able to view my profile. | π Bug Report: Verification email is not sent after sign up. [#32] | Fixed β |
[#6] | login or logout | As a Site user I want to be able to easily login or logout from my account so that I can access my personal account information. | There's a 'Sign in' link in the top of the page where the user can easily login into the application. Once they're logged, a 'Sign out' link appears. | Passed β |
[#7] | Recover password | As a Site user I want to be able to easily recover my password in case I forget it so that I can recover access to my account. | The user is able to request a password recovery. | Passed β |
[#8] | Confirmation email after registering | As a Site user I want to be able to receive a confirmation email after registering so that I can verify that my account registration was successful. | π Bug Report: Verification email is not sent after sign up. [#32] | Fixed β |
[#9] | Personalized profile | As a Site user I want to be able to have a personalized user profile so that I can view my personal order history and order confirmations, and save my payment information. | Not implemented yet | Passed β |
[#10] | List of available products | As a Shopper I want to be able to sort the list of available products so that I can easily identify the best priced and categorically sorted products. | The user can see the list of all available products. | Passed β |
[#11] | Specific product category | As a Shopper I want to be able to sort a specific category of product so that I can find the best-priced or best-rated product in a specific category, or sort the products in that category by name. | This feature was not implemented in this project. | To be implemented π¨ |
[#12] | Multiple categories | As a Shopper I want to be able to sort multiple categories of products simultaneously so that I can find the best-priced or best-rated product across broad categories, such as "vegan" or "best sellers. | This feature was not implemented in this project. | To be implemented π¨ |
[#13] | Searching by occasion | As a shopper, I want to be able to search for products by occasion, such as "birthdays" or "father's day". | Feature partially implemented | Passed β |
[#14] | Feedback about my searching | As a Shopper I want to be able to easily see what I have searched for and the number of results so that I can quickly decide whether the product I want is available. | This feature was not implemented in this project. | To be implemented π¨ |
[#15] | Select the type and quantity | As a Shopper I want to be able to easily select the type and quantity of a chocolate/cake/sweet when purchasing it so that I can ensure I don't accidentally select the wrong product, quantity or type. | The user can update the shopping bag by adding quantity or removing items. | Passed β |
[#16] | Items in my shopping bag | As a Shopper I want to be able to view items in my bad to be purchased so that I can identity the total cost of my purchase and all items I will receive. | The user is able to clearly identify items in their bag before purchase as well as the total cost of the purchase. | Passed β |
[#17] | Make changes to a individual product | As a Shopper I want to be able to adjust the quantity of a individual product in my shopping bag so that I can easily make changes to my purchase before checkout. | The user can update the shopping bag by adding quantity or removing items. | Passed β |
[#18] | Payment information | As a Shopper I want to be able to easily enter my payment information so that I can check out quickly and with no hassles. | The user can easily enter their payment information. | Passed β |
[#19] | Personal and payment information are safe and secure | As a Shopper I want to be able to ensure my personal and payment information are safe and secure so that I can confidently provide the needed information to make a purchase. | The user can note a βhttpsβ at the beginning of the URL as well as the closed lock or unbroken key in the browser, which indicates all data will be secure and encrypted when submitted on that website. | Passed β |
[#20] | Order confirmation | As a Shopper I want to be able to view an order confirmation right after checkout so that I can verify that I haven't made any mistakes. | The user can see right after checkout an order summary, detailing the purchase. Also, the user receives an email with the order confirmation. | Passed β |
[#21] | Email confirmation after purchase. | As a Shopper I want to be able to receive an email confirmation after checking out so that I can keep the confirmation of what I have purchased for my records. | π Bug Report: Confirmation email not sent after checkout. [#31 | Fixed β |
[#22] | Add a product. | As a Store Owner I want to be able to add a product so that I can add new items to my store. | Once the store owner is logged in, it is possible to see the 'Product Management' link in the menu at the top of the page. Upon clicking, the admin will see the option to add a new product and edit an existing product. yet. | Passed β |
[#23] | Edit/update a product | As a Store Owner I want to be able to edit/update a product so that I can change product prices, descriptions, images and other product criteria. | Once the store owner is logged in, it is possible to see the 'Product Management' link in the menu at the top of the page. Upon clicking, the admin will see the option to add a new product and edit an existing product. yet. | Passed β |
[#24] | Delete a product | As a Store Owner I want to be able to delete a product so that I can remove items that are no longer for sale. | On the product editing page, at the bottom of the page you can see a field with information for deleting the product and a button to confirm the action. When clicking, a modal opens. yet. | Passed β |
[#25] | Searching by keywords. | As a Shopper I want to be able to search for a product by keywords such as "chocolate" or "cakes" so that I can receive recommendations of the best products according to my search criteria. | This feature won't be implemented in this project. | To be implemented π¨ |
[#26] | Action messages. | As a Shopper I want to be able to see a message informing me of an action I took on the site so that I can be aware of what I've done, such as when I remove an item or add an item to the shopping bag. | The user can see a message box pops up upon they make any change such as login/logout, add/update/delete a product, checkout, and so on. | Passed β |
[#33] | Add a newsletter signup form to the application. | As a Site user I want to be able to sign up for a newsletter so that I can stay on top of store news. | The user is able to sign up to the newsletter and their contact will be saved in the store database for further promotions and deals. yet. | Passed β |
Bug ID | Bug description | Current behaviour | Expected behaviour | Status |
---|---|---|---|---|
[#31] | Confirmation email not sent after checkout. | After the user completes the purchase, the purchase summary is displayed, however, the confirmation email is not sent. | After the user completes the purchase, it is expected that a confirmation email will be sent to the email provided at the time of purchase. | Fixed β |
[#32] | Verification email is not sent after sign up. | After the user signs up for the application, the verification email is not sent, resulting in a 404 error/crashing the application. | After the user signs up for the application, an email is expected to be sent to the email address provided at the time of sign-up. | Fixed β |
[#34] | Issues in sign in/sign up form are present | Once I access the sign in and sign up form, I see that there are navigability issues. The form works, but it's not visibly nice. | That it is visibly pleasant and without navigability problems. | Fixed β |
Bug ID | Bug description | Current behaviour | Expected behaviour | Status |
---|---|---|---|---|
[#31] | Confirmation email not sent after checkout. | After the user completes the purchase, the purchase summary is displayed, however, the confirmation email is not sent. | After the user completes the purchase, it is expected that a confirmation email will be sent to the email provided at the time of purchase. | Fixed β |
I was trying to connect the EMAIL_BACKEND
with the smtp service from Google. I already had use this services previously, so I set up all my credentials as usual in env.py
and exported them into settings.py
in order to send confirmation email to customers as well as send email to users upon their registration in the application, password recovery, and so on. Basically, I had to go into my Google Account and turn off the Less secupe apps verification. As a result, it was possible for third-party applications to gain access to the account. However, as per Google Documentation, which can be find here, "To help keep your account secure, from May 30, 2022, ββGoogle no longer supports the use of third-party apps or devices which ask you to sign in to your Google Account using only your username and password."
Given that, Google now requires that you have 2-Step-Verification enabled before you can set up an application password.
Note: If you are seeing a message βThe setting that you are looking for is not available for your account.β you should enable 2-Step-Verification first.
To fix it, I went through my Google Account, then Security and finally click in App passwords.
Once this is done, the App password window will open and you needed to generate a password to use in the application.
In the Select app dropdown menu, choose the app youβre using. You can also select Other and enter you own custom app name.
And then a password will be generated.
Make sure to copy and secure your generated password before click in Done.
Once this is done, just replace the default password of your email with the generated password and the application will be able to send emails using Google's smtp service.
By forking the GitHub Repository we make a copy of the original repository on our GitHub account to view and/or make changes without affecting the original repository by using the following steps...
-
Log in to GitHub and locate the GitHub Repository
-
In the Repository header (not at the top of the page), find a "Code" drop-down button. By clicking this button, you will find some options to clone the project repository. If you have your SSH key configured, choose to select the 'SSH' option and then click on the button right after the url. This button will copy the url and you will paste it in your terminal. If you have not configured your SSH key, you can choose to use the HTTPS protocol. In the same way as was done in the SSH option, when selecting 'HTTPS' you must click on the button right after the url to copy and then paste it into your terminal.
https://github.com/emidiovaleretto/candy-care-dublin-ecommerce.git
-
You should now have a copy of the original repository in your GitHub account.
-
Ideally you will want to work within a virtual environment to allow all packages to be kept within the project, this can be installed using the following command (please note some IDE's require pip3 instead of pip, please check with the documentation for your chosen IDE). To create a virtual environment, run the command
The installation of a virtualenv is done using pip, Python's package manager. It is with it that we install, remove and update packages in our projects. One note is that PIP is already installed when we are using IDE's like VSCode or PyCharm for our Python projects. So, just run the command below to install the virtualenv package on our computer:
pip install virtualenv
Once this is done, the package will be installed and ready to be used. Now you can create and manage your virtual environments.
The process of creating a virtualenv is quite simple and can be done using a single command, as seen below:
virtualenv your_virtualenv_name
Hint: I usually choose to name my virtual environments after the project name, rather than just writing 'venv', for example, the project is called MyBlogProject
, so the name of the virtual environment would be something like myblogenv
. If you need to return to a certain project after a while, you'll easily find the respective environment for that project. But that is totally up to you.
After creating a virtualenv, it's needed to activate it so that you can install the necessary packages for the project. To do this, run the following command:
source your_virtualenv_name/bin/activate (Linux ou macOS)
your_virtualenv_name/Scripts/Activate (Windows)
-
Once that's done, you need to install the project's dependencies. To do this, just run the following command:
pip3 install -r requirements.txt
-
Next you need to create a new file within the root directory called
env.py
. This file will contain all your secret keys, public keys, production database settings etc. Everything you think should not be exposed, you should put within this file.
So add the following lines to configure the environmental variables.
import os
# SECRET KEYS
os.environ.setdefault("SECRET_KEY_DEVELOPMENT", "YOUR SECRET KEY")
os.environ.setdefault("SECRET_KEY_PRODUCTION", "YOUR SECRET KEY")
os.environ.setdefault("SECRET_KEY_TESTING", "YOUR SECRET KEY")
# DATABASE URL
os.environ.setdefault("DATABASE_URL", "YOUR DATABASE URL")
-
To set up your database you will first need to run the following command:
python3 manage.py migrate
-
Then you need to create a superuser. This will allow you to access the application's admin panel. To do so, run the following command in your terminal and fill in the required information as prompted.
python3 manage.py createsuperuser
-
Now you should be able to run the server using the following command:
python3 manage.py runserver
If everything has been correctly configure you should not get a message giving you a link to your locally hosted site usually at http://127.0.0.1:8000
-
Finally, stop the server by pressing CTRL + C (or cmd + C on Mac) and run the following command to populate the database.
python3 manage.py loaddata category.json python3 manage.py loaddata occasions.json python3 manage.py loaddata products.json
After running this command, all information contained in the category.json
, occasions.json
and products.json
files will be saved in the database. Once that's done, run the python3 manage.py runserver
command again and you should be able to see the application working.
Before we move forward deploying the app to Heroku, it is recommended that you create a account on Stripe to use the payment processing functionality.
Note: the application is set up for test payments only.
Follow the steps below to create an account and retrieve the necessary keys that you will need later:
- Create an account at Stripe.
- Upon the account was created, goto the Account Dashboard.
- After that, click in Developers - you will find on the right side, at the top of the page -, then click in API keys.
You will see something like this:
- You will see the
Publishable key
andSecret key
. Caution: Make sure to DO NOT expose your Secret Key. Keep both keys private by using environment variables. Later, you will need them to set the HerokuConfig Vars
.
Stripe Key | Value |
---|---|
STRIPE_PUBLISHABLE_KEY | [Your Publishable Key] |
STRIPE_SECRET_KEY | [Your Stripe Secret Key] |
As a way of exemplifying how the payment functionality works, Stripe provides three types of payment events and their respective card numbers: successful payment, requires authentication and failed payment. Below you will see a table with these events and their card numbers. Note that when using the application, you MUST NOT enter any real card numbers. Therefore, Stripe already makes these cards available for testing.
Payment event | Card Number |
---|---|
Successful payment | 4242 4242 4242 4242 |
Requires authentication | 4000 0025 0000 3155 |
Failed payment | 4000 0000 0000 9995 |
Additional information:
- Use a valid future date, such as 12/34.
- Use any three-digit CVC.
- Use any value you like for other form fields (you may be asked to enter a ZIP code).
To set up heroku you must:
- If your requirements.txt file has not changed you can skip this step. Otherwise, in your terminal type
pip freeze > requirements.txt
then save and push the changes. - Go to Heroku.com and sign in to your account or create a free one at Heroku.
- From the heroku dashboard click the 'Create new app' button.
- Name the app something unique and choose what region you are in then click 'Create app'.
- In the resources section, in the add-ons field, type
Heroku Postgreslq
and select the free cost option. - Now, go to the settings tab and find the Config Vars section. Click 'Reveal Config Vars'.
In the settings tab, select Reveal Config Vars and copy the pre populated DATABASE_URL
into your settings.py
file in your project in the Config Vars in Heroku you will need to populate with the following keys:
Key | Value |
---|---|
SECRET_KEY_PRODUCTION | [Your Secret Key] |
DEBUG_PRODUCTION | False |
HEROKU_DB | [Your DATABASE URL] |
HEROKU_HOST | [Your Heroku Host] |
STRIPE_PUBLISHABLE_KEY | [Your Publishable Key] |
STRIPE_SECRET_KEY | [Your Stripe Secret Key] |
- Then head over to the deploy section by clicking deploy from the nav bar at the top of the page.
- From the 'Deployment method' section select GitHub and click 'Connect to GitHub'.
- Enter the repository name as it is in GitHub and click 'search'.
- Click the 'connect' button next to the repository to link it to heroku.
- To deploy, scroll down and click the 'Deploy Branch' button.
- Heroku will notify you that the app was successfully deployed with a button to view the app.
- If you want to rebuild your app automatically you can also select the 'Enable Automatic Deploys' button which will then rebuild the app every time you push any changes.
- Pexels - All images were downloaded from the website.
- Freepik - For icons.
- Table of contents
- Code Institute
I would like to take the opportunity to thank:
- To God first, to my family, friends and colleagues for their advice, support and help with testing.
- To my mentor Richard Wells for their feedback, advices, support and, above all, for their patience.
- All Code Institute Tutors, Student Care and Community on Slack for the peer reviews and advice.
*Disclaimer: The following Context is completely fictional, the company, the context, the CEO, the business questions exist only in my imagination.
**For educational purposes only.