Here's the Gurobi code for the optimization problem.  The objective function and constraints are implemented as described.

```python
from gurobipy import Model, GRB

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

# Create variables
john_hours = m.addVar(lb=0, name="john_hours")
peggy_hours = m.addVar(lb=0, name="peggy_hours")
mary_hours = m.addVar(lb=0, name="mary_hours")
bill_hours = m.addVar(lb=0, name="bill_hours")

# Set objective function
m.setObjective(
    1 * john_hours**2 + 9 * john_hours * peggy_hours + 3 * john_hours * mary_hours + 8 * john_hours * bill_hours +
    8 * peggy_hours**2 + 4 * peggy_hours * mary_hours + 9 * peggy_hours * bill_hours +
    4 * mary_hours**2 + 6 * mary_hours * bill_hours +
    4 * bill_hours**2 +
    9 * john_hours + 9 * peggy_hours + 7 * mary_hours + 7 * bill_hours,
    GRB.MINIMIZE
)

# Add constraints
m.addConstr(9.81 * john_hours + 8.75 * peggy_hours >= 13, "c1")
m.addConstr(8.75 * peggy_hours + 1.26 * mary_hours >= 12, "c2")
m.addConstr(1.26 * mary_hours + 0.87 * bill_hours >= 19, "c3")
m.addConstr(9.81 * john_hours + 1.26 * mary_hours >= 31, "c4")
m.addConstr(9.81 * john_hours + 0.87 * bill_hours >= 20, "c5")
m.addConstr(9.81 * john_hours + 1.26 * mary_hours + 0.87 * bill_hours >= 25, "c6")
m.addConstr(9.81 * john_hours + 8.75 * peggy_hours + 1.26 * mary_hours + 0.87 * bill_hours >= 25, "c7")

m.addConstr(9.41 * john_hours + 0.53 * bill_hours >= 10, "c8")
m.addConstr(9.41 * john_hours + 3.47 * peggy_hours >= 6, "c9")
m.addConstr(9.41 * john_hours + 9.45 * mary_hours >= 12, "c10")
m.addConstr(3.47 * peggy_hours**2 + 0.53 * bill_hours**2 >= 14, "c11")
m.addConstr(9.41 * john_hours + 3.47 * peggy_hours + 9.45 * mary_hours + 0.53 * bill_hours >= 14, "c12")

m.addConstr(7.21 * john_hours**2 + 0.23 * bill_hours**2 >= 18, "c13")
m.addConstr(7.21 * john_hours + 1.75 * peggy_hours >= 11, "c14")
m.addConstr(1.75 * peggy_hours + 0.23 * bill_hours >= 13, "c15")
m.addConstr(7.21 * john_hours**2 + 1.75 * peggy_hours**2 + 1.49 * mary_hours**2 >= 18, "c16")
m.addConstr(1.75 * peggy_hours + 1.49 * mary_hours + 0.23 * bill_hours >= 18, "c17")
m.addConstr(7.21 * john_hours + 1.75 * peggy_hours + 1.49 * mary_hours >= 15, "c18")
m.addConstr(1.75 * peggy_hours + 1.49 * mary_hours + 0.23 * bill_hours >= 15, "c19")
m.addConstr(7.21 * john_hours + 1.75 * peggy_hours + 1.49 * mary_hours + 0.23 * bill_hours >= 15, "c20")

m.addConstr(-2 * john_hours + 3 * mary_hours >= 0, "c21")

m.addConstr(8.75 * peggy_hours + 1.26 * mary_hours <= 66, "c22")
m.addConstr(9.45 * mary_hours + 0.53 * bill_hours <= 66, "c23")
m.addConstr(9.41 * john_hours + 3.47 * peggy_hours <= 22, "c24")
m.addConstr(9.41 * john_hours**2 + 3.47 * peggy_hours**2 + 0.53 * bill_hours**2 <= 38, "c25")
m.addConstr(3.47 * peggy_hours + 9.45 * mary_hours + 0.53 * bill_hours <= 49, "c26")


# Optimize model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print('Obj: %g' % m.objVal)
    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))
elif m.status == GRB.INFEASIBLE:
    print('Optimization problem is infeasible.')
else:
    print('Optimization ended with status %d' % m.status)
```
