[{"data":1,"prerenderedAt":2307},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders":3,"surround:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders":2272,"ancestors:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders":2281,"children:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders":2286,"related:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders":2287},{"id":4,"title":5,"body":6,"dateModified":2237,"datePublished":2237,"description":2238,"extension":2239,"faq":2240,"keyword":2249,"kind":2250,"meta":2251,"navigation":97,"path":2261,"seo":2262,"slug":2265,"stem":2266,"topics":2267,"type":2270,"__hash__":2271},"docs\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders\u002Findex.md","Build a Warehouse Pick List from Orders",{"type":7,"value":8,"toc":2226},"minimark",[9,19,24,53,65,69,507,514,670,674,1047,1058,1364,1435,1438,1442,1567,1570,1574,2108,2115,2119,2154,2158,2161,2165,2171,2177,2183,2189,2193,2222],[10,11,12,13,18],"p",{},"Every morning a warehouse turns the orders that came in overnight into pick lists: which item to take from which bin, how many, and in what order to walk the aisles. Warehouse management systems do this, but many smaller operations run on a stock spreadsheet and an order export, and the pick lists are put together by hand — slowly, and with stock promised twice when two orders want the last units in a bin. The logic is not complicated, and pandas handles it well. This page builds pick lists from an order file and a bin-level stock file: each order line is allocated to specific bins, oldest stock first, and shortages are recorded rather than allocated; identical items across orders are combined into one pick; the picks are sorted into a snake path through the aisles; and each picker gets a printable Excel sheet with a tick column and a table for sorting the picked items back into orders. It belongs to ",[14,15,17],"a",{"href":16},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002F","Building Finance and Operations Reports",".",[20,21,23],"h2",{"id":22},"prerequisites","Prerequisites",[25,26,31],"pre",{"className":27,"code":28,"language":29,"meta":30,"style":30},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47,50],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"sMTad","pip",[35,44,46],{"class":45},"srMev"," install",[35,48,49],{"class":45}," pandas",[35,51,52],{"class":45}," openpyxl\n",[10,54,55,56,60,61,64],{},"Two inputs: the open order lines (order, SKU, quantity) and stock by bin, where each bin code is ",[57,58,59],"em",{},"zone–aisle–position"," — ",[32,62,63],{},"A-02-05"," is zone A, aisle 2, position 5 — with the quantity on hand and the date the stock was received. Twelve order lines from six orders are picked today.",[20,66,68],{"id":67},"step-1-allocate-order-lines-to-bins-oldest-stock-first","Step 1 — Allocate order lines to bins, oldest stock first",[25,70,74],{"className":71,"code":72,"language":73,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\norders = pd.read_excel(\"open_orders.xlsx\")\nstock = pd.read_excel(\"bin_stock.xlsx\", parse_dates=[\"Received\"]).sort_values([\"SKU\", \"Received\"])\navailable = stock.set_index(\"Bin\")[\"On hand\"].to_dict()\n\nallocations, shortages = [], []\nfor line in orders.itertuples(index=False):\n    need = line.Qty\n    for b in stock[stock[\"SKU\"] == line.SKU].itertuples(index=False):\n        take = min(need, available[b.Bin])\n        if take > 0:\n            allocations.append({\"Order\": line.Order, \"SKU\": line.SKU, \"Bin\": b.Bin, \"Qty\": take})\n            available[b.Bin] -= take\n            need -= take\n        if need == 0:\n            break\n    if need:\n        shortages.append({\"Order\": line.Order, \"SKU\": line.SKU, \"Ordered\": line.Qty, \"Short\": need})\n\nalloc = pd.DataFrame(allocations)\nshort = pd.DataFrame(shortages)\nassert alloc.groupby(\"Bin\")[\"Qty\"].sum().le(stock.set_index(\"Bin\")[\"On hand\"]).all()\nprint(alloc.to_string(index=False))\nprint(short.to_string(index=False))\n","python",[32,75,76,92,99,117,158,181,186,197,224,235,274,288,306,338,350,360,374,380,389,419,424,435,446,473,491],{"__ignoreMap":30},[35,77,78,82,86,89],{"class":37,"line":38},[35,79,81],{"class":80},"s-kum","import",[35,83,85],{"class":84},"skGVy"," pandas ",[35,87,88],{"class":80},"as",[35,90,91],{"class":84}," pd\n",[35,93,95],{"class":37,"line":94},2,[35,96,98],{"emptyLinePlaceholder":97},true,"\n",[35,100,102,105,108,111,114],{"class":37,"line":101},3,[35,103,104],{"class":84},"orders ",[35,106,107],{"class":80},"=",[35,109,110],{"class":84}," pd.read_excel(",[35,112,113],{"class":45},"\"open_orders.xlsx\"",[35,115,116],{"class":84},")\n",[35,118,120,123,125,127,130,133,137,139,142,145,148,151,153,155],{"class":37,"line":119},4,[35,121,122],{"class":84},"stock ",[35,124,107],{"class":80},[35,126,110],{"class":84},[35,128,129],{"class":45},"\"bin_stock.xlsx\"",[35,131,132],{"class":84},", ",[35,134,136],{"class":135},"sa561","parse_dates",[35,138,107],{"class":80},[35,140,141],{"class":84},"[",[35,143,144],{"class":45},"\"Received\"",[35,146,147],{"class":84},"]).sort_values([",[35,149,150],{"class":45},"\"SKU\"",[35,152,132],{"class":84},[35,154,144],{"class":45},[35,156,157],{"class":84},"])\n",[35,159,161,164,166,169,172,175,178],{"class":37,"line":160},5,[35,162,163],{"class":84},"available ",[35,165,107],{"class":80},[35,167,168],{"class":84}," stock.set_index(",[35,170,171],{"class":45},"\"Bin\"",[35,173,174],{"class":84},")[",[35,176,177],{"class":45},"\"On hand\"",[35,179,180],{"class":84},"].to_dict()\n",[35,182,184],{"class":37,"line":183},6,[35,185,98],{"emptyLinePlaceholder":97},[35,187,189,192,194],{"class":37,"line":188},7,[35,190,191],{"class":84},"allocations, shortages ",[35,193,107],{"class":80},[35,195,196],{"class":84}," [], []\n",[35,198,200,203,206,209,212,215,217,221],{"class":37,"line":199},8,[35,201,202],{"class":80},"for",[35,204,205],{"class":84}," line ",[35,207,208],{"class":80},"in",[35,210,211],{"class":84}," orders.itertuples(",[35,213,214],{"class":135},"index",[35,216,107],{"class":80},[35,218,220],{"class":219},"sP0c6","False",[35,222,223],{"class":84},"):\n",[35,225,227,230,232],{"class":37,"line":226},9,[35,228,229],{"class":84},"    need ",[35,231,107],{"class":80},[35,233,234],{"class":84}," line.Qty\n",[35,236,238,241,244,246,249,251,254,257,260,263,266,268,270,272],{"class":37,"line":237},10,[35,239,240],{"class":80},"    for",[35,242,243],{"class":84}," b ",[35,245,208],{"class":80},[35,247,248],{"class":84}," stock[stock[",[35,250,150],{"class":45},[35,252,253],{"class":84},"] ",[35,255,256],{"class":80},"==",[35,258,259],{"class":84}," line.",[35,261,262],{"class":219},"SKU",[35,264,265],{"class":84},"].itertuples(",[35,267,214],{"class":135},[35,269,107],{"class":80},[35,271,220],{"class":219},[35,273,223],{"class":84},[35,275,277,280,282,285],{"class":37,"line":276},11,[35,278,279],{"class":84},"        take ",[35,281,107],{"class":80},[35,283,284],{"class":219}," min",[35,286,287],{"class":84},"(need, available[b.Bin])\n",[35,289,291,294,297,300,303],{"class":37,"line":290},12,[35,292,293],{"class":80},"        if",[35,295,296],{"class":84}," take ",[35,298,299],{"class":80},">",[35,301,302],{"class":219}," 0",[35,304,305],{"class":84},":\n",[35,307,309,312,315,318,320,323,325,327,329,332,335],{"class":37,"line":308},13,[35,310,311],{"class":84},"            allocations.append({",[35,313,314],{"class":45},"\"Order\"",[35,316,317],{"class":84},": line.Order, ",[35,319,150],{"class":45},[35,321,322],{"class":84},": line.",[35,324,262],{"class":219},[35,326,132],{"class":84},[35,328,171],{"class":45},[35,330,331],{"class":84},": b.Bin, ",[35,333,334],{"class":45},"\"Qty\"",[35,336,337],{"class":84},": take})\n",[35,339,341,344,347],{"class":37,"line":340},14,[35,342,343],{"class":84},"            available[b.Bin] ",[35,345,346],{"class":80},"-=",[35,348,349],{"class":84}," take\n",[35,351,353,356,358],{"class":37,"line":352},15,[35,354,355],{"class":84},"            need ",[35,357,346],{"class":80},[35,359,349],{"class":84},[35,361,363,365,368,370,372],{"class":37,"line":362},16,[35,364,293],{"class":80},[35,366,367],{"class":84}," need ",[35,369,256],{"class":80},[35,371,302],{"class":219},[35,373,305],{"class":84},[35,375,377],{"class":37,"line":376},17,[35,378,379],{"class":80},"            break\n",[35,381,383,386],{"class":37,"line":382},18,[35,384,385],{"class":80},"    if",[35,387,388],{"class":84}," need:\n",[35,390,392,395,397,399,401,403,405,407,410,413,416],{"class":37,"line":391},19,[35,393,394],{"class":84},"        shortages.append({",[35,396,314],{"class":45},[35,398,317],{"class":84},[35,400,150],{"class":45},[35,402,322],{"class":84},[35,404,262],{"class":219},[35,406,132],{"class":84},[35,408,409],{"class":45},"\"Ordered\"",[35,411,412],{"class":84},": line.Qty, ",[35,414,415],{"class":45},"\"Short\"",[35,417,418],{"class":84},": need})\n",[35,420,422],{"class":37,"line":421},20,[35,423,98],{"emptyLinePlaceholder":97},[35,425,427,430,432],{"class":37,"line":426},21,[35,428,429],{"class":84},"alloc ",[35,431,107],{"class":80},[35,433,434],{"class":84}," pd.DataFrame(allocations)\n",[35,436,438,441,443],{"class":37,"line":437},22,[35,439,440],{"class":84},"short ",[35,442,107],{"class":80},[35,444,445],{"class":84}," pd.DataFrame(shortages)\n",[35,447,449,452,455,457,459,461,464,466,468,470],{"class":37,"line":448},23,[35,450,451],{"class":80},"assert",[35,453,454],{"class":84}," alloc.groupby(",[35,456,171],{"class":45},[35,458,174],{"class":84},[35,460,334],{"class":45},[35,462,463],{"class":84},"].sum().le(stock.set_index(",[35,465,171],{"class":45},[35,467,174],{"class":84},[35,469,177],{"class":45},[35,471,472],{"class":84},"]).all()\n",[35,474,476,479,482,484,486,488],{"class":37,"line":475},24,[35,477,478],{"class":219},"print",[35,480,481],{"class":84},"(alloc.to_string(",[35,483,214],{"class":135},[35,485,107],{"class":80},[35,487,220],{"class":219},[35,489,490],{"class":84},"))\n",[35,492,494,496,499,501,503,505],{"class":37,"line":493},25,[35,495,478],{"class":219},[35,497,498],{"class":84},"(short.to_string(",[35,500,214],{"class":135},[35,502,107],{"class":80},[35,504,220],{"class":219},[35,506,490],{"class":84},[10,508,509,510,513],{},"Each order line takes stock from the bins that hold its SKU, starting with the bin received earliest so older stock leaves first — first in, first out, which matters for anything with a shelf life or a risk of becoming obsolete. A running dictionary of what is still available in each bin is the important part: when order SO-502 asks for ten ",[57,511,512],{},"WID-A",", the oldest bin has only six left after SO-501, so it takes those six and the remaining four come from the second bin. That is exactly the double promise a hand-built list gets wrong. When the bins run out before the line is filled, the remainder is recorded as a shortage rather than allocated, and the assertion at the end proves that no bin has been asked for more than it holds. Orders are allocated in the order they appear in the file; sorting the order lines first by promised date or customer priority changes who gets the stock when there is not enough for everyone.",[515,516,524,525,524,529,524,533,524,541,524,551,524,558,524,563,524,569,524,574,524,578,524,584,524,587,524,591,524,595,524,598,524,603,524,609,524,612,524,615,524,618,524,622,524,626,524,629,524,634,524,639,524,642,524,646,524,649,524,654,524,660,524,663,524,666],"svg",{"viewBox":517,"role":518,"ariaLabelledBy":519,"xmlns":522,"style":523},"4 0 752 144","img",[520,521],"pick-alloc-t","pick-alloc-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[526,527,528],"title",{"id":520},"Allocating one order line",[530,531,532],"desc",{"id":521},"The bins holding the SKU are taken oldest first. From each bin the line takes as much as it still needs or the bin still has, and the bin's remaining quantity is reduced. If the bins run out first, the rest of the line is recorded as a shortage.",[534,535],"rect",{"x":536,"y":537,"width":538,"height":539,"fill":540},"4","0","752","144","#ffffff",[534,542],{"x":543,"y":544,"width":545,"height":546,"rx":547,"fill":548,"stroke":549,"style":550},"20.0","16.0","115.2","111.5","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[552,553,557],"text",{"x":554,"y":555,"style":556},"77.6","67.8","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Order line",[552,559,562],{"x":554,"y":560,"style":561},"87.2","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","SKU, quantity",[37,564],{"x1":565,"y1":566,"x2":567,"y2":566,"stroke":568,"style":550},"140.2","71.8","162.2","var(--brand,#5b5cf0)",[570,571],"polygon",{"points":572,"fill":573},"166.2,71.8 157.2,76.8 157.2,66.8","#5b5cf0",[534,575],{"x":576,"y":544,"width":545,"height":546,"rx":547,"fill":577,"stroke":568,"style":550},"171.2","#f0f4ff",[552,579,583],{"x":580,"y":581,"style":582},"228.8","59.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Bins for the",[552,585,262],{"x":580,"y":586,"style":582},"76.5",[552,588,590],{"x":580,"y":589,"style":561},"96.0","oldest first",[37,592],{"x1":593,"y1":566,"x2":594,"y2":566,"stroke":568,"style":550},"291.4","313.4",[570,596],{"points":597,"fill":573},"317.4,71.8 308.4,76.8 308.4,66.8",[534,599],{"x":600,"y":544,"width":545,"height":546,"rx":547,"fill":601,"stroke":602,"style":550},"322.4","#fdefd8","var(--gold,#b4740a)",[552,604,608],{"x":605,"y":606,"style":607},"380.0","41.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Take",[552,610,611],{"x":605,"y":581,"style":607},"min(need,",[552,613,614],{"x":605,"y":586,"style":607},"left)",[552,616,617],{"x":605,"y":589,"style":561},"update what is",[552,619,621],{"x":605,"y":620,"style":561},"113.5","left",[37,623],{"x1":624,"y1":566,"x2":625,"y2":566,"stroke":568,"style":550},"442.6","464.6",[570,627],{"points":628,"fill":573},"468.6,71.8 459.6,76.8 459.6,66.8",[534,630],{"x":631,"y":544,"width":545,"height":546,"rx":547,"fill":632,"stroke":633,"style":550},"473.6","#d9f4f1","var(--teal,#0f9488)",[552,635,638],{"x":636,"y":555,"style":637},"531.2","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Line filled",[552,640,641],{"x":636,"y":560,"style":561},"next line",[37,643],{"x1":644,"y1":566,"x2":645,"y2":566,"stroke":568,"style":550},"593.8","615.8",[570,647],{"points":648,"fill":573},"619.8,71.8 610.8,76.8 610.8,66.8",[534,650],{"x":651,"y":544,"width":545,"height":546,"rx":547,"fill":652,"stroke":653,"style":550},"624.8","#fce9e9","var(--danger,#dc2626)",[552,655,659],{"x":656,"y":657,"style":658},"682.4","50.2","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Bins empty",[552,661,662],{"x":656,"y":555,"style":658},"first",[552,664,665],{"x":656,"y":560,"style":561},"record a",[552,667,669],{"x":656,"y":668,"style":561},"104.8","shortage",[20,671,673],{"id":672},"step-2-batch-the-picks-and-sort-them-into-a-walking-path","Step 2 — Batch the picks and sort them into a walking path",[25,675,677],{"className":71,"code":676,"language":73,"meta":30,"style":30},"loc = alloc[\"Bin\"].str.extract(r\"(?P\u003CZone>[A-Z])-(?P\u003CAisle>\\d+)-(?P\u003CPosition>\\d+)\").astype({\"Aisle\": int, \"Position\": int})\nalloc = pd.concat([alloc, loc], axis=1)\n\npicks = alloc.groupby([\"Bin\", \"Zone\", \"Aisle\", \"Position\", \"SKU\"], as_index=False)[\"Qty\"].sum()\naisle_rank = picks[[\"Zone\", \"Aisle\"]].drop_duplicates().sort_values([\"Zone\", \"Aisle\"]).reset_index(drop=True)\naisle_rank[\"Leg\"] = aisle_rank.index\npicks = picks.merge(aisle_rank, on=[\"Zone\", \"Aisle\"])\npicks[\"Walk\"] = picks[\"Position\"].where(picks[\"Leg\"] % 2 == 0, -picks[\"Position\"])   # snake: every other aisle backwards\npicks = picks.sort_values([\"Leg\", \"Walk\"]).reset_index(drop=True)\npicks.insert(0, \"Stop\", picks.index + 1)\nprint(picks[[\"Stop\", \"Bin\", \"SKU\", \"Qty\"]].to_string(index=False))\n",[32,678,679,772,791,795,841,879,894,918,968,993,1015],{"__ignoreMap":30},[35,680,681,684,686,689,691,694,697,700,703,707,709,713,716,719,721,724,727,730,733,735,737,740,742,744,746,748,751,754,757,760,762,765,767,769],{"class":37,"line":38},[35,682,683],{"class":84},"loc ",[35,685,107],{"class":80},[35,687,688],{"class":84}," alloc[",[35,690,171],{"class":45},[35,692,693],{"class":84},"].str.extract(",[35,695,696],{"class":80},"r",[35,698,699],{"class":45},"\"",[35,701,702],{"class":219},"(",[35,704,706],{"class":705},"sx1sP","?P\u003CZone>",[35,708,141],{"class":219},[35,710,712],{"class":711},"sSjpA","A-Z",[35,714,715],{"class":219},"])",[35,717,718],{"class":45},"-",[35,720,702],{"class":219},[35,722,723],{"class":705},"?P\u003CAisle>",[35,725,726],{"class":219},"\\d",[35,728,729],{"class":80},"+",[35,731,732],{"class":219},")",[35,734,718],{"class":45},[35,736,702],{"class":219},[35,738,739],{"class":705},"?P\u003CPosition>",[35,741,726],{"class":219},[35,743,729],{"class":80},[35,745,732],{"class":219},[35,747,699],{"class":45},[35,749,750],{"class":84},").astype({",[35,752,753],{"class":45},"\"Aisle\"",[35,755,756],{"class":84},": ",[35,758,759],{"class":219},"int",[35,761,132],{"class":84},[35,763,764],{"class":45},"\"Position\"",[35,766,756],{"class":84},[35,768,759],{"class":219},[35,770,771],{"class":84},"})\n",[35,773,774,776,778,781,784,786,789],{"class":37,"line":94},[35,775,429],{"class":84},[35,777,107],{"class":80},[35,779,780],{"class":84}," pd.concat([alloc, loc], ",[35,782,783],{"class":135},"axis",[35,785,107],{"class":80},[35,787,788],{"class":219},"1",[35,790,116],{"class":84},[35,792,793],{"class":37,"line":101},[35,794,98],{"emptyLinePlaceholder":97},[35,796,797,800,802,805,807,809,812,814,816,818,820,822,824,827,830,832,834,836,838],{"class":37,"line":119},[35,798,799],{"class":84},"picks ",[35,801,107],{"class":80},[35,803,804],{"class":84}," alloc.groupby([",[35,806,171],{"class":45},[35,808,132],{"class":84},[35,810,811],{"class":45},"\"Zone\"",[35,813,132],{"class":84},[35,815,753],{"class":45},[35,817,132],{"class":84},[35,819,764],{"class":45},[35,821,132],{"class":84},[35,823,150],{"class":45},[35,825,826],{"class":84},"], ",[35,828,829],{"class":135},"as_index",[35,831,107],{"class":80},[35,833,220],{"class":219},[35,835,174],{"class":84},[35,837,334],{"class":45},[35,839,840],{"class":84},"].sum()\n",[35,842,843,846,848,851,853,855,857,860,862,864,866,869,872,874,877],{"class":37,"line":160},[35,844,845],{"class":84},"aisle_rank ",[35,847,107],{"class":80},[35,849,850],{"class":84}," picks[[",[35,852,811],{"class":45},[35,854,132],{"class":84},[35,856,753],{"class":45},[35,858,859],{"class":84},"]].drop_duplicates().sort_values([",[35,861,811],{"class":45},[35,863,132],{"class":84},[35,865,753],{"class":45},[35,867,868],{"class":84},"]).reset_index(",[35,870,871],{"class":135},"drop",[35,873,107],{"class":80},[35,875,876],{"class":219},"True",[35,878,116],{"class":84},[35,880,881,884,887,889,891],{"class":37,"line":183},[35,882,883],{"class":84},"aisle_rank[",[35,885,886],{"class":45},"\"Leg\"",[35,888,253],{"class":84},[35,890,107],{"class":80},[35,892,893],{"class":84}," aisle_rank.index\n",[35,895,896,898,900,903,906,908,910,912,914,916],{"class":37,"line":188},[35,897,799],{"class":84},[35,899,107],{"class":80},[35,901,902],{"class":84}," picks.merge(aisle_rank, ",[35,904,905],{"class":135},"on",[35,907,107],{"class":80},[35,909,141],{"class":84},[35,911,811],{"class":45},[35,913,132],{"class":84},[35,915,753],{"class":45},[35,917,157],{"class":84},[35,919,920,923,926,928,930,933,935,938,940,942,945,948,951,953,955,957,959,961,964],{"class":37,"line":199},[35,921,922],{"class":84},"picks[",[35,924,925],{"class":45},"\"Walk\"",[35,927,253],{"class":84},[35,929,107],{"class":80},[35,931,932],{"class":84}," picks[",[35,934,764],{"class":45},[35,936,937],{"class":84},"].where(picks[",[35,939,886],{"class":45},[35,941,253],{"class":84},[35,943,944],{"class":80},"%",[35,946,947],{"class":219}," 2",[35,949,950],{"class":80}," ==",[35,952,302],{"class":219},[35,954,132],{"class":84},[35,956,718],{"class":80},[35,958,922],{"class":84},[35,960,764],{"class":45},[35,962,963],{"class":84},"])   ",[35,965,967],{"class":966},"s-wDw","# snake: every other aisle backwards\n",[35,969,970,972,974,977,979,981,983,985,987,989,991],{"class":37,"line":226},[35,971,799],{"class":84},[35,973,107],{"class":80},[35,975,976],{"class":84}," picks.sort_values([",[35,978,886],{"class":45},[35,980,132],{"class":84},[35,982,925],{"class":45},[35,984,868],{"class":84},[35,986,871],{"class":135},[35,988,107],{"class":80},[35,990,876],{"class":219},[35,992,116],{"class":84},[35,994,995,998,1000,1002,1005,1008,1010,1013],{"class":37,"line":237},[35,996,997],{"class":84},"picks.insert(",[35,999,537],{"class":219},[35,1001,132],{"class":84},[35,1003,1004],{"class":45},"\"Stop\"",[35,1006,1007],{"class":84},", picks.index ",[35,1009,729],{"class":80},[35,1011,1012],{"class":219}," 1",[35,1014,116],{"class":84},[35,1016,1017,1019,1022,1024,1026,1028,1030,1032,1034,1036,1039,1041,1043,1045],{"class":37,"line":276},[35,1018,478],{"class":219},[35,1020,1021],{"class":84},"(picks[[",[35,1023,1004],{"class":45},[35,1025,132],{"class":84},[35,1027,171],{"class":45},[35,1029,132],{"class":84},[35,1031,150],{"class":45},[35,1033,132],{"class":84},[35,1035,334],{"class":45},[35,1037,1038],{"class":84},"]].to_string(",[35,1040,214],{"class":135},[35,1042,107],{"class":80},[35,1044,220],{"class":219},[35,1046,490],{"class":84},[10,1048,1049,1050,1053,1054,1057],{},"Picking order by order means walking past the same bins several times. Batch picking takes every allocation from the same bin together: the picker collects the 300 ",[57,1051,1052],{},"BOLT-M8"," for two orders from bin A-02-05 in one visit, not two, and splits them into orders at the packing bench. Grouping the allocations by bin and SKU does that. The walking order then comes from the bin code. Splitting it into zone, aisle and position allows a ",[57,1055,1056],{},"snake"," path: go up the first aisle in increasing position, down the next in decreasing position, up the third, and so on, so the picker never walks back to the start of an aisle. The trick is a sort key that is the position in even legs and the negative position in odd ones.",[515,1059,524,1065,524,1068,524,1071,524,1076,524,1082,524,1086,524,1092,524,1096,524,1100,524,1104,524,1108,524,1112,524,1116,524,1120,524,1124,524,1128,524,1131,524,1134,524,1138,524,1140,524,1143,524,1145,524,1147,524,1149,524,1152,524,1154,524,1157,524,1160,524,1164,524,1166,524,1169,524,1171,524,1174,524,1176,524,1178,524,1180,524,1182,524,1184,524,1187,524,1189,524,1193,524,1195,524,1197,524,1199,524,1201,524,1203,524,1205,524,1207,524,1210,524,1212,524,1215,524,1218,524,1221,524,1223,524,1225,524,1227,524,1230,524,1232,524,1235,524,1237,524,1239,524,1241,524,1244,524,1247,524,1251,524,1253,524,1255,524,1257,524,1260,524,1262,524,1264,524,1266,524,1269,524,1271,524,1274,524,1277,524,1281,524,1283,524,1285,524,1287,524,1290,524,1292,524,1295,524,1297,524,1300,524,1302,524,1305,524,1308,524,1312,524,1314,524,1316,524,1318,524,1321,524,1323,524,1326,524,1328,524,1331,524,1333,524,1335,524,1338,524,1342,524,1344,524,1346,524,1348,524,1351,524,1353,524,1355,524,1357,524,1360,524,1362],{"viewBox":1060,"role":518,"ariaLabelledBy":1061,"xmlns":522,"style":1064},"172 0 415 280",[1062,1063],"pick-path-t","pick-path-d","width:100%;max-width:415px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[526,1066,1067],{"id":1062},"The batch pick list in walking order",[530,1069,1070],{"id":1063},"The picker starts in zone A aisle 1, then walks back down aisle 2 and up aisle 3, then continues through zones B and C, collecting the combined quantity for all orders at each bin.",[534,1072],{"x":1073,"y":537,"width":1074,"height":1075,"fill":540},"172","415","280",[534,1077],{"x":1078,"y":544,"width":1079,"height":1080,"rx":537,"fill":548,"stroke":549,"style":1081},"188.5","32.0","24.0","stroke-width:1px",[534,1083],{"x":1084,"y":544,"width":1085,"height":1080,"rx":537,"fill":548,"stroke":549,"style":1081},"220.5","52.5",[552,1087,1091],{"x":1088,"y":1089,"style":1090},"246.8","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[534,1093],{"x":1094,"y":544,"width":1095,"height":1080,"rx":537,"fill":548,"stroke":549,"style":1081},"273.1","78.8",[552,1097,1099],{"x":1098,"y":1089,"style":1090},"312.5","B",[534,1101],{"x":1102,"y":544,"width":1103,"height":1080,"rx":537,"fill":548,"stroke":549,"style":1081},"351.9","90.3",[552,1105,1107],{"x":1106,"y":1089,"style":1090},"397.0","C",[534,1109],{"x":1110,"y":544,"width":1111,"height":1080,"rx":537,"fill":548,"stroke":549,"style":1081},"442.2","49.1",[552,1113,1115],{"x":1114,"y":1089,"style":1090},"466.7","D",[534,1117],{"x":1118,"y":544,"width":1119,"height":1080,"rx":537,"fill":548,"stroke":549,"style":1081},"491.3","80.2",[552,1121,1123],{"x":1122,"y":1089,"style":1090},"531.4","E",[534,1125],{"x":1078,"y":1126,"width":1079,"height":1127,"rx":537,"fill":548,"stroke":549,"style":1081},"40.0","28.0",[552,1129,788],{"x":1130,"y":581,"style":1090},"204.5",[534,1132],{"x":1084,"y":1126,"width":1085,"height":1127,"rx":537,"fill":577,"stroke":568,"style":1133},"stroke-width:1.5px",[552,1135,1137],{"x":1088,"y":581,"style":1136},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Stop",[534,1139],{"x":1094,"y":1126,"width":1095,"height":1127,"rx":537,"fill":577,"stroke":568,"style":1133},[552,1141,1142],{"x":1098,"y":581,"style":1136},"Bin",[534,1144],{"x":1102,"y":1126,"width":1103,"height":1127,"rx":537,"fill":577,"stroke":568,"style":1133},[552,1146,262],{"x":1106,"y":581,"style":1136},[534,1148],{"x":1110,"y":1126,"width":1111,"height":1127,"rx":537,"fill":577,"stroke":568,"style":1133},[552,1150,1151],{"x":1114,"y":581,"style":1136},"Qty",[534,1153],{"x":1118,"y":1126,"width":1119,"height":1127,"rx":537,"fill":577,"stroke":568,"style":1133},[552,1155,1156],{"x":1122,"y":581,"style":1136},"Direction",[534,1158],{"x":1078,"y":1159,"width":1079,"height":1127,"rx":537,"fill":548,"stroke":549,"style":1081},"68.0",[552,1161,1163],{"x":1130,"y":1162,"style":1090},"87.0","2",[534,1165],{"x":1084,"y":1159,"width":1085,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1167,788],{"x":1088,"y":1162,"style":1168},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[534,1170],{"x":1094,"y":1159,"width":1095,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1172,1173],{"x":1098,"y":1162,"style":1168},"A-01-02",[534,1175],{"x":1102,"y":1159,"width":1103,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1177,512],{"x":1106,"y":1162,"style":1168},[534,1179],{"x":1110,"y":1159,"width":1111,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1181,547],{"x":1114,"y":1162,"style":1168},[534,1183],{"x":1118,"y":1159,"width":1119,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1185,1186],{"x":1122,"y":1162,"style":1168},"aisle 1 ↑",[534,1188],{"x":1078,"y":589,"width":1079,"height":1127,"rx":537,"fill":548,"stroke":549,"style":1081},[552,1190,1192],{"x":1130,"y":1191,"style":1090},"115.0","3",[534,1194],{"x":1084,"y":589,"width":1085,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1196,1163],{"x":1088,"y":1191,"style":1168},[534,1198],{"x":1094,"y":589,"width":1095,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1200,63],{"x":1098,"y":1191,"style":1168},[534,1202],{"x":1102,"y":589,"width":1103,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1204,1052],{"x":1106,"y":1191,"style":1168},[534,1206],{"x":1110,"y":589,"width":1111,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1208,1209],{"x":1114,"y":1191,"style":1168},"300",[534,1211],{"x":1118,"y":589,"width":1119,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1213,1214],{"x":1122,"y":1191,"style":1168},"aisle 2 ↓",[534,1216],{"x":1078,"y":1217,"width":1079,"height":1127,"rx":537,"fill":548,"stroke":549,"style":1081},"124.0",[552,1219,536],{"x":1130,"y":1220,"style":1090},"143.0",[534,1222],{"x":1084,"y":1217,"width":1085,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1224,1192],{"x":1088,"y":1220,"style":1168},[534,1226],{"x":1094,"y":1217,"width":1095,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1228,1229],{"x":1098,"y":1220,"style":1168},"A-03-04",[534,1231],{"x":1102,"y":1217,"width":1103,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1233,1234],{"x":1106,"y":1220,"style":1168},"PUMP-X1",[534,1236],{"x":1110,"y":1217,"width":1111,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1238,1163],{"x":1114,"y":1220,"style":1168},[534,1240],{"x":1118,"y":1217,"width":1119,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1242,1243],{"x":1122,"y":1220,"style":1168},"aisle 3 ↑",[534,1245],{"x":1078,"y":1246,"width":1079,"height":1127,"rx":537,"fill":548,"stroke":549,"style":1081},"152.0",[552,1248,1250],{"x":1130,"y":1249,"style":1090},"171.0","5",[534,1252],{"x":1084,"y":1246,"width":1085,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1254,536],{"x":1088,"y":1249,"style":1168},[534,1256],{"x":1094,"y":1246,"width":1095,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1258,1259],{"x":1098,"y":1249,"style":1168},"B-01-03",[534,1261],{"x":1102,"y":1246,"width":1103,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1263,1052],{"x":1106,"y":1249,"style":1168},[534,1265],{"x":1110,"y":1246,"width":1111,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1267,1268],{"x":1114,"y":1249,"style":1168},"150",[534,1270],{"x":1118,"y":1246,"width":1119,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1272,1273],{"x":1122,"y":1249,"style":1168},"aisle 1 ↓",[534,1275],{"x":1078,"y":1276,"width":1079,"height":1127,"rx":537,"fill":548,"stroke":549,"style":1081},"180.0",[552,1278,1280],{"x":1130,"y":1279,"style":1090},"199.0","6",[534,1282],{"x":1084,"y":1276,"width":1085,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1284,1250],{"x":1088,"y":1279,"style":1168},[534,1286],{"x":1094,"y":1276,"width":1095,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1288,1289],{"x":1098,"y":1279,"style":1168},"B-02-01",[534,1291],{"x":1102,"y":1276,"width":1103,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1293,1294],{"x":1106,"y":1279,"style":1168},"GASKET-3",[534,1296],{"x":1110,"y":1276,"width":1111,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1298,1299],{"x":1114,"y":1279,"style":1168},"10",[534,1301],{"x":1118,"y":1276,"width":1119,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1303,1304],{"x":1122,"y":1279,"style":1168},"aisle 2 ↑",[534,1306],{"x":1078,"y":1307,"width":1079,"height":1127,"rx":537,"fill":548,"stroke":549,"style":1081},"208.0",[552,1309,1311],{"x":1130,"y":1310,"style":1090},"227.0","7",[534,1313],{"x":1084,"y":1307,"width":1085,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1315,1280],{"x":1088,"y":1310,"style":1168},[534,1317],{"x":1094,"y":1307,"width":1095,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1319,1320],{"x":1098,"y":1310,"style":1168},"C-01-06",[534,1322],{"x":1102,"y":1307,"width":1103,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1324,1325],{"x":1106,"y":1310,"style":1168},"WID-B",[534,1327],{"x":1110,"y":1307,"width":1111,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1329,1330],{"x":1114,"y":1310,"style":1168},"11",[534,1332],{"x":1118,"y":1307,"width":1119,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1334,1273],{"x":1122,"y":1310,"style":1168},[534,1336],{"x":1078,"y":1337,"width":1079,"height":1127,"rx":537,"fill":548,"stroke":549,"style":1081},"236.0",[552,1339,1341],{"x":1130,"y":1340,"style":1090},"255.0","8",[534,1343],{"x":1084,"y":1337,"width":1085,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1345,1311],{"x":1088,"y":1340,"style":1168},[534,1347],{"x":1094,"y":1337,"width":1095,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1349,1350],{"x":1098,"y":1340,"style":1168},"C-03-01",[534,1352],{"x":1102,"y":1337,"width":1103,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1354,512],{"x":1106,"y":1340,"style":1168},[534,1356],{"x":1110,"y":1337,"width":1111,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1358,1359],{"x":1114,"y":1340,"style":1168},"9",[534,1361],{"x":1118,"y":1337,"width":1119,"height":1127,"rx":537,"fill":540,"stroke":549,"style":1081},[552,1363,1243],{"x":1122,"y":1340,"style":1168},[515,1365,524,1370,524,1373,524,1376,524,1379,524,1384,524,1390,524,1395,524,1399,524,1403,524,1407,524,1411,524,1414,524,1419,524,1423,524,1426,524,1429,524,1432],{"viewBox":1366,"role":518,"ariaLabelledBy":1367,"xmlns":522,"style":523},"4 0 752 199",[1368,1369],"pick-batch-t","pick-batch-d",[526,1371,1372],{"id":1368},"Picking by order or in a batch",[530,1374,1375],{"id":1369},"Picking order by order visits a bin once for each order that needs it and needs no sorting afterwards. Batch picking visits each bin once for all orders, which shortens the walk, but the picked items must be sorted into orders at the packing bench.",[534,1377],{"x":536,"y":537,"width":538,"height":1378,"fill":540},"199",[534,1380],{"x":543,"y":544,"width":1381,"height":1382,"rx":1383,"fill":548,"stroke":549,"style":550},"351.0","167.0","14",[552,1385,1389],{"x":1386,"y":1387,"style":1388},"195.5","44.0","font-size:14px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Order by order",[37,1391],{"x1":1392,"y1":1393,"x2":1394,"y2":1393,"stroke":549,"style":1081},"36.0","57.0","355.0",[552,1396,1398],{"x":1386,"y":1397,"style":1168},"77.0","one trip per order",[552,1400,1402],{"x":1386,"y":1401,"style":1168},"103.0","same bin visited repeatedly",[552,1404,1406],{"x":1386,"y":1405,"style":1168},"129.0","no sorting afterwards",[552,1408,1410],{"x":1386,"y":1409,"style":1168},"155.0","suits few, large orders",[534,1412],{"x":1413,"y":544,"width":1381,"height":1382,"rx":1383,"fill":632,"stroke":633,"style":550},"389.0",[552,1415,1418],{"x":1416,"y":1387,"style":1417},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Batch",[37,1420],{"x1":1421,"y1":1393,"x2":1422,"y2":1393,"stroke":633,"style":1081},"405.0","724.0",[552,1424,1425],{"x":1416,"y":1397,"style":1168},"one trip for many orders",[552,1427,1428],{"x":1416,"y":1401,"style":1168},"each bin visited once",[552,1430,1431],{"x":1416,"y":1405,"style":1168},"sort into orders at packing",[552,1433,1434],{"x":1416,"y":1409,"style":1168},"suits many small orders",[10,1436,1437],{},"Batch picking pays off when there are many small orders that share items, which is typical of trade and online orders; for a handful of large orders, picking each one separately avoids the sorting step and is often just as quick.",[20,1439,1441],{"id":1440},"step-3-the-put-to-order-table-and-the-shortage-list","Step 3 — The put-to-order table and the shortage list",[25,1443,1445],{"className":71,"code":1444,"language":73,"meta":30,"style":30},"put = alloc.pivot_table(index=[\"SKU\", \"Bin\"], columns=\"Order\", values=\"Qty\", aggfunc=\"sum\", fill_value=0)\nprint(put.to_string())\nprint(\"units picked:\", int(alloc[\"Qty\"].sum()), \"| units short:\", int(short[\"Short\"].sum()) if len(short) else 0)\n",[32,1446,1447,1508,1515],{"__ignoreMap":30},[35,1448,1449,1452,1454,1457,1459,1461,1463,1465,1467,1469,1471,1474,1476,1478,1480,1483,1485,1487,1489,1492,1494,1497,1499,1502,1504,1506],{"class":37,"line":38},[35,1450,1451],{"class":84},"put ",[35,1453,107],{"class":80},[35,1455,1456],{"class":84}," alloc.pivot_table(",[35,1458,214],{"class":135},[35,1460,107],{"class":80},[35,1462,141],{"class":84},[35,1464,150],{"class":45},[35,1466,132],{"class":84},[35,1468,171],{"class":45},[35,1470,826],{"class":84},[35,1472,1473],{"class":135},"columns",[35,1475,107],{"class":80},[35,1477,314],{"class":45},[35,1479,132],{"class":84},[35,1481,1482],{"class":135},"values",[35,1484,107],{"class":80},[35,1486,334],{"class":45},[35,1488,132],{"class":84},[35,1490,1491],{"class":135},"aggfunc",[35,1493,107],{"class":80},[35,1495,1496],{"class":45},"\"sum\"",[35,1498,132],{"class":84},[35,1500,1501],{"class":135},"fill_value",[35,1503,107],{"class":80},[35,1505,537],{"class":219},[35,1507,116],{"class":84},[35,1509,1510,1512],{"class":37,"line":94},[35,1511,478],{"class":219},[35,1513,1514],{"class":84},"(put.to_string())\n",[35,1516,1517,1519,1521,1524,1526,1528,1531,1533,1536,1539,1541,1543,1546,1548,1551,1554,1557,1560,1563,1565],{"class":37,"line":101},[35,1518,478],{"class":219},[35,1520,702],{"class":84},[35,1522,1523],{"class":45},"\"units picked:\"",[35,1525,132],{"class":84},[35,1527,759],{"class":219},[35,1529,1530],{"class":84},"(alloc[",[35,1532,334],{"class":45},[35,1534,1535],{"class":84},"].sum()), ",[35,1537,1538],{"class":45},"\"| units short:\"",[35,1540,132],{"class":84},[35,1542,759],{"class":219},[35,1544,1545],{"class":84},"(short[",[35,1547,415],{"class":45},[35,1549,1550],{"class":84},"].sum()) ",[35,1552,1553],{"class":80},"if",[35,1555,1556],{"class":219}," len",[35,1558,1559],{"class":84},"(short) ",[35,1561,1562],{"class":80},"else",[35,1564,302],{"class":219},[35,1566,116],{"class":84},[10,1568,1569],{},"After a batch pick, the items have to be sorted back into their orders. A small pivot — SKU and bin down the side, orders across the top — tells the packer how many of each picked item go into each order. It is also a check: each row adds up to the quantity picked from that bin. The shortage list goes to whoever manages customer orders, so they can tell customers, split shipments or chase the supplier before the van leaves. Here two order lines cannot be filled completely: SO-505 gets one of its two pumps because only two were in stock and SO-503 took the first, and SO-504 is three gaskets short after SO-502's four left six of the ten. Of 498 units ordered, 494 are picked.",[20,1571,1573],{"id":1572},"step-4-one-printable-sheet-per-picker","Step 4 — One printable sheet per picker",[25,1575,1577],{"className":71,"code":1576,"language":73,"meta":30,"style":30},"from openpyxl import load_workbook\nfrom openpyxl.styles import Alignment, Font\n\npickers = [\"Picker 1\", \"Picker 2\"]\npicks[\"Picker\"] = [pickers[0] if leg \u003C 3 else pickers[1] for leg in picks[\"Leg\"]]     # zone A to picker 1, the rest to picker 2\npath = \"pick_lists_2026-10-06.xlsx\"\nwith pd.ExcelWriter(path) as xw:\n    for name, g in picks.groupby(\"Picker\"):\n        g.assign(Done=\"☐\")[[\"Stop\", \"Bin\", \"SKU\", \"Qty\", \"Done\"]].to_excel(xw, sheet_name=name, index=False, startrow=2)\n    put.reset_index().to_excel(xw, sheet_name=\"Put to order\", index=False)\n    (short if len(short) else pd.DataFrame(columns=[\"Order\", \"SKU\", \"Ordered\", \"Short\"])).to_excel(xw, sheet_name=\"Shortages\", index=False)\n\nwb = load_workbook(path)\nfor name in pickers:\n    ws = wb[name]\n    ws[\"A1\"] = f\"{name} — pick list for Tue 6 Oct 2026\"\n    ws[\"A1\"].font = Font(size=14, bold=True)\n    for row in ws.iter_rows(min_row=4):\n        row[4].alignment = Alignment(horizontal=\"center\")\n        for cell in row:\n            cell.font = Font(size=13)\n    ws.column_dimensions[\"B\"].width = ws.column_dimensions[\"C\"].width = 14\n    ws.page_setup.fitToWidth = 1\n    ws.sheet_properties.pageSetUpPr.fitToPage = True\n    ws.print_title_rows = \"3:3\"\nwb.save(path)\nprint(wb.sheetnames)\n",[32,1578,1579,1592,1604,1608,1629,1684,1694,1707,1723,1786,1808,1864,1868,1878,1890,1900,1929,1961,1982,2007,2020,2038,2064,2074,2084,2094,2100],{"__ignoreMap":30},[35,1580,1581,1584,1587,1589],{"class":37,"line":38},[35,1582,1583],{"class":80},"from",[35,1585,1586],{"class":84}," openpyxl ",[35,1588,81],{"class":80},[35,1590,1591],{"class":84}," load_workbook\n",[35,1593,1594,1596,1599,1601],{"class":37,"line":94},[35,1595,1583],{"class":80},[35,1597,1598],{"class":84}," openpyxl.styles ",[35,1600,81],{"class":80},[35,1602,1603],{"class":84}," Alignment, Font\n",[35,1605,1606],{"class":37,"line":101},[35,1607,98],{"emptyLinePlaceholder":97},[35,1609,1610,1613,1615,1618,1621,1623,1626],{"class":37,"line":119},[35,1611,1612],{"class":84},"pickers ",[35,1614,107],{"class":80},[35,1616,1617],{"class":84}," [",[35,1619,1620],{"class":45},"\"Picker 1\"",[35,1622,132],{"class":84},[35,1624,1625],{"class":45},"\"Picker 2\"",[35,1627,1628],{"class":84},"]\n",[35,1630,1631,1633,1636,1638,1640,1643,1645,1647,1649,1652,1655,1658,1661,1664,1666,1668,1670,1672,1674,1676,1678,1681],{"class":37,"line":160},[35,1632,922],{"class":84},[35,1634,1635],{"class":45},"\"Picker\"",[35,1637,253],{"class":84},[35,1639,107],{"class":80},[35,1641,1642],{"class":84}," [pickers[",[35,1644,537],{"class":219},[35,1646,253],{"class":84},[35,1648,1553],{"class":80},[35,1650,1651],{"class":84}," leg ",[35,1653,1654],{"class":80},"\u003C",[35,1656,1657],{"class":219}," 3",[35,1659,1660],{"class":80}," else",[35,1662,1663],{"class":84}," pickers[",[35,1665,788],{"class":219},[35,1667,253],{"class":84},[35,1669,202],{"class":80},[35,1671,1651],{"class":84},[35,1673,208],{"class":80},[35,1675,932],{"class":84},[35,1677,886],{"class":45},[35,1679,1680],{"class":84},"]]     ",[35,1682,1683],{"class":966},"# zone A to picker 1, the rest to picker 2\n",[35,1685,1686,1689,1691],{"class":37,"line":183},[35,1687,1688],{"class":84},"path ",[35,1690,107],{"class":80},[35,1692,1693],{"class":45}," \"pick_lists_2026-10-06.xlsx\"\n",[35,1695,1696,1699,1702,1704],{"class":37,"line":188},[35,1697,1698],{"class":80},"with",[35,1700,1701],{"class":84}," pd.ExcelWriter(path) ",[35,1703,88],{"class":80},[35,1705,1706],{"class":84}," xw:\n",[35,1708,1709,1711,1714,1716,1719,1721],{"class":37,"line":199},[35,1710,240],{"class":80},[35,1712,1713],{"class":84}," name, g ",[35,1715,208],{"class":80},[35,1717,1718],{"class":84}," picks.groupby(",[35,1720,1635],{"class":45},[35,1722,223],{"class":84},[35,1724,1725,1728,1731,1733,1736,1739,1741,1743,1745,1747,1749,1751,1753,1755,1758,1761,1764,1766,1769,1771,1773,1775,1777,1780,1782,1784],{"class":37,"line":226},[35,1726,1727],{"class":84},"        g.assign(",[35,1729,1730],{"class":135},"Done",[35,1732,107],{"class":80},[35,1734,1735],{"class":45},"\"☐\"",[35,1737,1738],{"class":84},")[[",[35,1740,1004],{"class":45},[35,1742,132],{"class":84},[35,1744,171],{"class":45},[35,1746,132],{"class":84},[35,1748,150],{"class":45},[35,1750,132],{"class":84},[35,1752,334],{"class":45},[35,1754,132],{"class":84},[35,1756,1757],{"class":45},"\"Done\"",[35,1759,1760],{"class":84},"]].to_excel(xw, ",[35,1762,1763],{"class":135},"sheet_name",[35,1765,107],{"class":80},[35,1767,1768],{"class":84},"name, ",[35,1770,214],{"class":135},[35,1772,107],{"class":80},[35,1774,220],{"class":219},[35,1776,132],{"class":84},[35,1778,1779],{"class":135},"startrow",[35,1781,107],{"class":80},[35,1783,1163],{"class":219},[35,1785,116],{"class":84},[35,1787,1788,1791,1793,1795,1798,1800,1802,1804,1806],{"class":37,"line":237},[35,1789,1790],{"class":84},"    put.reset_index().to_excel(xw, ",[35,1792,1763],{"class":135},[35,1794,107],{"class":80},[35,1796,1797],{"class":45},"\"Put to order\"",[35,1799,132],{"class":84},[35,1801,214],{"class":135},[35,1803,107],{"class":80},[35,1805,220],{"class":219},[35,1807,116],{"class":84},[35,1809,1810,1813,1815,1817,1819,1821,1824,1826,1828,1830,1832,1834,1836,1838,1840,1842,1844,1847,1849,1851,1854,1856,1858,1860,1862],{"class":37,"line":276},[35,1811,1812],{"class":84},"    (short ",[35,1814,1553],{"class":80},[35,1816,1556],{"class":219},[35,1818,1559],{"class":84},[35,1820,1562],{"class":80},[35,1822,1823],{"class":84}," pd.DataFrame(",[35,1825,1473],{"class":135},[35,1827,107],{"class":80},[35,1829,141],{"class":84},[35,1831,314],{"class":45},[35,1833,132],{"class":84},[35,1835,150],{"class":45},[35,1837,132],{"class":84},[35,1839,409],{"class":45},[35,1841,132],{"class":84},[35,1843,415],{"class":45},[35,1845,1846],{"class":84},"])).to_excel(xw, ",[35,1848,1763],{"class":135},[35,1850,107],{"class":80},[35,1852,1853],{"class":45},"\"Shortages\"",[35,1855,132],{"class":84},[35,1857,214],{"class":135},[35,1859,107],{"class":80},[35,1861,220],{"class":219},[35,1863,116],{"class":84},[35,1865,1866],{"class":37,"line":290},[35,1867,98],{"emptyLinePlaceholder":97},[35,1869,1870,1873,1875],{"class":37,"line":308},[35,1871,1872],{"class":84},"wb ",[35,1874,107],{"class":80},[35,1876,1877],{"class":84}," load_workbook(path)\n",[35,1879,1880,1882,1885,1887],{"class":37,"line":340},[35,1881,202],{"class":80},[35,1883,1884],{"class":84}," name ",[35,1886,208],{"class":80},[35,1888,1889],{"class":84}," pickers:\n",[35,1891,1892,1895,1897],{"class":37,"line":352},[35,1893,1894],{"class":84},"    ws ",[35,1896,107],{"class":80},[35,1898,1899],{"class":84}," wb[name]\n",[35,1901,1902,1905,1908,1910,1912,1915,1917,1920,1923,1926],{"class":37,"line":362},[35,1903,1904],{"class":84},"    ws[",[35,1906,1907],{"class":45},"\"A1\"",[35,1909,253],{"class":84},[35,1911,107],{"class":80},[35,1913,1914],{"class":80}," f",[35,1916,699],{"class":45},[35,1918,1919],{"class":711},"{",[35,1921,1922],{"class":84},"name",[35,1924,1925],{"class":711},"}",[35,1927,1928],{"class":45}," — pick list for Tue 6 Oct 2026\"\n",[35,1930,1931,1933,1935,1938,1940,1943,1946,1948,1950,1952,1955,1957,1959],{"class":37,"line":376},[35,1932,1904],{"class":84},[35,1934,1907],{"class":45},[35,1936,1937],{"class":84},"].font ",[35,1939,107],{"class":80},[35,1941,1942],{"class":84}," Font(",[35,1944,1945],{"class":135},"size",[35,1947,107],{"class":80},[35,1949,1383],{"class":219},[35,1951,132],{"class":84},[35,1953,1954],{"class":135},"bold",[35,1956,107],{"class":80},[35,1958,876],{"class":219},[35,1960,116],{"class":84},[35,1962,1963,1965,1968,1970,1973,1976,1978,1980],{"class":37,"line":382},[35,1964,240],{"class":80},[35,1966,1967],{"class":84}," row ",[35,1969,208],{"class":80},[35,1971,1972],{"class":84}," ws.iter_rows(",[35,1974,1975],{"class":135},"min_row",[35,1977,107],{"class":80},[35,1979,536],{"class":219},[35,1981,223],{"class":84},[35,1983,1984,1987,1989,1992,1994,1997,2000,2002,2005],{"class":37,"line":391},[35,1985,1986],{"class":84},"        row[",[35,1988,536],{"class":219},[35,1990,1991],{"class":84},"].alignment ",[35,1993,107],{"class":80},[35,1995,1996],{"class":84}," Alignment(",[35,1998,1999],{"class":135},"horizontal",[35,2001,107],{"class":80},[35,2003,2004],{"class":45},"\"center\"",[35,2006,116],{"class":84},[35,2008,2009,2012,2015,2017],{"class":37,"line":421},[35,2010,2011],{"class":80},"        for",[35,2013,2014],{"class":84}," cell ",[35,2016,208],{"class":80},[35,2018,2019],{"class":84}," row:\n",[35,2021,2022,2025,2027,2029,2031,2033,2036],{"class":37,"line":426},[35,2023,2024],{"class":84},"            cell.font ",[35,2026,107],{"class":80},[35,2028,1942],{"class":84},[35,2030,1945],{"class":135},[35,2032,107],{"class":80},[35,2034,2035],{"class":219},"13",[35,2037,116],{"class":84},[35,2039,2040,2043,2046,2049,2051,2054,2057,2059,2061],{"class":37,"line":437},[35,2041,2042],{"class":84},"    ws.column_dimensions[",[35,2044,2045],{"class":45},"\"B\"",[35,2047,2048],{"class":84},"].width ",[35,2050,107],{"class":80},[35,2052,2053],{"class":84}," ws.column_dimensions[",[35,2055,2056],{"class":45},"\"C\"",[35,2058,2048],{"class":84},[35,2060,107],{"class":80},[35,2062,2063],{"class":219}," 14\n",[35,2065,2066,2069,2071],{"class":37,"line":448},[35,2067,2068],{"class":84},"    ws.page_setup.fitToWidth ",[35,2070,107],{"class":80},[35,2072,2073],{"class":219}," 1\n",[35,2075,2076,2079,2081],{"class":37,"line":475},[35,2077,2078],{"class":84},"    ws.sheet_properties.pageSetUpPr.fitToPage ",[35,2080,107],{"class":80},[35,2082,2083],{"class":219}," True\n",[35,2085,2086,2089,2091],{"class":37,"line":493},[35,2087,2088],{"class":84},"    ws.print_title_rows ",[35,2090,107],{"class":80},[35,2092,2093],{"class":45}," \"3:3\"\n",[35,2095,2097],{"class":37,"line":2096},26,[35,2098,2099],{"class":84},"wb.save(path)\n",[35,2101,2103,2105],{"class":37,"line":2102},27,[35,2104,478],{"class":219},[35,2106,2107],{"class":84},"(wb.sheetnames)\n",[10,2109,2110,2111,18],{},"Each picker gets a sheet with their stops in walking order, the bin, the SKU, the quantity and an empty box to tick, in a large font because the list is read on a trolley, not at a desk. Splitting by zone is the simplest way to divide the work between two pickers without them crossing paths; splitting by number of stops or by weight works the same way with a different rule. The heading row repeats on every printed page, and fit-to-width keeps each list on the paper. The put-to-order and shortage sheets go to the packing bench and the customer service team. For printing sheets from a scheduled job, see ",[14,2112,2114],{"href":2113},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fprint-an-excel-workbook-from-python-with-win32com\u002F","Print an Excel Workbook from Python with win32com",[20,2116,2118],{"id":2117},"common-pitfalls","Common pitfalls",[2120,2121,2122,2130,2136,2142,2148],"ul",{},[2123,2124,2125,2129],"li",{},[2126,2127,2128],"strong",{},"Allocating against the starting stock."," Track what is left in each bin as lines are allocated.",[2123,2131,2132,2135],{},[2126,2133,2134],{},"Over-allocating silently."," Record shortages, and assert no bin is overdrawn.",[2123,2137,2138,2141],{},[2126,2139,2140],{},"Picking order by order."," Combine identical bin and SKU picks into one stop.",[2123,2143,2144,2147],{},[2126,2145,2146],{},"Sorting bins alphabetically."," Use a snake path by aisle so pickers never double back.",[2123,2149,2150,2153],{},[2126,2151,2152],{},"Losing the link to orders."," Keep a put-to-order table for sorting the batch at packing.",[20,2155,2157],{"id":2156},"conclusion","Conclusion",[10,2159,2160],{},"A pick list is an allocation, a grouping and a sort. Allocate each order line to its SKU's bins oldest first while tracking what is left in each bin, and record what cannot be filled as a shortage. Combine allocations from the same bin into one stop, order the stops in a snake path through zones and aisles, give each picker a printable sheet with tick boxes, and hand the packers a put-to-order table to split the batch back into orders.",[20,2162,2164],{"id":2163},"frequently-asked-questions","Frequently asked questions",[10,2166,2167,2170],{},[2126,2168,2169],{},"How do I allocate stock to orders first in, first out in pandas?","\nSort the bins for each SKU by received date and take from each in turn, reducing a running record of what is left in every bin.",[10,2172,2173,2176],{},[2126,2174,2175],{},"How do I sort a pick list to minimise walking?","\nSplit bin codes into zone, aisle and position, and sort by aisle with the position ascending in one aisle and descending in the next.",[10,2178,2179,2182],{},[2126,2180,2181],{},"What is batch picking?","\nCollecting the combined quantity of an item for several orders in one visit to its bin, then sorting it into orders afterwards.",[10,2184,2185,2188],{},[2126,2186,2187],{},"How do I record stock shortages when allocating orders?","\nWhen the bins for a SKU are exhausted before the line is filled, store the remaining quantity in a shortage list instead of allocating it.",[20,2190,2192],{"id":2191},"related","Related",[2120,2194,2195,2201,2208,2215],{},[2123,2196,2197,2198,2200],{},"Up one level: ",[14,2199,17],{"href":16}," — finance and operations reports.",[2123,2202,2203,2207],{},[14,2204,2206],{"href":2205},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-inventory-reorder-report\u002F","Build an Inventory Reorder Report with Python and Excel"," — what to replenish.",[2123,2209,2210,2214],{},[14,2211,2213],{"href":2212},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fcalculate-fifo-inventory-valuation-with-python\u002F","Calculate FIFO Inventory Valuation with Python"," — first in, first out for valuation.",[2123,2216,2217,2221],{},[14,2218,2220],{"href":2219},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-purchase-order-tracking-report\u002F","Build a Purchase Order Tracking Report"," — chasing the shortages.",[2223,2224,2225],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sx1sP, html code.shiki .sx1sP{--shiki-default:#22863A;--shiki-dark:#72F088}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":30,"searchDepth":94,"depth":94,"links":2227},[2228,2229,2230,2231,2232,2233,2234,2235,2236],{"id":22,"depth":94,"text":23},{"id":67,"depth":94,"text":68},{"id":672,"depth":94,"text":673},{"id":1440,"depth":94,"text":1441},{"id":1572,"depth":94,"text":1573},{"id":2117,"depth":94,"text":2118},{"id":2156,"depth":94,"text":2157},{"id":2163,"depth":94,"text":2164},{"id":2191,"depth":94,"text":2192},"2026-10-02","Turn the day's open orders into printable pick lists with pandas: allocate each order line to stock in specific bins, oldest stock first, record shortages instead of over-allocating, combine identical items across orders into one batch pick, sort the picks in a snake path through the aisles so the picker never doubles back, and write one sheet per picker with tick boxes and a put-to-order table.","md",[2241,2243,2245,2247],{"q":2169,"a":2242},"Sort the bins for each SKU by received date and take from each in turn, reducing a running record of what is left in every bin.",{"q":2175,"a":2244},"Split bin codes into zone, aisle and position, and sort by aisle with the position ascending in one aisle and descending in the next.",{"q":2181,"a":2246},"Collecting the combined quantity of an item for several orders in one visit to its bin, then sorting it into orders afterwards.",{"q":2187,"a":2248},"When the bins for a SKU are exhausted before the line is filled, store the remaining quantity in a shortage list instead of allocating it.","warehouse pick list python",null,{"breadcrumb":2252},[2253,2256,2259],{"name":2254,"item":2255},"Home","\u002F",{"name":2257,"item":2258},"Automating Reporting Workflows with Python and Excel","\u002Fautomating-reporting-workflows\u002F",{"name":2260,"item":16},"Building Finance and Operations Reports in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders",{"title":2263,"description":2264},"Build a Warehouse Pick List from Orders with Python","Pick lists with pandas: allocate order lines to bins oldest first, record shortages, batch identical SKUs, sort picks in a snake path by aisle and position, and print one Excel sheet per picker.","build-a-warehouse-pick-list-from-orders","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders\u002Findex",[2268,2269],"report-layouts","pandas","how-to","dGAO7PIdJjCOw2T5V8WuZHNyxiy8gD4Zym-r2S5QmFA",[2273,2277],{"title":2274,"path":2275,"stem":2276,"children":-1},"Build a VAT Return Summary from Transactions","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions\u002Findex",{"title":2278,"path":2279,"stem":2280,"children":-1},"Build a Warranty Claims Report","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warranty-claims-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warranty-claims-report\u002Findex",[2282,2284],{"path":2283,"title":2260},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports",{"path":2285,"title":2257},"\u002Fautomating-reporting-workflows",[],[2288,2292,2295,2298,2301,2304],{"path":2289,"title":2290,"kind":2291},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards","Building Multi-Sheet Excel Dashboards","guide",{"path":2293,"title":2294,"kind":2270},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-data-dictionary-sheet-to-an-excel-report","Add a Data Dictionary Sheet to an Excel Report",{"path":2296,"title":2297,"kind":2270},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-kpi-summary-block-to-an-excel-dashboard","Add a KPI Summary Block to an Excel Dashboard",{"path":2299,"title":2300,"kind":2270},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-table-of-contents-sheet-with-hyperlinks-in-excel","Add a Table of Contents Sheet with Hyperlinks in Excel",{"path":2302,"title":2303,"kind":2270},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-slicer-style-filters-to-an-excel-dashboard","Add a Dropdown Filter That Drives an Excel Dashboard",{"path":2305,"title":2306,"kind":2270},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-summary-sheet-to-excel-report-python","Add a Summary Sheet to an Excel Report with Python",1790972127460]