```json
{
  "sym_variables": [
    ("x1", "number of full-time employees"),
    ("x2", "number of part-time employees")
  ],
  "objective_function": "800*x1 + 400*x2",
  "constraints": [
    "x1 + x2 >= 60",
    "x1 >= 40",
    "x1 >= (1/3)*x2",
    "800*x1 + 400*x2 <= 30000",
    "x1 >= 0",
    "x2 >= 0"
  ]
}
```

```python
import gurobipy as gp
from gurobipy import GRB

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

# Create variables
full_time = m.addVar(lb=0, vtype=GRB.INTEGER, name="full_time")
part_time = m.addVar(lb=0, vtype=GRB.INTEGER, name="part_time")


# Set objective function
m.setObjective(800 * full_time + 400 * part_time, GRB.MINIMIZE)

# Add constraints
m.addConstr(full_time + part_time >= 60, "total_employees")
m.addConstr(full_time >= 40, "min_full_time")
m.addConstr(full_time >= (1/3) * part_time, "full_time_ratio")
m.addConstr(800 * full_time + 400 * part_time <= 30000, "max_wage")


# Optimize model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print(f"Optimal solution found: ")
    print(f"Number of full-time employees: {full_time.x}")
    print(f"Number of part-time employees: {part_time.x}")
    print(f"Total weekly wage: ${m.objVal}")
elif m.status == GRB.INFEASIBLE:
    print("Model is infeasible.")
else:
    print(f"Optimization ended with status {m.status}")

```
