```json
{
  "sym_variables": [
    ("x0", "hours worked by Hank"),
    ("x1", "hours worked by Bill"),
    ("x2", "hours worked by George")
  ],
  "objective_function": "2.14 * x0 + 7.59 * x1 + 8.12 * x2",
  "constraints": [
    "13 * x0 + 10 * x1 + 5 * x2 >= 61",
    "23 * x0 + 6 * x1 >= 27",
    "23 * x0 + 6 * x1 + 7 * x2 >= 31",
    "19 * x1 + 13 * x2 <= 91",
    "14 * x0 + 19 * x1 <= 136",
    "14 * x0 + 19 * x1 + 13 * x2 <= 136",
    "10 * x1 + 5 * x2 <= 133",
    "13 * x0 + 5 * x2 <= 169",
    "13 * x0 + 10 * x1 <= 81",
    "13 * x0 + 10 * x1 + 5 * x2 <= 173",
    "6 * x1 + 7 * x2 <= 90",
    "23 * x0 + 6 * x1 <= 177",
    "23 * x0 + 6 * x1 + 7 * x2 <= 177",
    "7 * x0 + 16 * x2 <= 98",
    "7 * x0 + 14 * x1 + 16 * x2 <= 98"
  ]
}
```

```python
import gurobipy as gp

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

    # Create variables
    hank_hours = model.addVar(vtype=gp.GRB.INTEGER, name="hank_hours")
    bill_hours = model.addVar(vtype=gp.GRB.CONTINUOUS, name="bill_hours")
    george_hours = model.addVar(vtype=gp.GRB.CONTINUOUS, name="george_hours")

    # Set objective function
    model.setObjective(2.14 * hank_hours + 7.59 * bill_hours + 8.12 * george_hours, gp.GRB.MAXIMIZE)

    # Add constraints
    model.addConstr(13 * hank_hours + 10 * bill_hours + 5 * george_hours >= 61, "dollar_cost_min")
    model.addConstr(23 * hank_hours + 6 * bill_hours >= 27, "work_quality_hank_bill_min")
    model.addConstr(23 * hank_hours + 6 * bill_hours + 7 * george_hours >= 31, "work_quality_min")
    model.addConstr(19 * bill_hours + 13 * george_hours <= 91, "computer_competence_bill_george_max")
    model.addConstr(14 * hank_hours + 19 * bill_hours <= 136, "computer_competence_hank_bill_max")
    model.addConstr(14 * hank_hours + 19 * bill_hours + 13 * george_hours <= 136, "computer_competence_max")
    model.addConstr(10 * bill_hours + 5 * george_hours <= 133, "dollar_cost_bill_george_max")
    model.addConstr(13 * hank_hours + 5 * george_hours <= 169, "dollar_cost_hank_george_max")
    model.addConstr(13 * hank_hours + 10 * bill_hours <= 81, "dollar_cost_hank_bill_max")
    model.addConstr(13 * hank_hours + 10 * bill_hours + 5 * george_hours <= 173, "dollar_cost_max_1")
    model.addConstr(13 * hank_hours + 10 * bill_hours + 5 * george_hours <= 173, "dollar_cost_max_2")  # Duplicate constraint
    model.addConstr(6 * bill_hours + 7 * george_hours <= 90, "work_quality_bill_george_max")
    model.addConstr(23 * hank_hours + 6 * bill_hours <= 177, "work_quality_hank_bill_max")
    model.addConstr(23 * hank_hours + 6 * bill_hours + 7 * george_hours <= 177, "work_quality_max")
    model.addConstr(7 * hank_hours + 16 * george_hours <= 98, "organization_score_hank_george_max")
    model.addConstr(7 * hank_hours + 14 * bill_hours + 16 * george_hours <= 98, "organization_score_max")


    # Optimize model
    model.optimize()

    if model.status == gp.GRB.OPTIMAL:
        print('Obj: %g' % model.objVal)
        print('Hank Hours: %g' % hank_hours.x)
        print('Bill Hours: %g' % bill_hours.x)
        print('George Hours: %g' % george_hours.x)
    elif model.status == gp.GRB.INFEASIBLE:
        print('The model is infeasible.')
    else:
        print('Optimization ended with status %d' % model.status)


except gp.GurobiError as e:
    print('Error code ' + str(e.errno) + ': ' + str(e))

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