broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today > x['min_shelf']]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 101, 4], ['U', 3, 190, 5]], 'today': 101, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 102, 4], ['U', 3, 190, 5]], 'today': 102, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 103, 4], ['U', 3, 190, 5]], 'today': 103, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 104, 4], ['U', 3, 190, 5]], 'today': 104, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 105, 4], ['U', 3, 190, 5]], 'today': 105, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today > x['min_shelf'] - 1 and l[2] > today + 1]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 101, 4], ['U', 3, 190, 5]], 'today': 101, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 102, 4], ['U', 3, 190, 5]], 'today': 102, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 103, 4], ['U', 3, 190, 5]], 'today': 103, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 104, 4], ['U', 3, 190, 5]], 'today': 104, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}], ['expires today no minimum', {'lots': [['T', 3, 105, 4], ['U', 3, 190, 5]], 'today': 105, 'order_qty': 2, 'min_shelf': 0}, {'picks': [['T', 2]], 'cost': 8}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Lots with exactly the minimum remaining shelf life are refused at the dock.

Input {lots:[[lot,qty,expiry_day,unit_cost]], today, order_qty, min_shelf}. A lot is eligible when expiry_day - today >= min_shelf. Eligible lots are picked by earliest expiry, ties by lot id ascending. If eligible stock < order_qty return {"error":"insufficient","available":eligible qty}. Return {picks:[[lot,qty]], cost}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] >= x['min_shelf']]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] >= today]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Nearly expired lots are shipped because shelf life is compared against an absolute day number.

Input {lots:[[lot,qty,expiry_day,unit_cost]], today, order_qty, min_shelf}. A lot is eligible when expiry_day - today >= min_shelf. Eligible lots are picked by earliest expiry, ties by lot id ascending. If eligible stock < order_qty return {"error":"insufficient","available":eligible qty}. Return {picks:[[lot,qty]], cost}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today >= x['min_shelf']]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: l[0])
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today >= x['min_shelf']]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[1], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Pickers are sent to lots in lot-number order, leaving short-dated lots to expire.

Input {lots:[[lot,qty,expiry_day,unit_cost]], today, order_qty, min_shelf}. A lot is eligible when expiry_day - today >= min_shelf. Eligible lots are picked by earliest expiry, ties by lot id ascending. If eligible stock < order_qty return {"error":"insufficient","available":eligible qty}. Return {picks:[[lot,qty]], cost}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today >= x['min_shelf']]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], -l[3]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today >= x['min_shelf']]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]), reverse=True)
    elig.sort(key=lambda l: l[2])
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Among lots with the same expiry the pick order is unstable against the stated lot-id rule.

Input {lots:[[lot,qty,expiry_day,unit_cost]], today, order_qty, min_shelf}. A lot is eligible when expiry_day - today >= min_shelf. Eligible lots are picked by earliest expiry, ties by lot id ascending. If eligible stock < order_qty return {"error":"insufficient","available":eligible qty}. Return {picks:[[lot,qty]], cost}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today >= x['min_shelf']]
    avail = sum(l[1] for l in x['lots'])
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today >= x['min_shelf']]
    avail = sum(l[1] for l in x['lots'] if l[2] >= today)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(need, qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
An order is accepted against stock that is too close to expiry and then comes up short.

Input {lots:[[lot,qty,expiry_day,unit_cost]], today, order_qty, min_shelf}. A lot is eligible when expiry_day - today >= min_shelf. Eligible lots are picked by earliest expiry, ties by lot id ascending. If eligible stock < order_qty return {"error":"insufficient","available":eligible qty}. Return {picks:[[lot,qty]], cost}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today >= x['min_shelf']]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = qty
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    today = x['today']
    elig = [l for l in x['lots'] if l[2] - today >= x['min_shelf']]
    avail = sum(l[1] for l in elig)
    if avail < x['order_qty']:
        return {'error': 'insufficient', 'available': avail}
    elig.sort(key=lambda l: (l[2], l[0]))
    need = x['order_qty']
    picks = []
    cost = 0
    for lot, qty, exp, unit in elig:
        if need == 0:
            break
        take = min(x['order_qty'], qty)
        picks.append([lot, take])
        cost += take * unit
        need -= take
    return {'picks': picks, 'cost': cost}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 106, 10], ['B', 4, 200, 11]], 'today': 101, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 6, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 6, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 381, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 107, 10], ['B', 4, 200, 11]], 'today': 102, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 7, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 7, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 382, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 6, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 1]], 'cost': 70}], ['shelf boundary', {'lots': [['A', 4, 108, 10], ['B', 4, 200, 11]], 'today': 103, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 8, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 8, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 383, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 7, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 2]], 'cost': 80}], ['shelf boundary', {'lots': [['A', 4, 109, 10], ['B', 4, 200, 11]], 'today': 104, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 9, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 9, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 384, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]], [['earliest expiry', {'lots': [['L3', 5, 120, 10], ['L1', 5, 110, 12], ['L2', 5, 130, 9]], 'today': 100, 'order_qty': 8, 'min_shelf': 5}, {'picks': [['L1', 5], ['L3', 3]], 'cost': 90}], ['shelf boundary', {'lots': [['A', 4, 110, 10], ['B', 4, 200, 11]], 'today': 105, 'order_qty': 3, 'min_shelf': 5}, {'picks': [['A', 3]], 'cost': 30}], ['insufficient', {'lots': [['A', 4, 150, 10], ['B', 9, 101, 11]], 'today': 100, 'order_qty': 10, 'min_shelf': 10}, {'error': 'insufficient', 'available': 4}], ['tie by lot', {'lots': [['Z9', 2, 140, 8], ['A1', 2, 140, 7], ['M5', 9, 150, 6]], 'today': 100, 'order_qty': 3, 'min_shelf': 1}, {'picks': [['A1', 2], ['Z9', 1]], 'cost': 22}], ['expired skipped', {'lots': [['OLD', 50, 90, 1], ['NEW', 10, 300, 2]], 'today': 100, 'order_qty': 4, 'min_shelf': 0}, {'picks': [['NEW', 4]], 'cost': 8}], ['zero order', {'lots': [['A', 3, 150, 10]], 'today': 100, 'order_qty': 0, 'min_shelf': 0}, {'picks': [], 'cost': 0}], ['big lots small order', {'lots': [['B7', 100, 400, 3], ['C2', 1, 385, 5], ['A4', 2, 390, 4]], 'today': 100, 'order_qty': 2, 'min_shelf': 30}, {'picks': [['C2', 1], ['A4', 1]], 'cost': 9}]]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)

prompt:
Whole lots are picked even when the order needs only part of the lot.

Input {lots:[[lot,qty,expiry_day,unit_cost]], today, order_qty, min_shelf}. A lot is eligible when expiry_day - today >= min_shelf. Eligible lots are picked by earliest expiry, ties by lot id ascending. If eligible stock < order_qty return {"error":"insufficient","available":eligible qty}. Return {picks:[[lot,qty]], cost}.

split: open-access