```json
{
  "sym_variables": [
    ("x0", "hours worked by Peggy"),
    ("x1", "hours worked by Paul"),
    ("x2", "hours worked by Hank")
  ],
  "objective_function": "7*x0 + 3*x1 + 3*x2",
  "constraints": [
    "3*x0 + 2*x2 <= 27",
    "7*x1 + 2*x2 <= 27",
    "3*x0 + 7*x1 <= 34",
    "3*x0 + 7*x1 + 2*x2 <= 34",
    "x0 + x1 + 8*x2 >= 12",
    "x1 + 8*x2 <= 29",
    "x0 + x1 <= 33",
    "x0 + x1 + 8*x2 <= 33"
  ]
}
```

```python
from gurobipy import Model, GRB

# Create a new model
model = Model("Maximize Productivity and Paperwork")

# Create variables
peggy_hours = model.addVar(vtype=GRB.INTEGER, name="peggy_hours")
paul_hours = model.addVar(vtype=GRB.CONTINUOUS, name="paul_hours")
hank_hours = model.addVar(vtype=GRB.INTEGER, name="hank_hours")


# Set objective function
model.setObjective(7 * peggy_hours + 3 * paul_hours + 3 * hank_hours, GRB.MAXIMIZE)

# Add constraints
model.addConstr(3 * peggy_hours + 2 * hank_hours <= 27, "paperwork_peggy_hank")
model.addConstr(7 * paul_hours + 2 * hank_hours <= 27, "paperwork_paul_hank")
model.addConstr(3 * peggy_hours + 7 * paul_hours <= 34, "paperwork_peggy_paul")
model.addConstr(3 * peggy_hours + 7 * paul_hours + 2 * hank_hours <= 34, "paperwork_total")
model.addConstr(peggy_hours + paul_hours + 8 * hank_hours >= 12, "productivity_min")
model.addConstr(paul_hours + 8 * hank_hours <= 29, "productivity_paul_hank")
model.addConstr(peggy_hours + paul_hours <= 33, "productivity_peggy_paul")
model.addConstr(peggy_hours + paul_hours + 8 * hank_hours <= 33, "productivity_total")


# Optimize model
model.optimize()

# Print results
if model.status == GRB.OPTIMAL:
    print('Optimal solution found:')
    print(f"Peggy hours: {peggy_hours.x}")
    print(f"Paul hours: {paul_hours.x}")
    print(f"Hank hours: {hank_hours.x}")
    print(f"Objective value: {model.objVal}")
elif model.status == GRB.INFEASIBLE:
    print("Model is infeasible.")
else:
    print(f"Optimization ended with status {model.status}")

```
