This is a simple Flask-based shopping cart system.
Python version: 3.12.4
- CRUD operations for products: Create, Read, Update, and Delete products from the pricing table.
- Calculates subtotal with special pricing rules: Includes support for special pricing (e.g., "3 for 140").
- JSON-based API endpoints: All operations are performed via JSON-based RESTful API endpoints.
-
POST /api/pricing
Description: Replace the entire pricing table with a new set of products. This clears the existing table before inserting new products.
Request Body: JSON list of products, each containing:code
(string): Unique product code.unit_price
(float): Price per unit.special_price
(string, optional): Special price in the format"x for y"
(e.g., "3 for 140"). Example
[ { "code": "A", "unit_price": 50, "special_price": "3 for 130" }, { "code": "B", "unit_price": 30, "special_price": "2 for 45" }, { "code": "C", "unit_price": 20 } ]
Response:
- Success:
201 Created
with a success message. - Error:
400 Bad Request
if the request format is incorrect or missing required fields.
-
PUT /api/pricing
Description: Update or add products in the pricing table. If a product with the given code exists, it will be updated; otherwise, it will be added.
Request Body: JSON list of products (same format as the POST request).
Example[ { "code": "A", "unit_price": 55, "special_price": "3 for 130" }, { "code": "D", "unit_price": 40 } ]
Response:
- Success:
200 OK
with a success message. - Error:
400 Bad Request
if the request format is incorrect or missing required fields.
- Success:
-
GET /api/pricing
Description: Retrieve the entire pricing table.
Response:- Success:
200 OK
with a list of all products in the pricing table.
- Success:
-
PATCH /api/pricing/
Description: Partially update a product's details by its code. Only the fields provided in the request body will be updated.
Request Body: JSON object with fields to update (e.g.,unit_price
,special_price
).
Example{ "unit_price": 25, "special_price": "5 for 100" }
Response:
- Success:
200 OK
with a success message. - Error:
404 Not Found
if the product with the given code does not exist.
- Success:
-
DELETE /api/pricing
Description: Delete specific products by their codes.
Request Body: JSON list of product codes to delete.
Example[ "A", "B" ]
Response:
- Success:
200 OK
with a list of deleted products. - Error:
404 Not Found
if none of the provided products exist.
- Success:
- POST /api/subtotal
Description: Calculate the subtotal based on a list of products and their quantities. Supports special pricing.
Request Body: JSON list of items, each containing:
code
(string): The product code.
quantity
(int): The quantity of the product to calculate the subtotal for.
Example
[
{
"code": "A",
"quantity": 3
},
{
"code": "B",
"quantity": 2
}
]
Response:
- Success:
200 OK
with the calculated subtotal.
- Error:
400 Bad Request
if the request format is incorrect or required fields are missing.
- Error:
404 Not Found
if a product code is not found.
If you are running the app locally, follow these steps:
-
Clone the repository:
git clone <repository-url>
cd spareroom-shopping-cart-kata
-
Set up a virtual environment:
Only required for local development (not necessary for Docker or Heroku deployments):
python3 -m venv .venv
source .venv/bin/activate # For Windows: .venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Set up PostgreSQL: Make sure PostgreSQL is running, and ensure the correct credentials are set in .env
or environment variables.
-
Run database migrations:
flask db upgrade
-
Run the Flask application:
- Mac OS:
export FLASK_APP=app.py
- Windows:
set FLASK_APP=app.py
Start the application:
python app.py
This will run the app locally at http://127.0.0.1:5000/
.
-
API Testing Example:
To test the /api/subtotal
endpoint locally:
curl -X POST http://localhost:5000/api/subtotal \
-H "Content-Type: application/json" \
-d '[{"code":"A","quantity":3},{"code":"B","quantity":3},{"code":"C","quantity":1},{"code":"D","quantity":2}]'
Alternatively, you can run the app using Docker:
-
Run the app using Docker Compose:
docker-compose up --build
-
Access the app at http://127.0.0.1:5000
.
-
API Testing Example (within container):
To test the /api/subtotal
endpoint inside Docker:
curl -X POST http://localhost:5000/api/subtotal \
-H "Content-Type: application/json" \
-d '[{"code":"A","quantity":3},{"code":"B","quantity":3},{"code":"C","quantity":1},{"code":"D","quantity":2}]'
The app is already deployed on Heroku:
- Heroku App URL: https://spareroom-shopping-cart-kata-bdd866b64262.herokuapp.com/
-
API Testing Example on Heroku:
To test the /api/subtotal
endpoint on Heroku:
curl -X POST https://spareroom-shopping-cart-kata-bdd866b64262.herokuapp.com/api/subtotal \
-H "Content-Type: application/json" \
-d '[{"code":"A","quantity":3},{"code":"B","quantity":3},{"code":"C","quantity":1},{"code":"D","quantity":2}]'
- Run unit tests:
python -m unittest discover -s tests
- Generate HTML report:
python tests/test_app.py