Skip to content

H-jamesR2/receipt-processor-API

Repository files navigation

Rcpt Processor

Table of Contents:

  1. Description
  2. API-Specs-Summary
  3. Running-the-Server
  4. Testing-the-API
  5. Running-Unit-Tests

Description:

A webservice that fulfils the documented API. The API is described below. A formal definition is provided in the api.yml file, but the information in this README is sufficient for describing the problem statement.

Data does not need to persist when application stops. It is sufficient to store information in memory. Database installation should not be needed for testing the solution.

Language Selection

Company preferred language: Go

Instructions include how to get an environment in any OS that can run your project. For example, if you write your project in Javascript simply stating to "run npm start to start the application" was not sufficient, because the engineer may not have NPM. As a result, Provided a docker file and the required docker commands as a simple way to satisfy this requirement.

Submitting Solution

Provided a link to a public repository, such as GitHub or BitBucket, that contains code to the provided link through Greenhouse.


Summary-of-API-Specification

Endpoint: Process Rcpts

  • Path: /receipts/process
  • Method: POST
  • Payload: Rcpt JSON
  • Response: JSON containing an id for the receipt.

Description:

Takes in a JSON receipt (see example in the example directory) and returns a JSON object with an ID generated by your code.

The ID returned is the ID that should be passed into /receipts/{id}/points to get the number of points the receipt was awarded.

How many points should be earned are defined by the rules below.

Reminder: Data does not need to survive an application restart. This is to allow you to use in-memory solutions to track any data generated by this endpoint.

Example Response:

{ "id": "7fb1377b-b223-49d9-a31a-5a02701dd310" }

Endpoint: Get Points

  • Path: /receipts/{id}/points
  • Method: GET
  • Response: A JSON object containing the number of points awarded.

A simple Getter endpoint that looks up the receipt by the ID and returns an object specifying the points awarded.

Example Response:

{ "points": 32 }

Rules

These rules collectively define how many points are awarded to a receipt.

  • One point for every alphanumeric character in the retailer name.
  • 50 points if the total is a round dollar amount with no cents.
  • 25 points if the total is a multiple of 0.25.
  • 5 points for every two items on the receipt.
  • If the trimmed length of the item description is a multiple of 3, multiply the price by 0.2 and round up to the nearest integer. The result is the number of points earned.
  • 6 points if the day in the purchase date is odd.
  • 10 points if the time of purchase is after 2:00pm and before 4:00pm.

Examples

{
  "retailer": "Target",
  "purchaseDate": "2022-01-01",
  "purchaseTime": "13:01",
  "items": [
    {
      "shortDescription": "Mountain Dew 12PK",
      "price": "6.49"
    },{
      "shortDescription": "Emils Cheese Pizza",
      "price": "12.25"
    },{
      "shortDescription": "Knorr Creamy Chicken",
      "price": "1.26"
    },{
      "shortDescription": "Doritos Nacho Cheese",
      "price": "3.35"
    },{
      "shortDescription": "   Klarbrunn 12-PK 12 FL OZ  ",
      "price": "12.00"
    }
  ],
  "total": "35.35"
}
Total Points: 28
Breakdown:
     6 points - retailer name has 6 characters
    10 points - 4 items (2 pairs @ 5 points each)
     3 Points - "Emils Cheese Pizza" is 18 characters (a multiple of 3)
                item price of 12.25 * 0.2 = 2.45, rounded up is 3 points
     3 Points - "Klarbrunn 12-PK 12 FL OZ" is 24 characters (a multiple of 3)
                item price of 12.00 * 0.2 = 2.4, rounded up is 3 points
     6 points - purchase day is odd
  + ---------
  = 28 points

{
  "retailer": "M&M Corner Market",
  "purchaseDate": "2022-03-20",
  "purchaseTime": "14:33",
  "items": [
    {
      "shortDescription": "Gatorade",
      "price": "2.25"
    },{
      "shortDescription": "Gatorade",
      "price": "2.25"
    },{
      "shortDescription": "Gatorade",
      "price": "2.25"
    },{
      "shortDescription": "Gatorade",
      "price": "2.25"
    }
  ],
  "total": "9.00"
}
Total Points: 109
Breakdown:
    50 points - total is a round dollar amount
    25 points - total is a multiple of 0.25
    14 points - retailer name (M&M Corner Market) has 14 alphanumeric characters
                note: '&' is not alphanumeric
    10 points - 2:33pm is between 2:00pm and 4:00pm
    10 points - 4 items (2 pairs @ 5 points each)
  + ---------
  = 109 points


Running-the-Server

