```json
{
  "sym_variables": [
    ("x0", "rotisserie chickens"),
    ("x1", "ham sandwiches"),
    ("x2", "potatoes")
  ],
  "objective_function": "2.4 * x0 + 2.19 * x1 + 6.37 * x2",
  "constraints": [
    "15 * x0 + 6 * x1 + 15 * x2 >= 28",
    "17 * x1 + 21 * x2 >= 25",
    "20 * x0 + 21 * x2 >= 38",
    "20 * x0 + 17 * x1 + 21 * x2 >= 35",
    "5 * x0 + 14 * x1 >= 13",
    "14 * x1 + 8 * x2 >= 14",
    "5 * x0 + 8 * x2 >= 14",
    "15 * x0 + 6 * x1 <= 40",
    "15 * x0 + 6 * x1 + 15 * x2 <= 40",
    "17 * x1 + 21 * x2 <= 77",
    "20 * x0 + 17 * x1 <= 105",
    "20 * x0 + 21 * x2 <= 114",
    "20 * x0 + 17 * x1 + 21 * x2 <= 143",
    "5 * x0 + 14 * x1 <= 63",
    "14 * x1 + 8 * x2 <= 60",
    "5 * x0 + 14 * x1 + 8 * x2 <= 64"
  ]
}
```

```python
import gurobipy as gp

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

    # Create variables
    x0 = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="rotisserie_chickens")
    x1 = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="ham_sandwiches")
    x2 = m.addVar(lb=0, vtype=gp.GRB.CONTINUOUS, name="potatoes")


    # Set objective function
    m.setObjective(2.4 * x0 + 2.19 * x1 + 6.37 * x2, gp.GRB.MAXIMIZE)

    # Add constraints
    m.addConstr(15 * x0 + 6 * x1 + 15 * x2 >= 28, "calcium_min")
    m.addConstr(17 * x1 + 21 * x2 >= 25, "fat_min_hs_p")
    m.addConstr(20 * x0 + 21 * x2 >= 38, "fat_min_rc_p")
    m.addConstr(20 * x0 + 17 * x1 + 21 * x2 >= 35, "fat_min")
    m.addConstr(5 * x0 + 14 * x1 >= 13, "carbs_min_rc_hs")
    m.addConstr(14 * x1 + 8 * x2 >= 14, "carbs_min_hs_p")
    m.addConstr(5 * x0 + 8 * x2 >= 14, "carbs_min_rc_p")
    m.addConstr(15 * x0 + 6 * x1 <= 40, "calcium_max_rc_hs")
    m.addConstr(15 * x0 + 6 * x1 + 15 * x2 <= 122, "calcium_max") # Using provided upper bound
    m.addConstr(17 * x1 + 21 * x2 <= 77, "fat_max_hs_p")
    m.addConstr(20 * x0 + 17 * x1 <= 105, "fat_max_rc_hs")
    m.addConstr(20 * x0 + 21 * x2 <= 114, "fat_max_rc_p")
    m.addConstr(20 * x0 + 17 * x1 + 21 * x2 <= 143, "fat_max") # Using provided upper bound
    m.addConstr(5 * x0 + 14 * x1 <= 63, "carbs_max_rc_hs")
    m.addConstr(14 * x1 + 8 * x2 <= 60, "carbs_max_hs_p")
    m.addConstr(5 * x0 + 14 * x1 + 8 * x2 <= 64, "carbs_max") # Using provided upper bound


    # Optimize model
    m.optimize()

    if m.status == gp.GRB.OPTIMAL:
        print('Obj: %g' % m.objVal)
        for v in m.getVars():
            print('%s %g' % (v.varName, v.x))
    elif m.status == gp.GRB.INFEASIBLE:
        print('Optimization problem is infeasible.')
    else:
        print('Optimization ended with status %d' % m.status)


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

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