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

```python
from gurobipy import Model, GRB

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

# Create variables
bill_hours = m.addVar(vtype=GRB.INTEGER, name="bill_hours")
john_hours = m.addVar(vtype=GRB.CONTINUOUS, name="john_hours")

# Set objective function
m.setObjective(5.02 * bill_hours**2 + 4.37 * bill_hours * john_hours + 3.47 * john_hours**2 + 3.78 * john_hours, GRB.MAXIMIZE)

# Add constraints
m.addConstr(8 * bill_hours + 13 * john_hours <= 132, "c0")  # Total dollar cost per hour <= 132
m.addConstr(2 * bill_hours + 9 * john_hours <= 130, "c1")  # Total work quality rating <= 130
m.addConstr(6 * bill_hours + 12 * john_hours <= 123, "c2")  # Total likelihood to quit index <= 123

m.addConstr(8 * bill_hours**2 + 13 * john_hours**2 >= 35, "c3")  # Combined dollar cost per hour >= 35
m.addConstr(2 * bill_hours + 9 * john_hours >= 41, "c4")  # Combined work quality rating >= 41
m.addConstr(6 * bill_hours + 12 * john_hours >= 38, "c5")  # Combined likelihood to quit index >= 38

m.addConstr(3 * bill_hours - 6 * john_hours >= 0, "c6")

m.addConstr(8 * bill_hours**2 + 13 * john_hours**2 <= 123, "c7")  # Combined dollar cost per hour <= 123
m.addConstr(8 * bill_hours + 13 * john_hours <= 123, "c8")  # Combined dollar cost per hour <= 123
m.addConstr(2 * bill_hours**2 + 9 * john_hours**2 <= 80, "c9")  # Combined work quality rating <= 80
m.addConstr(2 * bill_hours + 9 * john_hours <= 80, "c10")  # Combined work quality rating <= 80
m.addConstr(6 * bill_hours + 12 * john_hours <= 71, "c11")  # Combined likelihood to quit index <= 71


# Optimize model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print('Obj: %g' % m.objVal)
    print('Bill Hours: %g' % bill_hours.x)
    print('John Hours: %g' % john_hours.x)
elif m.status == GRB.INFEASIBLE:
    print('The model is infeasible.')
else:
    print('Optimization ended with status %d' % m.status)

```
