## Problem Description and Formulation

The toy shop produces two types of products: plush toys and action figures. The production of each product requires assembly and packaging time. The goal is to determine the optimal number of plush toys and action figures to produce in order to maximize profit, given the available assembly and packaging times.

Let's denote:
- \(P\) as the number of plush toys,
- \(A\) as the number of action figures.

## Constraints:

1. Assembly time constraint: \(20P + 15A \leq 1200\)
2. Packaging time constraint: \(4P + 5A \leq 900\)
3. Non-negativity constraints: \(P \geq 0, A \geq 0\)

## Objective Function:

Maximize profit: \(4P + 4.50A\)

## Gurobi Code

```python
import gurobi

def solve_toy_shop_problem():
    # Create a new model
    model = gurobi.Model()

    # Define variables
    P = model.addVar(lb=0, name="Plush_Toys")  # Number of plush toys
    A = model.addVar(lb=0, name="Action_Figures")  # Number of action figures

    # Objective function: Maximize profit
    model.setObjective(4 * P + 4.50 * A, gurobi.GRB.MAXIMIZE)

    # Assembly time constraint
    model.addConstr(20 * P + 15 * A <= 1200, name="Assembly_Time")

    # Packaging time constraint
    model.addConstr(4 * P + 5 * A <= 900, name="Packaging_Time")

    # Optimize
    model.optimize()

    # Print solution
    if model.status == gurobi.GRB.OPTIMAL:
        print(f"Optimal solution found.")
        print(f"Plush Toys: {P.varValue}")
        print(f"Action Figures: {A.varValue}")
        print(f"Max Profit: {model.objVal}")
    else:
        print("No optimal solution found.")

if __name__ == "__main__":
    solve_toy_shop_problem()
```    model.optimize()

    # Print the solution
    if model.status == gurobi.GRB.OPTIMAL:
        print("Optimal solution found.")
        print(f"Plush toys: {x1.varValue}")
        print(f"Action figures: {x2.varValue}")
        print(f"Max profit: {model.objVal}")
    else:
        print("No optimal solution found.")

solve_toy_shop_problem()
```