To solve this optimization problem, we first need to define the decision variables and the objective function. Let's denote the number of hoodies to be made as \(H\) and the number of sweaters to be made as \(S\). The profit per hoodie is $20, and the profit per sweater is $15. Therefore, the total profit can be represented by the equation \(20H + 15S\), which we aim to maximize.

The constraints are based on the availability of fabric and dye. Each hoodie requires 3 units of fabric, and each sweater requires 2 units of fabric. Given that there are 500 units of fabric available, this constraint can be represented as \(3H + 2S \leq 500\). For the dye, each hoodie requires 2 units, and each sweater requires 1.5 units, with a total of 300 units of dye available, leading to the constraint \(2H + 1.5S \leq 300\).

Additionally, we have non-negativity constraints because the company cannot produce a negative number of hoodies or sweaters: \(H \geq 0\) and \(S \geq 0\).

Now, let's translate this problem into Gurobi code in Python:

```python
from gurobipy import *

# Create a new model
model = Model("Production_Optimization")

# Define the decision variables
H = model.addVar(lb=0, vtype=GRB.CONTINUOUS, name="Hoodies")
S = model.addVar(lb=0, vtype=GRB.CONTINUOUS, name="Sweaters")

# Define the objective function
model.setObjective(20*H + 15*S, GRB.MAXIMIZE)

# Add constraints
model.addConstr(3*H + 2*S <= 500, "Fabric_Constraint")
model.addConstr(2*H + 1.5*S <= 300, "Dye_Constraint")

# Optimize the model
model.optimize()

# Print the results
if model.status == GRB.OPTIMAL:
    print("Optimal solution found.")
    print(f"Number of Hoodies: {H.x}")
    print(f"Number of Sweaters: {S.x}")
    print(f"Total Profit: ${20*H.x + 15*S.x:.2f}")
else:
    print("No optimal solution found.")

```