```json
{
  "sym_variables": [
    ("x0", "headsets"),
    ("x1", "rubber bands"),
    ("x2", "planners"),
    ("x3", "hole punches")
  ],
  "objective_function": "2*x0 + 3*x1 + 5*x2 + 7*x3",
  "constraints": [
    "0.5*x0 + 0.12*x2 + 2.75*x3 >= 45",
    "0.5*x0 + 2.54*x1 + 0.12*x2 >= 45",
    "0.5*x0 + 0.12*x2 + 2.75*x3 >= 36",
    "0.5*x0 + 2.54*x1 + 0.12*x2 >= 36",
    "1.49*x0 + 0.16*x1 >= 39",
    "0.16*x1 + 0.33*x2 >= 54",
    "0.5*x0 + 2.54*x1 <= 164",
    "2.54*x1 + 0.12*x2 <= 104",
    "0.5*x0 + 0.12*x2 <= 101",
    "2.54*x1 + 2.75*x3 <= 92",
    "0.5*x0 + 2.54*x1 + 0.12*x2 + 2.75*x3 <= 92",  
    "0.16*x1 + 0.33*x2 <= 177",
    "1.49*x0 + 0.33*x2 <= 190",
    "0.33*x2 + 2.73*x3 <= 85",
    "1.49*x0 + 0.16*x1 + 0.33*x2 + 2.73*x3 <= 85",
    "0.5*x0 + 2.54*x1 + 0.12*x2 + 2.75*x3 <= 222",
    "1.49*x0 + 0.16*x1 + 0.33*x2 + 2.73*x3 <= 231"
  ]
}
```

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

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

# Create variables
headsets = m.addVar(vtype=GRB.INTEGER, name="headsets")
rubber_bands = m.addVar(vtype=GRB.INTEGER, name="rubber_bands")
planners = m.addVar(vtype=GRB.INTEGER, name="planners")
hole_punches = m.addVar(vtype=GRB.INTEGER, name="hole_punches")

# Set objective function
m.setObjective(2*headsets + 3*rubber_bands + 5*planners + 7*hole_punches, GRB.MAXIMIZE)

# Add constraints
m.addConstr(0.5*headsets + 0.12*planners + 2.75*hole_punches >= 45)
m.addConstr(0.5*headsets + 2.54*rubber_bands + 0.12*planners >= 45)
m.addConstr(0.5*headsets + 0.12*planners + 2.75*hole_punches >= 36)
m.addConstr(0.5*headsets + 2.54*rubber_bands + 0.12*planners >= 36)
m.addConstr(1.49*headsets + 0.16*rubber_bands >= 39)
m.addConstr(0.16*rubber_bands + 0.33*planners >= 54)
m.addConstr(0.5*headsets + 2.54*rubber_bands <= 164)
m.addConstr(2.54*rubber_bands + 0.12*planners <= 104)
m.addConstr(0.5*headsets + 0.12*planners <= 101)
m.addConstr(2.54*rubber_bands + 2.75*hole_punches <= 92)
m.addConstr(0.5*headsets + 2.54*rubber_bands + 0.12*planners + 2.75*hole_punches <= 92)
m.addConstr(0.16*rubber_bands + 0.33*planners <= 177)
m.addConstr(1.49*headsets + 0.33*planners <= 190)
m.addConstr(0.33*planners + 2.73*hole_punches <= 85)
m.addConstr(1.49*headsets + 0.16*rubber_bands + 0.33*planners + 2.73*hole_punches <= 85)
m.addConstr(0.5*headsets + 2.54*rubber_bands + 0.12*planners + 2.75*hole_punches <= 222)
m.addConstr(1.49*headsets + 0.16*rubber_bands + 0.33*planners + 2.73*hole_punches <= 231)


# Optimize model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print('Obj: %g' % m.objVal)
    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))
elif m.status == GRB.INFEASIBLE:
    print("The model is infeasible.")
else:
    print("Optimization ended with status:", m.status)

```