Environment Setup

Requirements:

  • Docker
  • PostgreSQL

.env File Setup:

You must have a .env file in the dockerFiles and root directory containing the following:

DB_HOST=db
DB_USER=<your_db_user>
DB_PASSWORD=<your_db_password>
DB_NAME=<your_db_name>
PORT=8080

TEST_DB_HOST=localhost
TEST_DB_USER=postgres
TEST_DB_PASSWORD=<your_test_db_password>
TEST_DB_NAME=<your_test_db_name>
TEST_DB_PORT=5435

Reset Directives

To reset Docker, including volumes and images, use the following commands:

docker system df
docker-compose -f dockerFiles/docker-compose.yml down --rmi all -v --remove-orphans
docker system prune -a --volumes -f
docker system df

Building and Running the Docker Containers

To build and run the Docker containers, execute:

docker-compose -f dockerFiles/docker-compose.yml up --build

This will start the application on the specified port (default is 8080).

Testing-the-API

Optional (if you have jq [library]):

add " | jq" at end of each curl statement below to get cleaner json format...

Create a new receipt (POST):

curl -X POST http://localhost:8080/receipts/process -H "Content-Type: application/json" -d '{
    "retailer": "Target",
    "purchaseDate": "2022-01-01",
    "purchaseTime": "13:01",
    "total": "35.35",
    "items": [
        {
            "sku": "TGT-BVRG-MTNDEW-SODA-SIZE-12PK-00001",
            "shortDescription": "Mountain Dew 12PK",
            "quantity": 1,
            "pricePaid": "6.49"
        },
        {
            "sku": "TGT-FOOD-EMILS-PIZZA-TYPE-CHEESE-00002",
            "shortDescription": "Emils Cheese Pizza",
            "quantity": 1,
            "pricePaid": "12.25"
        },
        {
            "sku": "TGT-FOOD-KNORR-SOUP-FLVR-CHICKEN-00003",
            "shortDescription": "Knorr Creamy Chicken",
            "quantity": 1,
            "pricePaid": "1.26"
        },
        {
            "sku": "TGT-SNCK-DORITOS-CHIPS-FLVR-NACHO-00004",
            "shortDescription": "Doritos Nacho Cheese",
            "quantity": 1,
            "pricePaid": "3.35"
        },
        {
            "sku": "TGT-BVRG-KLARBRUNN-WATER-SIZE-12PK-00005",
            "shortDescription": "   Klarbrunn 12-PK 12 FL OZ  ",
            "quantity": 1,
            "pricePaid": "12.00"
        }
    ]
}'

Creating a new receipt (POST) from stored JSON file:

curl -X POST http://localhost:8080/receipts/process -H "Content-Type: application/json" -d @[Directory of JSON Files]/[JSON File]
Example:
curl -X POST http://localhost:8080/receipts/process -H "Content-Type: application/json" -d @examples/readme-mmCornerMarket-receipt.json

Retrieve (GET) the list of all receipts:

curl http://localhost:8080/receipts/

Retrieve (GET) a specific receipt by ID (replace RECEIPT_ID with the actual ID returned in the response):

curl http://localhost:8080/receipts/RECEIPT_ID

Retrieve (GET) the points for a specific receipt by ID (replace RECEIPT_ID with the actual ID returned in the response):

curl http://localhost:8080/receipts/RECEIPT_ID/points

Running a command to a non-existent endpoint should return an Endpoint not found.

curl http://localhost:8080/rcpt

Here’s the updated section for running unit tests, including the instruction to change into the model directory first:


Running-Unit-Tests

Requirements:

  • PostgreSQL
  • Postgres App (Optional but Ideal)

Running Tests Locally in model

To run unit tests, follow these steps:

  1. Ensure PostgreSQL is Running: Before running the tests, make sure that PostgreSQL is running and configured with the correct host, user, password, database name, and port as specified in your .env file.
  • Ideally do this in the Postgres app.
  • You are free to create a Server in your Postgres app with matching host, user, password, database name, and port as is in receipt_test.go or change the "DBConfig" to your needs.
  1. Navigate to the model Directory: Change into the model directory where the test files are located:

    cd model
  2. Reset the Test Database: Ensure the test database is reset to avoid conflicts with existing data.

  3. Run the Tests: Use the following command to run the tests:

    go test -v ./...
  4. Check Coverage: To check the test coverage, run:

    go test -coverprofile=coverage.out
    go tool cover -html=coverage.out

About

GoLang REST API for practice with: MVC (design), Go (Language), REST-APIs, Docker, PostgreSQL (DB)

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors