Here's the Gurobi code to solve your optimization problem:

```python
import gurobipy as gp

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

# Create variables
rubber_gloves = m.addVar(vtype=gp.GRB.INTEGER, name="rubber_gloves")
cookies = m.addVar(vtype=gp.GRB.INTEGER, name="cookies")
napkins = m.addVar(vtype=gp.GRB.INTEGER, name="napkins")
dish_soap = m.addVar(vtype=gp.GRB.INTEGER, name="dish_soap")

# Set objective function
m.setObjective(3 * rubber_gloves + 7 * cookies + 7 * napkins + 7 * dish_soap, gp.GRB.MINIMIZE)

# Add constraints
m.addConstr(1.97 * rubber_gloves + 0.95 * cookies + 0.46 * napkins + 0.64 * dish_soap <= 144, "storage_space") #r0
m.addConstr(1.93 * rubber_gloves + 1.77 * cookies + 1.08 * napkins + 0.4 * dish_soap <= 136, "usefulness_rating") #r1
m.addConstr(0.09 * rubber_gloves + 1.49 * cookies + 0.84 * napkins + 0.96 * dish_soap <= 213, "weight") #r2
m.addConstr(1.12 * rubber_gloves + 1.23 * cookies + 0.52 * napkins + 0.04 * dish_soap <= 108, "dollar_cost") #r3

m.addConstr(1.97 * rubber_gloves + 0.46 * napkins >= 27, "storage_rg_n")
m.addConstr(0.95 * cookies + 0.46 * napkins >= 26, "storage_c_n")
m.addConstr(1.97 * rubber_gloves + 0.64 * dish_soap >= 16, "storage_rg_ds")
m.addConstr(1.97 * rubber_gloves + 0.95 * cookies + 0.46 * napkins + 0.64 * dish_soap >= 16, "storage_all")

m.addConstr(1.77 * cookies + 0.4 * dish_soap >= 14, "usefulness_c_ds")
m.addConstr(1.08 * napkins + 0.4 * dish_soap >= 24, "usefulness_n_ds")
m.addConstr(1.93 * rubber_gloves + 1.77 * cookies + 0.4 * dish_soap >= 33, "usefulness_rg_c_ds")
m.addConstr(1.93 * rubber_gloves + 1.08 * napkins + 0.4 * dish_soap >= 33, "usefulness_rg_n_ds")
m.addConstr(1.93 * rubber_gloves + 1.77 * cookies + 1.08 * napkins >= 33, "usefulness_rg_c_n")
m.addConstr(1.93 * rubber_gloves + 1.77 * cookies + 0.4 * dish_soap >= 32, "usefulness_rg_c_ds_2")
m.addConstr(1.93 * rubber_gloves + 1.08 * napkins + 0.4 * dish_soap >= 32, "usefulness_rg_n_ds_2")
m.addConstr(1.93 * rubber_gloves + 1.77 * cookies + 1.08 * napkins >= 32, "usefulness_rg_c_n_2")
m.addConstr(1.93 * rubber_gloves + 1.77 * cookies + 0.4 * dish_soap >= 21, "usefulness_rg_c_ds_3")
m.addConstr(1.93 * rubber_gloves + 1.08 * napkins + 0.4 * dish_soap >= 21, "usefulness_rg_n_ds_3")
m.addConstr(1.93 * rubber_gloves + 1.77 * cookies + 1.08 * napkins >= 21, "usefulness_rg_c_n_3")
m.addConstr(1.93 * rubber_gloves + 1.77 * cookies + 1.08 * napkins + 0.4 * dish_soap >= 21, "usefulness_all")


m.addConstr(0.09 * rubber_gloves + 0.84 * napkins >= 26, "weight_rg_n")
m.addConstr(0.84 * napkins + 0.96 * dish_soap >= 40, "weight_n_ds")
m.addConstr(0.09 * rubber_gloves + 1.49 * cookies >= 36, "weight_rg_c")
m.addConstr(1.49 * cookies + 0.84 * napkins >= 40, "weight_c_n")
m.addConstr(0.09 * rubber_gloves + 0.96 * dish_soap >= 41, "weight_rg_ds")
m.addConstr(0.09 * rubber_gloves + 1.49 * cookies + 0.84 * napkins + 0.96 * dish_soap >= 41, "weight_all")

m.addConstr(1.23 * cookies + 0.52 * napkins >= 18, "cost_c_n")
m.addConstr(1.12 * rubber_gloves + 0.52 * napkins >= 17, "cost_rg_n")
m.addConstr(1.12 * rubber_gloves + 1.23 * cookies + 0.52 * napkins + 0.04 * dish_soap >= 17, "cost_all")

m.addConstr(9 * cookies - napkins >= 0, "cn_rel")
m.addConstr(5 * rubber_gloves - 2 * cookies >= 0, "rg_c_rel")

m.addConstr(0.95 * cookies + 0.46 * napkins <= 39, "storage_c_n_ub")
m.addConstr(1.97 * rubber_gloves + 0.95 * cookies <= 135, "storage_rg_c_ub")
m.addConstr(0.95 * cookies + 0.64 * dish_soap <= 138, "storage_c_ds_ub")
m.addConstr(1.97 * rubber_gloves + 0.46 * napkins <= 120, "storage_rg_n_ub")
m.addConstr(0.46 * napkins + 0.64 * dish_soap <= 137, "storage_n_ds_ub")
m.addConstr(1.97 * rubber_gloves + 0.95 * cookies + 0.46 * napkins <= 87, "storage_rg_c_n_ub")

m.addConstr(1.93 * rubber_gloves + 1.08 * napkins + 0.4 * dish_soap <= 67, "usefulness_rg_n_ds_ub")
m.addConstr(1.49 * cookies + 0.84 * napkins + 0.96 * dish_soap <= 161, "weight_c_n_ds_ub")
m.addConstr(0.09 * rubber_gloves + 1.49 * cookies + 0.84 * napkins <= 211, "weight_rg_c_n_ub")

m.addConstr(1.12 * rubber_gloves + 0.52 * napkins <= 38, "cost_rg_n_ub")
m.addConstr(1.23 * cookies + 0.04 * dish_soap <= 30, "cost_c_ds_ub")
m.addConstr(1.12 * rubber_gloves + 1.23 * cookies <= 95, "cost_rg_c_ub")


# 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)

```