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

```python
import gurobipy as gp

# Create a new model
m = gp.Model("work_hour_optimization")

# Create variables
paul_hours = m.addVar(name="paul_hours", lb=0)  # Non-negative hours
hank_hours = m.addVar(name="hank_hours", lb=0)  # Non-negative hours

# Set objective function
m.setObjective(8 * paul_hours + 8 * hank_hours, gp.GRB.MAXIMIZE)

# Add constraints

# Resource constraints (using provided data)
m.addConstr(14.64 * paul_hours + 0.84 * hank_hours >= 58, "org_score_min")
m.addConstr(7.43 * paul_hours + 6.44 * hank_hours >= 85, "dollar_cost_min")
m.addConstr(22.05 * paul_hours + 15.58 * hank_hours >= 107, "quit_index_min")
m.addConstr(2.11 * paul_hours + 20.34 * hank_hours >= 93, "paperwork_min")
m.addConstr(7.51 * paul_hours + 9.68 * hank_hours >= 94, "work_quality_min")

m.addConstr(paul_hours - 8 * hank_hours >= 0, "paul_hank_ratio")


m.addConstr(14.64 * paul_hours + 0.84 * hank_hours <= 157, "org_score_max") # Redundant constraint
m.addConstr(14.64 * paul_hours + 0.84 * hank_hours == 157, "org_score_equal") # Redundant constraint
m.addConstr(7.43 * paul_hours + 6.44 * hank_hours <= 144, "dollar_cost_max") # Redundant constraint
m.addConstr(22.05 * paul_hours + 15.58 * hank_hours <= 242, "quit_index_max") # Redundant constraint
m.addConstr(2.11 * paul_hours + 20.34 * hank_hours <= 344, "paperwork_max") # Redundant constraint
m.addConstr(7.51 * paul_hours + 9.68 * hank_hours <= 309, "work_quality_max") # Redundant constraint


# Optimize model
m.optimize()

# Print results
if m.status == gp.GRB.OPTIMAL:
    print('Optimal objective value:', m.objVal)
    print('Paul hours:', paul_hours.x)
    print('Hank hours:', hank_hours.x)
elif m.status == gp.GRB.INFEASIBLE:
    print('The model is infeasible.')
else:
    print(f"Optimization terminated with status {m.status}")

```
