```json
{
  "sym_variables": [
    ("x1", "number of waiters"),
    ("x2", "number of managers")
  ],
  "objective_function": "1200*x1 + 2000*x2",
  "constraints": [
    "x1 + x2 >= 50",
    "x2 >= 15",
    "x2 >= (1/3)*x1",
    "1200*x1 + 2000*x2 <= 500000",
    "x1 >= 0",
    "x2 >= 0"
  ]
}
```

```python
import gurobipy as gp

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

    # Create variables
    waiters = m.addVar(lb=0, vtype=gp.GRB.INTEGER, name="waiters")  # Integer variable
    managers = m.addVar(lb=0, vtype=gp.GRB.INTEGER, name="managers") # Integer variable


    # Set objective function
    m.setObjective(1200*waiters + 2000*managers, gp.GRB.MINIMIZE)

    # Add constraints
    m.addConstr(waiters + managers >= 50, "total_workers")
    m.addConstr(managers >= 15, "min_managers")
    m.addConstr(managers >= (1/3)*waiters, "manager_waiter_ratio")
    m.addConstr(1200*waiters + 2000*managers <= 500000, "max_wage")


    # Optimize model
    m.optimize()

    # Print solution
    if m.status == gp.GRB.OPTIMAL:
        print(f"Optimal solution found:\nWaiters: {waiters.x}\nManagers: {managers.x}\nTotal Wage Bill: ${m.objVal}")
    elif m.status == gp.GRB.INFEASIBLE:
        print("The model is infeasible.")
    else:
        print(f"Optimization terminated with status {m.status}")


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

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