To solve this problem, we first need to define the decision variables and the objective function. Let's denote the number of chairs as `c` and the number of nightstands as `n`. The profit per chair is $300, and the profit per nightstand is $500. Thus, the total profit can be represented as `300c + 500n`.

The constraints are based on the time availability for John and William. For John, each chair takes 2 hours, and each nightstand takes 5 hours. Since John has 30 hours available, we have `2c + 5n <= 30`. For William, each chair and each nightstand take 4 hours. With 40 hours available, the constraint is `4c + 4n <= 40`.

We also need to ensure that the number of chairs and nightstands made are non-negative since they cannot produce a negative quantity of items.

Now, let's formulate this problem in Gurobi using Python:

```python
from gurobipy import *

# Create a new model
m = Model("woodshop")

# Decision variables: Number of chairs (c) and number of nightstands (n)
c = m.addVar(vtype=GRB.INTEGER, name="chairs")
n = m.addVar(vtype=GRB.INTEGER, name="nightstands")

# Objective function: Maximize profit
m.setObjective(300*c + 500*n, GRB.MAXIMIZE)

# Constraints:
# 1. John's time constraint: 2c + 5n <= 30
m.addConstr(2*c + 5*n <= 30, name="john_time")

# 2. William's time constraint: 4c + 4n <= 40
m.addConstr(4*c + 4*n <= 40, name="william_time")

# 3. Non-negativity constraints for c and n
m.addConstr(c >= 0, name="non_neg_c")
m.addConstr(n >= 0, name="non_neg_n")

# Optimize the model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Chairs: {c.x}")
    print(f"Nightstands: {n.x}")
    print(f"Total Profit: ${300*c.x + 500*n.x:.2f}")
else:
    print("No optimal solution found")
```