```json
{
  "sym_variables": [
    ("x0", "dish soap bottles"),
    ("x1", "paper towel rolls"),
    ("x2", "candles"),
    ("x3", "diapers")
  ],
  "objective_function": "1.01*x0 + 3.64*x1 + 1.72*x2 + 1.49*x3",
  "constraints": [
    "4*x0 + 7*x1 + 9*x2 + 12*x3 <= 288",
    "11*x0 + 15*x1 + 3*x2 + 7*x3 <= 139",
    "10*x0 + 17*x1 + 14*x2 + 12*x3 <= 262",
    "9*x2 + 12*x3 >= 47",
    "7*x1 + 9*x2 >= 30",
    "7*x1 + 12*x3 >= 71",
    "4*x0 + 7*x1 + 9*x2 + 12*x3 >= 71",
    "11*x0 + 3*x2 >= 32",
    "3*x2 + 7*x3 >= 19",
    "15*x1 + 3*x2 >= 18",
    "11*x0 + 15*x1 >= 30",
    "15*x1 + 7*x3 >= 21",
    "11*x0 + 3*x2 + 7*x3 >= 26",
    "11*x0 + 15*x1 + 3*x2 >= 26",
    "11*x0 + 3*x2 + 7*x3 >= 24",
    "11*x0 + 15*x1 + 3*x2 >= 24",
    "11*x0 + 15*x1 + 3*x2 + 7*x3 >= 24",
    "10*x0 + 14*x2 >= 64",
    "10*x0 + 12*x3 >= 52",
    "10*x0 + 17*x1 + 14*x2 >= 61",
    "10*x0 + 17*x1 + 12*x3 >= 61",
    "17*x1 + 14*x2 + 12*x3 >= 61",
    "10*x0 + 17*x1 + 14*x2 >= 37",
    "10*x0 + 17*x1 + 12*x3 >= 37",
    "17*x1 + 14*x2 + 12*x3 >= 37",
    "10*x0 + 17*x1 + 14*x2 >= 55",
    "10*x0 + 17*x1 + 12*x3 >= 55",
    "17*x1 + 14*x2 + 12*x3 >= 55",
    "10*x0 + 17*x1 + 14*x2 + 12*x3 >= 55",
    "-8*x1 + 5*x3 >= 0",
    "-1*x0 + 3*x3 >= 0",
    "4*x0 + 12*x3 <= 87",
    "9*x2 + 12*x3 <= 103",
    "4*x0 + 9*x2 <= 154",
    "7*x1 + 12*x3 <= 210",
    "4*x0 + 7*x1 + 9*x2 <= 249",
    "15*x1 + 3*x2 <= 119",
    "15*x1 + 3*x2 + 7*x3 <= 127",
    "11*x0 + 15*x1 + 7*x3 <= 45", 
    "11*x0 + 15*x1 + 3*x2 <= 132",
    "14*x2 + 12*x3 <= 193",
    "17*x1 + 12*x3 <= 121",
    "10*x0 + 17*x1 <= 242",
    "17*x1 + 14*x2 <= 173",
    "x0 == int",
    "x1 == int",
    "x2 == int",
    "x3 == int"
  ]
}
```

```python
import gurobipy as gp

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

# Create variables
x0 = m.addVar(vtype=gp.GRB.INTEGER, name="dish_soap_bottles")
x1 = m.addVar(vtype=gp.GRB.INTEGER, name="paper_towel_rolls")
x2 = m.addVar(vtype=gp.GRB.INTEGER, name="candles")
x3 = m.addVar(vtype=gp.GRB.INTEGER, name="diapers")

# Set objective function
m.setObjective(1.01 * x0 + 3.64 * x1 + 1.72 * x2 + 1.49 * x3, gp.GRB.MINIMIZE)

# Add constraints
m.addConstr(4 * x0 + 7 * x1 + 9 * x2 + 12 * x3 <= 288, "storage_space")
m.addConstr(11 * x0 + 15 * x1 + 3 * x2 + 7 * x3 <= 139, "usefulness_rating")
m.addConstr(10 * x0 + 17 * x1 + 14 * x2 + 12 * x3 <= 262, "weight")

m.addConstr(9*x2 + 12*x3 >= 47, "c1")
m.addConstr(7*x1 + 9*x2 >= 30, "c2")
m.addConstr(7*x1 + 12*x3 >= 71, "c3")
m.addConstr(4*x0 + 7*x1 + 9*x2 + 12*x3 >= 71, "c4")
m.addConstr(11*x0 + 3*x2 >= 32, "c5")
m.addConstr(3*x2 + 7*x3 >= 19, "c6")
m.addConstr(15*x1 + 3*x2 >= 18, "c7")
m.addConstr(11*x0 + 15*x1 >= 30, "c8")
m.addConstr(15*x1 + 7*x3 >= 21, "c9")
m.addConstr(11*x0 + 3*x2 + 7*x3 >= 26, "c10")
m.addConstr(11*x0 + 15*x1 + 3*x2 >= 26, "c11")
m.addConstr(11*x0 + 3*x2 + 7*x3 >= 24, "c12")
m.addConstr(11*x0 + 15*x1 + 3*x2 >= 24, "c13")
m.addConstr(11*x0 + 15*x1 + 3*x2 + 7*x3 >= 24, "c14")
m.addConstr(10*x0 + 14*x2 >= 64, "c15")
m.addConstr(10*x0 + 12*x3 >= 52, "c16")
m.addConstr(10*x0 + 17*x1 + 14*x2 >= 61, "c17")
m.addConstr(10*x0 + 17*x1 + 12*x3 >= 61, "c18")
m.addConstr(17*x1 + 14*x2 + 12*x3 >= 61, "c19")
m.addConstr(10*x0 + 17*x1 + 14*x2 >= 37, "c20")
m.addConstr(10*x0 + 17*x1 + 12*x3 >= 37, "c21")
m.addConstr(17*x1 + 14*x2 + 12*x3 >= 37, "c22")
m.addConstr(10*x0 + 17*x1 + 14*x2 >= 55, "c23")
m.addConstr(10*x0 + 17*x1 + 12*x3 >= 55, "c24")
m.addConstr(17*x1 + 14*x2 + 12*x3 >= 55, "c25")
m.addConstr(10*x0 + 17*x1 + 14*x2 + 12*x3 >= 55, "c26")
m.addConstr(-8*x1 + 5*x3 >= 0, "c27")
m.addConstr(-1*x0 + 3*x3 >= 0, "c28")
m.addConstr(4*x0 + 12*x3 <= 87, "c29")
m.addConstr(9*x2 + 12*x3 <= 103, "c30")
m.addConstr(4*x0 + 9*x2 <= 154, "c31")
m.addConstr(7*x1 + 12*x3 <= 210, "c32")
m.addConstr(4*x0 + 7*x1 + 9*x2 <= 249, "c33")
m.addConstr(15*x1 + 3*x2 <= 119, "c34")
m.addConstr(15*x1 + 3*x2 + 7*x3 <= 127, "c35")
m.addConstr(11*x0 + 15*x1 + 7*x3 <= 45, "c36")
m.addConstr(11*x0 + 15*x1 + 3*x2 <= 132, "c37")
m.addConstr(14*x2 + 12*x3 <= 193, "c38")
m.addConstr(17*x1 + 12*x3 <= 121, "c39")
m.addConstr(10*x0 + 17*x1 <= 242, "c40")
m.addConstr(17*x1 + 14*x2 <= 173, "c41")


# Optimize model
m.optimize()

# Print results
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("The model is infeasible.")
else:
    print("Optimization ended with status %d" % m.status)

```