Python Homework – Inventory program with nested dictionaries

Question:

Not sure if anyone can help. This is my first class so I’m very new to python and programming in general. I have a program for my Python class that I am stuck on. I have it doing the basics, but cannot figure out how to check the inventory quantity against the user inputted quantity. I know the nested if statement is incorrect ( I left that in so I had something) but that’s what I’m struggling with.

Also..I have only laid out the ending part of the program which is why my input is blank.

supplier_data is what was provided to us by the instructor.

    supplier_data = '{"parts": ["sprocket", "gizmo", "widget", "dodad"], "sprocket": 
    {"price": 3.99, "quantity": 32}, "gizmo": {"price": 7.98, "quantity": 2}, "widget": 
    {"price": 14.32, "quantity": 4}, "dodad": {"price": 0.5, "quantity": 0}}'


    import json
    json.loads(supplier_data)
    new_data = json.loads(supplier_data)
    print(new_data)

    print("Welcome to the parts ordering system, please enter in a part name, followed 
    by a quantity.n")
    print("Parts for order are:n")
    print("sprocket")
    print("gizmo")
    print("widget")
    print("dodadnn")

    order = {}
    inventory = True
    while inventory:
        part_input = input("Please enter in a part name, or quit to exit: ")
        if part_input in new_data.keys():
           quantity_input = int(input("Please enter in a quantity to order: "))
           order[part_input] = quantity_input
           print(order)
           if quantity_input >= new_data['sprocket']['quantity']:
                print("Error, only" + new_data['sprocket']['quantity'] + part_input + " 
                are available!")
                continue

        elif part_input == "quit":
             inventory = False

        else:
             print("Error, part does not exist, try again.")

This is what I get currently when I run it.

Welcome to the parts ordering system, please enter in a part name, followed by a quantity.

Parts for order are:

sprocket
gizmo
widget
dodad


Please enter in a part name, or quit to exit: sprocket
Please enter in a quantity to order: 3
{'sprocket': 3}
Please enter in a part name, or quit to exit: gizmo
Please enter in a quantity to order: 1
{'sprocket': 3, 'gizmo': 1}
Please enter in a part name, or quit to exit: widget
Please enter in a quantity to order: 8
{'sprocket': 3, 'gizmo': 1, 'widget': 8}
Please enter in a part name, or quit to exit: dodad
Please enter in a quantity to order: 1
{'sprocket': 3, 'gizmo': 1, 'widget': 8, 'dodad': 1}
Please enter in a part name, or quit to exit: quit
Your Order

Total: $
Thank you for using the parts ordering system!

Process finished with exit code 0
Asked By: Pythonnewbie

||

Answers:

The error I see is in the line

if quantity_input >= new_data['sprocket']['quantity']:
                print("Error, only" + new_data['sprocket']['quantity'] + part_input + " 
                are available!")

Replace the first key with part_input
This should be more like this

if quantity_input >= new_data[part_input]['quantity']:
                print("Error, only" + new_data[part_input]['quantity'] + part_input + " 
                are available!")

And just for user-friendliness just add this line inside your first if

print(f'{part_input} has quantity {supplier_data_dict[part_input]["quantity"]}')

Also, you have a logic error since your dictionary has ‘parts’ as another key. I can tell that it should not be regarded as a part type. I hope it helps

Answered By: MatErW3len

Here’s a solution that also performs the discount of each order’s quantity from supplier data, whenever an order is placed:


import json
import pprint

supplier_data = """{"parts": ["sprocket", "gizmo", "widget", "dodad"], 
"sprocket": {"price": 3.99, "quantity": 32}, "gizmo": {"price": 7.98, "quantity": 2}, 
"widget": {"price": 14.32, "quantity": 4}, "dodad": {"price": 0.5, "quantity": 0}}"""

json.loads(supplier_data)
new_data = json.loads(supplier_data)

print(f"{' Inventory Program ':=^50}")
print(
    "Welcome to the parts ordering system, please enter in a part name, "
    "followed "
    "by a quantity.n"
)
print(
    "Parts to order can be one of:n- "
    + "n- ".join(new_data["parts"])
    + "nn"
)

order = {}
inventory = True

while inventory:

    total_parts_left = sum(
        value.get("quantity", 0) if isinstance(value, dict) else 0
        for value in new_data.values()
    )
    if total_parts_left <= 0:
        pprint.pprint(
            "There are no more quantities left for any part. Exiting..."
        )
        inventory = False
        break

    part_input = input(
        "Please enter a part name, or quit/q to exitnAvailable parts:n- "
        + "n- ".join(
            filter(lambda key: new_data[key]["quantity"] > 0, new_data["parts"])
        )
        + "nnPart name:"
    )
    if part_input in new_data.keys():
        quantity_input = int(
            input(
                f"Please enter in a quantity to order ("
                f"{new_data[part_input]['quantity']:,} units available):"
            )
        )

        if quantity_input > new_data[part_input]["quantity"]:
            print(
                f"Error: only {new_data[part_input]['quantity']} units are "
                f"available for {part_input}!"
            )
            continue
        else:
            order[part_input] = order.get(part_input, 0) + quantity_input
            print(
                f'nYour order of {quantity_input:,} units for part "'
                f'{part_input}" was fullfilled!n'
            )
            pprint.pprint("Updated order:")
            pprint.pprint(order)
            print("n" + "=" * 50 + "n")

            # Note: comment the next line if you don't want to update the
            # `supplier_data`
            #       inventory of each part, after an order gets placed.
            new_data[part_input]["quantity"] -= quantity_input

    elif part_input in ["quit", "q"]:
        inventory = False
    else:
        print(
            f'Error: part "{part_input}" does not exist, choose one of the '
            f"following:n- "
            + "n- ".join(new_data["parts"])
            + "nnThen try again..."
        )

order_cost = sum(
    new_data[key]["price"] * value if isinstance(new_data[key], dict) else 0
    for key, value in order.items()
)

if order_cost > 0:
    print(f"n{' Your Order ':=^50}")
    pprint.pprint(order)
    print(f"Total Cost: ${order_cost:,.2f}")
else:
    print("You didn't order any part...")


Output Example:

"""
=============== Inventory Program ================
Welcome to the parts ordering system, please enter in a part name, followed by a quantity.

Parts to order can be one of:
- sprocket
- gizmo
- widget
- dodad


Please enter a part name, or quit/q to exit
Available parts:
- sprocket
- gizmo
- widget

Part name: sprocket
Please enter in a quantity to order (32 units available): 32

Your order of 32 units for part "sprocket" was fullfilled!

'Updated order:'
{'sprocket': 32}

==================================================

Please enter a part name, or quit/q to exit
Available parts:
- gizmo
- widget

Part name: gizmo
Please enter in a quantity to order (2 units available): 2

Your order of 2 units for part "gizmo" was fullfilled!

'Updated order:'
{'gizmo': 2, 'sprocket': 32}

==================================================

Please enter a part name, or quit/q to exit
Available parts:
- widget

Part name: widget
Please enter in a quantity to order (4 units available): 5
Error: only 4 units are available for widget!
Please enter a part name, or quit/q to exit
Available parts:
- widget

Part name: widget
Please enter in a quantity to order (4 units available): 4

Your order of 4 units for part "widget" was fullfilled!

'Updated order:'
{'gizmo': 2, 'sprocket': 32, 'widget': 4}

==================================================

'There are no more quantities left for any part. Exiting...'

=================== Your Order ===================
{'gizmo': 2, 'sprocket': 32, 'widget': 4}
Total Cost: $200.92
"""

Commented Solution

Here’s a commented version of the solution:

import json
import pprint

# 1. First, we load the `supplier_data` into a dictionary using `json.loads()`.
#    The loaded dictionary will be stored inside a variable named `new_data`
supplier_data = """{"parts": ["sprocket", "gizmo", "widget", "dodad"], 
"sprocket": {"price": 3.99, "quantity": 32}, "gizmo": {"price": 7.98, "quantity": 2}, 
"widget": {"price": 14.32, "quantity": 4}, "dodad": {"price": 0.5, "quantity": 0}}"""

json.loads(supplier_data)
new_data = json.loads(supplier_data)

print(f"{' Inventory Program ':=^50}")
print(
    "Welcome to the parts ordering system, please enter in a part name, "
    "followed "
    "by a quantity.n"
)
print(
    "Parts to order can be one of:n- "
    + "n- ".join(new_data["parts"])
    + "nn"
)

order = {}
inventory = True

# 2. Then, we create a `while` loop that will keep running until the user
#    decides to quit.
while inventory:

    # 3. Calculate the total number of parts left in the inventory.
    #    If there aren't any parts left, print a message to notify the user and
    #    exit the `while` loop.
    total_parts_left = sum(
        value. Get("quantity", 0) if isinstance(value, dict) else 0
        for value in new_data.values()
    )
    # 4. If the total number of parts left is less than or equal to 0, we print
    #    a message and exit the program.
    if total_parts_left <= 0:
        pprint.pprint(
            "There are no more quantities left for any part. Exiting..."
        )
        inventory = False
        break

    # 5. If the total number of parts left is greater than 0, we ask the user
    #    to enter a part name. The `filter` statement allows us to print the 
    #    parts that have a quantity greater than 0 left.
    part_input = input(
        "Please enter a part name, or quit/q to exitnAvailable parts:n- "
        + "n- ".join(
            filter(lambda key: new_data[key]["quantity"] > 0, new_data["parts"])
        )
        + "nnPart name:"
    )
    # 6. If the part name entered by the user is in the `supplier_data`
    #    dictionary, we ask the user to enter a quantity.
    if part_input in new_data.keys():
        quantity_input = int(
            input(
                f"Please enter in a quantity to order ("
                f"{new_data[part_input]['quantity']:,} units available):"
            )
        )

        # 7. If the quantity entered by the user is greater than the quantity
        #    available for that part, we print an error message and ask the user
        #    to enter a part name again.
        if quantity_input > new_data[part_input]["quantity"]:
            print(
                f"Error: only {new_data[part_input]['quantity']} units are "
                f"available for {part_input}!"
            )
            continue
        # 8. If the quantity entered by the user is less than or equal to the
        #    quantity available for that part, we add the part and quantity 
        #    to the `order` dictionary, print the updated order, and update the 
        #    quantity available for that part in the `supplier_data` dictionary.
        else:
            order[part_input] = order.get(part_input, 0) + quantity_input
            print(
                f'nYour order of {quantity_input:,} units for part "'
                f'{part_input}" was fullfilled!n'
            )
            pprint.pprint("Updated order:")
            pprint.pprint(order)
            print("n" + "=" * 50 + "n")

            # Note: comment the next line if you don't want to update the
            # `supplier_data`
            #       inventory of each part, after an order gets placed.
            new_data[part_input]["quantity"] -= quantity_input

    # 9. If the user enters `quit` or `q`, we exit the `while` loop.
    elif part_input in ["quit", "q"]:
        inventory = False
    # 10. If the part name entered by the user is not in the `supplier_data`
    #    dictionary, we print an error message and ask the user to enter a part
    #    name again.
    else:
        print(
            f'Error: part "{part_input}" does not exist, choose one of the '
            f"following:n- "
            + "n- ".join(new_data["parts"])
            + "nnThen try again..."
        )

# 11. After the `while` loop, we calculate the total cost of the order.
order_cost = sum(
    new_data[key]["price"] * value if isinstance(new_data[key], dict) else 0
    for key, value in order.items()
)

# 12. If the total cost of the order is greater than 0, we print the order
#     and the total cost. Total cost only equals zero if no quantity for any
#     part is specified. 
if order_cost > 0:
    print(f"n{' Your Order ':=^50}")
    pprint.pprint(order)
    print(f"Total Cost: ${order_cost:,.2f}")
# 13. If the total cost of the order is less than or equal to 0, meaning no
#     order was placed, we print a message saying that the user didn't
#     order any part.
else:
    print("You didn't order any part...")

Answered By: Ingwersen_erik
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.