```json
{
  "sym_variables": [
    ("x0", "hours worked by Hank"),
    ("x1", "hours worked by Jean")
  ],
  "objective_function": "8.95 * x0 + 2.52 * x1",
  "constraints": [
    "21 * x0 + 13 * x1 >= 69",
    "30 * x0 + 4 * x1 >= 111",
    "27 * x0 + 28 * x1 >= 51",
    "-5 * x0 + 4 * x1 >= 0",
    "21 * x0 + 13 * x1 <= 125",
    "30 * x0 + 4 * x1 <= 274",
    "27 * x0 + 28 * x1 <= 168"
  ]
}
```

```python
import gurobipy as gp

try:
    # Create a new model
    model = gp.Model("optimize_work_hours")

    # Create variables
    hank_hours = model.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="hank_hours")
    jean_hours = model.addVar(lb=0, vtype=gp.GRB.INTEGER, name="jean_hours")

    # Set objective function
    model.setObjective(8.95 * hank_hours + 2.52 * jean_hours, gp.GRB.MINIMIZE)

    # Add constraints
    model.addConstr(21 * hank_hours + 13 * jean_hours >= 69, "organization_score_min")
    model.addConstr(30 * hank_hours + 4 * jean_hours >= 111, "likelihood_to_quit_min")
    model.addConstr(27 * hank_hours + 28 * jean_hours >= 51, "paperwork_competence_min")
    model.addConstr(-5 * hank_hours + 4 * jean_hours >= 0, "custom_constraint")
    model.addConstr(21 * hank_hours + 13 * jean_hours <= 125, "organization_score_max")
    model.addConstr(30 * hank_hours + 4 * jean_hours <= 274, "likelihood_to_quit_max")
    model.addConstr(27 * hank_hours + 28 * jean_hours <= 168, "paperwork_competence_max")


    # Optimize model
    model.optimize()

    # Print results
    if model.status == gp.GRB.OPTIMAL:
        print(f"Optimal solution found:")
        print(f"  Hours worked by Hank: {hank_hours.x}")
        print(f"  Hours worked by Jean: {jean_hours.x}")
        print(f"  Objective value: {model.objVal}")
    elif model.status == gp.GRB.INFEASIBLE:
        print("Model is infeasible.")
    else:
        print(f"Optimization ended with status {model.status}")


except gp.GurobiError as e:
    print(f"Error code {e.errno}: {e}")

except AttributeError:
    print('Encountered an attribute error')
```