Here's the Gurobi code to solve the optimization problem:

```python
import gurobipy as gp

# Create a new model
m = gp.Model("employee_scheduling")

# Create variables
laura_hours = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="laura_hours")
dale_hours = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="dale_hours")
john_hours = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="john_hours")

# Set objective function
m.setObjective(3.01 * laura_hours + 8.33 * dale_hours + 4.51 * john_hours, gp.GRB.MINIMIZE)

# Add constraints
m.addConstr(13 * laura_hours + 7 * dale_hours >= 4, "productivity_laura_dale_min")
m.addConstr(13 * laura_hours + 7 * dale_hours + 8 * john_hours >= 4, "productivity_total_min")
m.addConstr(14 * laura_hours + 3 * dale_hours >= 15, "work_quality_laura_dale_min")
m.addConstr(3 * dale_hours + 14 * john_hours >= 11, "work_quality_dale_john_min")
m.addConstr(14 * laura_hours + 3 * dale_hours + 14 * john_hours >= 19, "work_quality_total_min")
m.addConstr(5 * laura_hours + 14 * dale_hours >= 17, "organization_laura_dale_min")
m.addConstr(5 * laura_hours + 14 * dale_hours + 5 * john_hours >= 9, "organization_total_min")
m.addConstr(-9 * laura_hours + 1 * john_hours >= 0, "constraint_1")
m.addConstr(8 * dale_hours - 1 * john_hours >= 0, "constraint_2")
m.addConstr(8 * laura_hours - 4 * dale_hours >= 0, "constraint_3")
m.addConstr(13 * laura_hours + 8 * john_hours <= 30, "productivity_laura_john_max")
m.addConstr(13 * laura_hours + 7 * dale_hours <= 41, "productivity_laura_dale_max")
m.addConstr(13 * laura_hours + 7 * dale_hours + 8 * john_hours <= 42, "productivity_total_max")
m.addConstr(14 * dale_hours + 5 * john_hours <= 33, "organization_dale_john_max")
m.addConstr(5 * laura_hours + 5 * john_hours <= 39, "organization_laura_john_max")


# Optimize model
m.optimize()

# Print results
if m.status == gp.GRB.OPTIMAL:
    print('Optimal objective: %g' % m.objVal)
    print('Laura hours:', laura_hours.x)
    print('Dale hours:', dale_hours.x)
    print('John hours:', john_hours.x)
elif m.status == gp.GRB.INFEASIBLE:
    print('The model is infeasible.')
else:
    print('Optimization ended with status %d' % m.status)

```
