[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v0

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v0

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multi_sourcing_v0",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 5,
    "SKU_Premium": 0,
    "SKU_ShortLife": 1
  },
  "cold_capacity": {
    "DC1": 4000,
    "DC2": 3500,
    "DC3": 3000,
    "DC4": 3000,
    "DC5": 2500
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      303,
      311,
      328,
      365,
      435,
      549,
      711,
      906,
      1100,
      1245,
      1300,
      1245,
      1100,
      906,
      711,
      549,
      435,
      365,
      328,
      311
    ],
    "SKU_Premium": [
      151,
      155,
      164,
      182,
      217,
      274,
      355,
      453,
      550,
      622,
      650,
      622,
      550,
      453,
      355,
      274,
      217,
      182,
      164,
      155
    ],
    "SKU_ShortLife": [
      121,
      124,
      131,
      146,
      174,
      219,
      284,
      362,
      440,
      498,
      520,
      498,
      440,
      362,
      284,
      219,
      174,
      146,
      131,
      124
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 0.5,
      "SKU_Premium": 10.0,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": []
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v1

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v1

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multi_sourcing_v1",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 5,
    "SKU_Premium": 0,
    "SKU_ShortLife": 1
  },
  "cold_capacity": {
    "DC1": 3456.3645401623567,
    "DC2": 3544.86702667332,
    "DC3": 3008.8219270638024,
    "DC4": 2687.2716663554443,
    "DC5": 2235.463908876728
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      321,
      273,
      375,
      355,
      421,
      470,
      763,
      887,
      1015,
      1291,
      1203,
      1122,
      1022,
      917,
      754,
      515,
      454,
      333,
      375,
      322
    ],
    "SKU_Premium": [
      170,
      133,
      179,
      178,
      237,
      303,
      308,
      396,
      631,
      697,
      656,
      678,
      619,
      439,
      325,
      251,
      191,
      168,
      150,
      164
    ],
    "SKU_ShortLife": [
      136,
      127,
      116,
      136,
      168,
      202,
      270,
      322,
      486,
      537,
      555,
      439,
      414,
      379,
      254,
      220,
      171,
      136,
      134,
      130
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 0.5,
      "SKU_Premium": 10.0,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": []
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v2

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v2

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multi_sourcing_v2",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 5,
    "SKU_Premium": 0,
    "SKU_ShortLife": 1
  },
  "cold_capacity": {
    "DC1": 4084.612978823098,
    "DC2": 3598.26441328805,
    "DC3": 2650.0534022829756,
    "DC4": 2992.8419953849925,
    "DC5": 2734.206362421372
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      281,
      314,
      323,
      313,
      370,
      569,
      801,
      875,
      1010,
      1359,
      1275,
      1091,
      1248,
      877,
      642,
      585,
      465,
      406,
      323,
      267
    ],
    "SKU_Premium": [
      165,
      161,
      142,
      196,
      211,
      242,
      379,
      467,
      604,
      626,
      614,
      576,
      516,
      403,
      306,
      273,
      194,
      159,
      145,
      149
    ],
    "SKU_ShortLife": [
      128,
      127,
      145,
      158,
      179,
      224,
      270,
      325,
      480,
      486,
      465,
      509,
      437,
      351,
      264,
      209,
      160,
      158,
      122,
      140
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 0.5,
      "SKU_Premium": 10.0,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": []
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v3

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v3

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multi_sourcing_v3",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 5,
    "SKU_Premium": 0,
    "SKU_ShortLife": 1
  },
  "cold_capacity": {
    "DC1": 4304.482184332716,
    "DC2": 3109.200946582979,
    "DC3": 3335.4317720467943,
    "DC4": 3286.9384117229283,
    "DC5": 2654.3116262976264
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      280,
      316,
      361,
      345,
      376,
      602,
      681,
      881,
      1135,
      1078,
      1398,
      1122,
      966,
      935,
      777,
      548,
      428,
      361,
      291,
      350
    ],
    "SKU_Premium": [
      142,
      138,
      145,
      205,
      186,
      240,
      370,
      462,
      472,
      660,
      701,
      654,
      502,
      458,
      383,
      294,
      204,
      192,
      158,
      162
    ],
    "SKU_ShortLife": [
      129,
      108,
      112,
      164,
      193,
      187,
      251,
      398,
      467,
      542,
      464,
      467,
      416,
      369,
      295,
      247,
      195,
      159,
      127,
      116
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 0.5,
      "SKU_Premium": 10.0,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": []
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v4

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multi_sourcing
Scenario ID: retail_f7_multi_sourcing_v4

[BUSINESS DESCRIPTION]
Business narrative:
Products differ in their effective sourcing regimes: some behave like slow but cheap supply, while others behave like fast but expensive supply. Lead times and holding costs vary across products, creating multi-speed inventory dynamics. Demand is local and exogenous at each location, and unmet demand is lost and penalized.

Structure cues:
- The inventory structure is single-echelon with product-specific lead times, similar to retail_f6_lead_time, together with storage capacity and lost sales.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. These limits must be respected.
- The JSON sets different lead times (SKU_Basic=5, SKU_Premium=0, SKU_ShortLife=1) and holding costs (SKU_Basic=0.5, SKU_Premium=10.0). Orders for each product become available only after that product's lead time, and inventory carried over incurs its corresponding holding cost.
- For each product, location, and period, on-hand stock is determined by previous on-hand stock, arrivals of past orders whose lead time completes in that period, sales, and waste, and must remain non-negative.
- The scenario mimics slow/cheap (Basic) and fast/expensive (Premium) sourcing channels at the product level through heterogeneous lead times and cost profiles.
- The objective is to minimize total cost (aggregating purchasing, holding, waste, and lost sales) while correctly handling the different lead times and holding-cost profiles.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multi_sourcing_v4",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "DC1",
    "DC2",
    "DC3",
    "DC4",
    "DC5"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 5,
    "SKU_Premium": 0,
    "SKU_ShortLife": 1
  },
  "cold_capacity": {
    "DC1": 3819.1237104651036,
    "DC2": 3224.2858454662423,
    "DC3": 3083.3458495977297,
    "DC4": 2954.237590018825,
    "DC5": 2566.460979143829
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "DC1": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC2": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC3": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC4": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC5": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      262,
      355,
      353,
      348,
      499,
      630,
      689,
      903,
      1184,
      1341,
      1385,
      1352,
      1022,
      793,
      793,
      511,
      393,
      329,
      305,
      339
    ],
    "SKU_Premium": [
      149,
      146,
      160,
      171,
      209,
      273,
      367,
      447,
      470,
      581,
      599,
      713,
      580,
      432,
      406,
      234,
      196,
      203,
      172,
      149
    ],
    "SKU_ShortLife": [
      111,
      136,
      146,
      142,
      168,
      194,
      263,
      329,
      405,
      489,
      487,
      509,
      418,
      324,
      284,
      188,
      187,
      143,
      124,
      105
    ]
  },
  "demand_share": {
    "DC1": 0.25,
    "DC2": 0.2,
    "DC3": 0.2,
    "DC4": 0.2,
    "DC5": 0.15
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 0.5,
      "SKU_Premium": 10.0,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": []
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v0

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v0

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multiechelon_chain_v0",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "Plant",
    "DC1",
    "DC2",
    "Store1",
    "Store2",
    "Store3"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "Plant": 8000.0,
    "DC1": 4000.0,
    "DC2": 4000.0,
    "Store1": 600.0,
    "Store2": 600.0,
    "Store3": 600.0
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "Plant": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC1": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "DC2": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "Store1": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store2": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store3": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      303,
      311,
      328,
      365,
      435,
      549,
      711,
      906,
      1100,
      1245,
      1300,
      1245,
      1100,
      906,
      711,
      549,
      435,
      365,
      328,
      311
    ],
    "SKU_Premium": [
      151,
      155,
      164,
      182,
      217,
      274,
      355,
      453,
      550,
      622,
      650,
      622,
      550,
      453,
      355,
      274,
      217,
      182,
      164,
      155
    ],
    "SKU_ShortLife": [
      121,
      124,
      131,
      146,
      174,
      219,
      284,
      362,
      440,
      498,
      520,
      498,
      440,
      362,
      284,
      219,
      174,
      146,
      131,
      124
    ]
  },
  "demand_share": {
    "Plant": 0.0,
    "DC1": 0.0,
    "DC2": 0.0,
    "Store1": 0.3,
    "Store2": 0.4,
    "Store3": 0.3
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "Plant",
        "DC1"
      ],
      [
        "Plant",
        "DC2"
      ],
      [
        "DC1",
        "Store1"
      ],
      [
        "DC1",
        "Store2"
      ],
      [
        "DC2",
        "Store2"
      ],
      [
        "DC2",
        "Store3"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.


[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v1

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA SCHEMA]
{
  "name": str,                          # scenario identifier
  "periods": int,                       # number of time periods
  "products": [str, ...],               # list of product IDs
  "locations": [str, ...],              # list of location IDs

  "shelf_life": {p: int},               # shelf life in periods per product
  "lead_time": {p: int},                # order lead time per product (0 = same-period arrival)

  "demand_curve": {p: [float, ...]},    # demand per product per period (0-indexed list)
  "demand_share": {l: float},           # fraction of total demand at each location

  "production_cap": {p: [float, ...]},  # max production per product per period (0-indexed list)
  "cold_capacity": {l: float},          # storage capacity per location
  "cold_usage": {p: float},             # storage units per unit of product

  "labor_cap": {l: [float, ...]},       # labor hours per location per period (0-indexed list)
  "labor_usage": {p: float},            # labor hours per unit sold
  "return_rate": {p: float},            # fraction of sales returned next period

  "costs": {
    "purchasing": {p: float},           # cost per unit ordered
    "inventory": {p: float},            # holding cost per unit per period
    "waste": {p: float},                # cost per unit expired
    "lost_sales": {p: float},           # penalty per unit of unmet demand
    "fixed_order": float,               # fixed cost per order placed
    "transshipment": float              # cost per unit transshipped
  },

  "constraints": {
    "moq": float,                       # minimum order quantity (0 = no MOQ)
    "pack_size": int,                   # order must be multiple of this (1 = no constraint)
    "budget_per_period": float|null,    # max purchasing cost per period
    "waste_limit_pct": float|null       # max waste as fraction of total demand
  },

  "network": {
    "sub_edges": [[p_from, p_to], ...], # substitution: p_from's demand can be served by p_to
    "trans_edges": [[l_from, l_to], ...]# transshipment: can ship from l_from to l_to
  }
}

[DATA ACCESS]
- The variable `data` is pre-loaded. Do NOT use file I/O.
- Lists are 0-indexed (period t in model uses index [t-1] in data arrays)

CRITICAL - Network edges require tuple conversion for Gurobi:
  sub_edges = [tuple(e) for e in data.get('network', {}).get('sub_edges', [])]
  trans_edges = [tuple(e) for e in data.get('network', {}).get('trans_edges', [])]

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that models and solves this optimization problem.

[SCENARIO]
Family: F7 (Network and Multi Echelon)
Archetype: retail_f7_multiechelon_chain
Scenario ID: retail_f7_multiechelon_chain_v1

[BUSINESS DESCRIPTION]
Business narrative:
The network is an explicit three-echelon chain consisting of a plant, distribution centers, and retail stores. Demand occurs only at stores; the plant and distribution centers act purely as upstream nodes that hold and move inventory. Customers are never backordered: store demand that cannot be met from store inventory is lost and penalized.

Structure cues:
- Locations: Plant (upstream), DC1/DC2 (distribution centers), Store1/Store2/Store3 (retail). The transshipment network defines directed edges: Plant->DC1, Plant->DC2, DC1->Store1, DC1->Store2, DC2->Store2, DC2->Store3.
- Shelf life: Each product has a shelf life in periods. Inventory must be tracked by REMAINING LIFE.

  VARIABLE DEFINITION: I[p,l,t,r] = inventory at START of period t with r periods remaining.
  Convention: r=1 is OLDEST (sell first FIFO), r=shelf_life[p] is FRESHEST.

  KEY EQUATIONS - implement EXACTLY as written, do NOT add or remove terms:

  (1) Fresh inflow: I[p,l,t,SL] = Q[p,t] * demand_share[l]
      - This is ONLY the inflow from production. Do NOT subtract sales here!
      - Q is total production, demand_share distributes it to locations.

  (2) Aging: I[p,l,t+1,r] = I[p,l,t,r+1] - sales[p,l,t,r+1] for r=1..SL-1
      - Inventory tomorrow with r remaining = inventory today with r+1 remaining - sales

  (3) Waste: W[p,l,t] = I[p,l,t,1] - sales[p,l,t,1]
      - Items with r=1 that aren't sold become waste

  (4) Sales availability: sales[p,l,t,r] <= I[p,l,t,r]
      - Can only sell what you have in inventory

  (5) Inventory holding cost: charged on (I[p,l,t,r] - sales[p,l,t,r]) for r >= 2
      - Charge on END-of-period inventory (after sales), exclude expiring items (r=1)
- Storage capacity: sum over products of (cold_usage[p] * total_inventory[p,l,t]) <= cold_capacity[l]. Capacities differ by echelon: Plant=8000, DC1/DC2=4000, Stores=600.
- Inventory is allowed to flow only along the directed edges. There is no direct shipment between stores, between distribution centers, or from stores back upstream.
- Demand occurs only at store nodes according to demand_share (Store1=30%, Store2=40%, Store3=30%). Upstream nodes (Plant, DCs) do not face direct customer demand.
- For each product, location, and period, inventory reflects previous stock, production or inbound shipments, outbound shipments, sales at stores, and waste, and must remain non-negative.
- Lost sales occur only at store nodes when local demand cannot be served from available inventory, even after receiving shipments from upstream.
- The objective is to minimize total cost including purchasing, holding at all echelons, transshipment, waste, and lost sales, subject to the three-echelon topology.

[DATA]
The following JSON contains all instance data. Parse it directly in your code.

```json
{
  "name": "retail_f7_multiechelon_chain_v1",
  "description": "Standard seasonal retail scenario.",
  "periods": 20,
  "products": [
    "SKU_Basic",
    "SKU_Premium",
    "SKU_ShortLife"
  ],
  "locations": [
    "Plant",
    "DC1",
    "DC2",
    "Store1",
    "Store2",
    "Store3"
  ],
  "shelf_life": {
    "SKU_Basic": 10,
    "SKU_Premium": 8,
    "SKU_ShortLife": 4
  },
  "lead_time": {
    "SKU_Basic": 0,
    "SKU_Premium": 0,
    "SKU_ShortLife": 0
  },
  "cold_capacity": {
    "Plant": 7969.798541468495,
    "DC1": 3407.868633501556,
    "DC2": 4226.874768906733,
    "Store1": 527.5535465562568,
    "Store2": 574.4081112573077,
    "Store3": 591.0778823689047
  },
  "cold_usage": {
    "SKU_Basic": 1.0,
    "SKU_Premium": 3.0,
    "SKU_ShortLife": 1.2
  },
  "production_cap": {
    "SKU_Basic": [
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800,
      800
    ],
    "SKU_Premium": [
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400,
      400
    ],
    "SKU_ShortLife": [
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500,
      500
    ]
  },
  "labor_cap": {
    "Plant": [
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0,
      99999.0
    ],
    "DC1": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "DC2": [
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0,
      500.0
    ],
    "Store1": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store2": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ],
    "Store3": [
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0,
      200.0
    ]
  },
  "labor_usage": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "return_rate": {
    "SKU_Basic": 0.0,
    "SKU_Premium": 0.0,
    "SKU_ShortLife": 0.0
  },
  "demand_curve": {
    "SKU_Basic": [
      341,
      355,
      365,
      414,
      422,
      514,
      633,
      882,
      1170,
      1149,
      1129,
      1118,
      1120,
      975,
      802,
      621,
      496,
      314,
      295,
      275
    ],
    "SKU_Premium": [
      163,
      172,
      184,
      165,
      243,
      256,
      304,
      486,
      617,
      714,
      602,
      627,
      529,
      513,
      334,
      293,
      224,
      175,
      153,
      141
    ],
    "SKU_ShortLife": [
      122,
      129,
      126,
      144,
      168,
      211,
      313,
      327,
      377,
      469,
      574,
      467,
      470,
      415,
      265,
      221,
      194,
      139,
      126,
      116
    ]
  },
  "demand_share": {
    "Plant": 0.0,
    "DC1": 0.0,
    "DC2": 0.0,
    "Store1": 0.3,
    "Store2": 0.4,
    "Store3": 0.3
  },
  "costs": {
    "lost_sales": {
      "SKU_Basic": 50.0,
      "SKU_Premium": 80.0,
      "SKU_ShortLife": 40.0
    },
    "inventory": {
      "SKU_Basic": 1.0,
      "SKU_Premium": 1.5,
      "SKU_ShortLife": 1.0
    },
    "waste": {
      "SKU_Basic": 2.0,
      "SKU_Premium": 3.0,
      "SKU_ShortLife": 2.0
    },
    "fixed_order": 0.0,
    "transshipment": 0.5,
    "purchasing": {
      "SKU_Basic": 10.0,
      "SKU_Premium": 20.0,
      "SKU_ShortLife": 15.0
    }
  },
  "constraints": {
    "moq": 0,
    "pack_size": 1,
    "budget_per_period": null,
    "waste_limit_pct": null
  },
  "network": {
    "sub_edges": [
      [
        "SKU_Basic",
        "SKU_Premium"
      ]
    ],
    "trans_edges": [
      [
        "Plant",
        "DC1"
      ],
      [
        "Plant",
        "DC2"
      ],
      [
        "DC1",
        "Store1"
      ],
      [
        "DC1",
        "Store2"
      ],
      [
        "DC2",
        "Store2"
      ],
      [
        "DC2",
        "Store3"
      ]
    ]
  }
}
```

[OUTPUT FORMAT]
- Import: import gurobipy as gp; from gurobipy import GRB; import json
- Set Gurobi params: m.Params.OutputFlag = 0; m.Params.Threads = 1; m.Params.Seed = 0
- Print at end:
  print(f"status: {{m.Status}}")
  if m.Status == 2:
      print(f"objective: {{m.ObjVal}}")
- Output ONLY executable Python code. No markdown, no explanations.

[TASK]
Write a GurobiPy script that:
1. Parses the JSON data above (use json.loads on the string)
2. Models and solves the optimization problem
3. Prints status and objective value

Standard seasonal retail scenario.