[{"data":1,"prerenderedAt":2607},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report":3,"surround:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report":2572,"ancestors:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report":2581,"children:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report":2586,"related:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report":2587},{"id":4,"title":5,"body":6,"dateModified":2539,"datePublished":2539,"description":2540,"extension":2541,"faq":2542,"keyword":2551,"kind":2552,"meta":2553,"navigation":130,"path":2562,"seo":2563,"slug":2566,"stem":2567,"topics":2568,"type":2570,"__hash__":2571},"docs\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report\u002Findex.md","Build an Employee Leave Balance Report",{"type":7,"value":8,"toc":2528},"minimark",[9,19,24,59,66,70,82,630,643,850,854,857,1248,1251,1255,1616,1627,1739,1742,1847,1851,1854,2398,2413,2417,2452,2456,2463,2467,2473,2479,2485,2491,2495,2524],[10,11,12,13,18],"p",{},"Leave balances are a small calculation that generates a lot of questions: \"how many days do I have left?\", \"why does my balance differ from my own count?\", \"who still has fifteen days to take before December?\". HR systems hold the answer in principle, but the report people actually use is often a spreadsheet maintained by hand — and the hand-maintained version is where the errors live: a part-timer's Monday bank holiday counted as leave, a booking over New Year counted entirely in one year, a starter given a full year's entitlement. This page builds the report with pandas from two exports — the employee list and the leave bookings — counting every booking in working days according to each person's work pattern and the public holiday calendar, pro-rating entitlement for starters and part-timers, applying carry-over that expires, and flagging balances that need attention. 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 numpy openpyxl holidays\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47,50,53,56],"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}," numpy",[35,54,55],{"class":45}," openpyxl",[35,57,58],{"class":45}," holidays\n",[10,60,61,62,65],{},"The inputs are an employee list — start and end dates, the days of the week each person works, full-time entitlement and days carried over from last year — and a bookings export with one row per booking: employee, first and last day, and a half-day flag. The leave year is the calendar year 2026 and the report is run on 2 October 2026. Public holidays come from the ",[32,63,64],{},"holidays"," package for England; use your own calendar if your organisation's differs.",[20,67,69],{"id":68},"step-1-count-bookings-in-each-persons-working-days","Step 1 — Count bookings in each person's working days",[10,71,72,73,76,77,81],{},"A booking from Monday to Friday is five days for a full-timer, but only three for someone who works Monday to Wednesday, and four if the Monday is a public holiday. NumPy's ",[32,74,75],{},"busday_count"," does this counting with a ",[78,79,80],"em",{},"weekmask"," for the work pattern and a list of holidays to skip:",[25,83,87],{"className":84,"code":85,"language":86,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import holidays\nimport numpy as np\nimport pandas as pd\n\nYEAR = 2026\nYEAR_START, YEAR_END = np.datetime64(f\"{YEAR}-01-01\"), np.datetime64(f\"{YEAR + 1}-01-01\")\nBANK_HOLIDAYS = np.array(sorted(holidays.country_holidays(\"GB\", subdiv=\"ENG\", years=[YEAR, YEAR + 1])), dtype=\"datetime64[D]\")\n\nemp = pd.read_excel(\"employees.xlsx\")\nbook = pd.read_excel(\"leave_bookings.xlsx\").merge(emp[[\"Employee\", \"Work days\"]], on=\"Employee\")\n\ndef days_in_year(row):\n    start = max(np.datetime64(row[\"From\"].date()), YEAR_START)\n    end = min(np.datetime64(row[\"To\"].date()) + np.timedelta64(1, \"D\"), YEAR_END)   # busday_count excludes the end\n    if start >= end:\n        return 0.0\n    days = np.busday_count(start, end, weekmask=row[\"Work days\"], holidays=BANK_HOLIDAYS)\n    return 0.5 if row[\"Half day\"] and days == 1 else float(days)\n\nbook[\"Days\"] = book.apply(days_in_year, axis=1)\nbook[\"Taken\"] = np.where(book[\"To\"] \u003C pd.Timestamp(\"2026-10-02\"), \"taken\", \"booked\")\nprint(book[[\"Employee\", \"From\", \"To\", \"Work days\", \"Days\", \"Taken\"]].head(8).to_string(index=False))\n","python",[32,88,89,98,112,125,132,145,204,269,274,290,326,331,344,368,413,428,437,468,509,514,539,579],{"__ignoreMap":30},[35,90,91,95],{"class":37,"line":38},[35,92,94],{"class":93},"s-kum","import",[35,96,58],{"class":97},"skGVy",[35,99,101,103,106,109],{"class":37,"line":100},2,[35,102,94],{"class":93},[35,104,105],{"class":97}," numpy ",[35,107,108],{"class":93},"as",[35,110,111],{"class":97}," np\n",[35,113,115,117,120,122],{"class":37,"line":114},3,[35,116,94],{"class":93},[35,118,119],{"class":97}," pandas ",[35,121,108],{"class":93},[35,123,124],{"class":97}," pd\n",[35,126,128],{"class":37,"line":127},4,[35,129,131],{"emptyLinePlaceholder":130},true,"\n",[35,133,135,139,142],{"class":37,"line":134},5,[35,136,138],{"class":137},"sP0c6","YEAR",[35,140,141],{"class":93}," =",[35,143,144],{"class":137}," 2026\n",[35,146,148,151,154,157,159,162,165,168,172,174,177,180,183,185,187,189,191,194,197,199,201],{"class":37,"line":147},6,[35,149,150],{"class":137},"YEAR_START",[35,152,153],{"class":97},", ",[35,155,156],{"class":137},"YEAR_END",[35,158,141],{"class":93},[35,160,161],{"class":97}," np.datetime64(",[35,163,164],{"class":93},"f",[35,166,167],{"class":45},"\"",[35,169,171],{"class":170},"sSjpA","{",[35,173,138],{"class":137},[35,175,176],{"class":170},"}",[35,178,179],{"class":45},"-01-01\"",[35,181,182],{"class":97},"), np.datetime64(",[35,184,164],{"class":93},[35,186,167],{"class":45},[35,188,171],{"class":170},[35,190,138],{"class":137},[35,192,193],{"class":93}," +",[35,195,196],{"class":137}," 1",[35,198,176],{"class":170},[35,200,179],{"class":45},[35,202,203],{"class":97},")\n",[35,205,207,210,212,215,218,221,224,226,230,233,236,238,241,243,246,248,250,252,254,256,259,262,264,267],{"class":37,"line":206},7,[35,208,209],{"class":137},"BANK_HOLIDAYS",[35,211,141],{"class":93},[35,213,214],{"class":97}," np.array(",[35,216,217],{"class":137},"sorted",[35,219,220],{"class":97},"(holidays.country_holidays(",[35,222,223],{"class":45},"\"GB\"",[35,225,153],{"class":97},[35,227,229],{"class":228},"sa561","subdiv",[35,231,232],{"class":93},"=",[35,234,235],{"class":45},"\"ENG\"",[35,237,153],{"class":97},[35,239,240],{"class":228},"years",[35,242,232],{"class":93},[35,244,245],{"class":97},"[",[35,247,138],{"class":137},[35,249,153],{"class":97},[35,251,138],{"class":137},[35,253,193],{"class":93},[35,255,196],{"class":137},[35,257,258],{"class":97},"])), ",[35,260,261],{"class":228},"dtype",[35,263,232],{"class":93},[35,265,266],{"class":45},"\"datetime64[D]\"",[35,268,203],{"class":97},[35,270,272],{"class":37,"line":271},8,[35,273,131],{"emptyLinePlaceholder":130},[35,275,277,280,282,285,288],{"class":37,"line":276},9,[35,278,279],{"class":97},"emp ",[35,281,232],{"class":93},[35,283,284],{"class":97}," pd.read_excel(",[35,286,287],{"class":45},"\"employees.xlsx\"",[35,289,203],{"class":97},[35,291,293,296,298,300,303,306,309,311,314,317,320,322,324],{"class":37,"line":292},10,[35,294,295],{"class":97},"book ",[35,297,232],{"class":93},[35,299,284],{"class":97},[35,301,302],{"class":45},"\"leave_bookings.xlsx\"",[35,304,305],{"class":97},").merge(emp[[",[35,307,308],{"class":45},"\"Employee\"",[35,310,153],{"class":97},[35,312,313],{"class":45},"\"Work days\"",[35,315,316],{"class":97},"]], ",[35,318,319],{"class":228},"on",[35,321,232],{"class":93},[35,323,308],{"class":45},[35,325,203],{"class":97},[35,327,329],{"class":37,"line":328},11,[35,330,131],{"emptyLinePlaceholder":130},[35,332,334,337,341],{"class":37,"line":333},12,[35,335,336],{"class":93},"def",[35,338,340],{"class":339},"s_Opv"," days_in_year",[35,342,343],{"class":97},"(row):\n",[35,345,347,350,352,355,358,361,364,366],{"class":37,"line":346},13,[35,348,349],{"class":97},"    start ",[35,351,232],{"class":93},[35,353,354],{"class":137}," max",[35,356,357],{"class":97},"(np.datetime64(row[",[35,359,360],{"class":45},"\"From\"",[35,362,363],{"class":97},"].date()), ",[35,365,150],{"class":137},[35,367,203],{"class":97},[35,369,371,374,376,379,381,384,387,390,393,396,398,401,404,406,409],{"class":37,"line":370},14,[35,372,373],{"class":97},"    end ",[35,375,232],{"class":93},[35,377,378],{"class":137}," min",[35,380,357],{"class":97},[35,382,383],{"class":45},"\"To\"",[35,385,386],{"class":97},"].date()) ",[35,388,389],{"class":93},"+",[35,391,392],{"class":97}," np.timedelta64(",[35,394,395],{"class":137},"1",[35,397,153],{"class":97},[35,399,400],{"class":45},"\"D\"",[35,402,403],{"class":97},"), ",[35,405,156],{"class":137},[35,407,408],{"class":97},")   ",[35,410,412],{"class":411},"s-wDw","# busday_count excludes the end\n",[35,414,416,419,422,425],{"class":37,"line":415},15,[35,417,418],{"class":93},"    if",[35,420,421],{"class":97}," start ",[35,423,424],{"class":93},">=",[35,426,427],{"class":97}," end:\n",[35,429,431,434],{"class":37,"line":430},16,[35,432,433],{"class":93},"        return",[35,435,436],{"class":137}," 0.0\n",[35,438,440,443,445,448,450,452,455,457,460,462,464,466],{"class":37,"line":439},17,[35,441,442],{"class":97},"    days ",[35,444,232],{"class":93},[35,446,447],{"class":97}," np.busday_count(start, end, ",[35,449,80],{"class":228},[35,451,232],{"class":93},[35,453,454],{"class":97},"row[",[35,456,313],{"class":45},[35,458,459],{"class":97},"], ",[35,461,64],{"class":228},[35,463,232],{"class":93},[35,465,209],{"class":137},[35,467,203],{"class":97},[35,469,471,474,477,480,483,486,489,492,495,498,500,503,506],{"class":37,"line":470},18,[35,472,473],{"class":93},"    return",[35,475,476],{"class":137}," 0.5",[35,478,479],{"class":93}," if",[35,481,482],{"class":97}," row[",[35,484,485],{"class":45},"\"Half day\"",[35,487,488],{"class":97},"] ",[35,490,491],{"class":93},"and",[35,493,494],{"class":97}," days ",[35,496,497],{"class":93},"==",[35,499,196],{"class":137},[35,501,502],{"class":93}," else",[35,504,505],{"class":137}," float",[35,507,508],{"class":97},"(days)\n",[35,510,512],{"class":37,"line":511},19,[35,513,131],{"emptyLinePlaceholder":130},[35,515,517,520,523,525,527,530,533,535,537],{"class":37,"line":516},20,[35,518,519],{"class":97},"book[",[35,521,522],{"class":45},"\"Days\"",[35,524,488],{"class":97},[35,526,232],{"class":93},[35,528,529],{"class":97}," book.apply(days_in_year, ",[35,531,532],{"class":228},"axis",[35,534,232],{"class":93},[35,536,395],{"class":137},[35,538,203],{"class":97},[35,540,542,544,547,549,551,554,556,558,561,564,567,569,572,574,577],{"class":37,"line":541},21,[35,543,519],{"class":97},[35,545,546],{"class":45},"\"Taken\"",[35,548,488],{"class":97},[35,550,232],{"class":93},[35,552,553],{"class":97}," np.where(book[",[35,555,383],{"class":45},[35,557,488],{"class":97},[35,559,560],{"class":93},"\u003C",[35,562,563],{"class":97}," pd.Timestamp(",[35,565,566],{"class":45},"\"2026-10-02\"",[35,568,403],{"class":97},[35,570,571],{"class":45},"\"taken\"",[35,573,153],{"class":97},[35,575,576],{"class":45},"\"booked\"",[35,578,203],{"class":97},[35,580,582,585,588,590,592,594,596,598,600,602,604,606,608,610,613,616,619,622,624,627],{"class":37,"line":581},22,[35,583,584],{"class":137},"print",[35,586,587],{"class":97},"(book[[",[35,589,308],{"class":45},[35,591,153],{"class":97},[35,593,360],{"class":45},[35,595,153],{"class":97},[35,597,383],{"class":45},[35,599,153],{"class":97},[35,601,313],{"class":45},[35,603,153],{"class":97},[35,605,522],{"class":45},[35,607,153],{"class":97},[35,609,546],{"class":45},[35,611,612],{"class":97},"]].head(",[35,614,615],{"class":137},"8",[35,617,618],{"class":97},").to_string(",[35,620,621],{"class":228},"index",[35,623,232],{"class":93},[35,625,626],{"class":137},"False",[35,628,629],{"class":97},"))\n",[10,631,632,633,635,636,639,640,18],{},"Clipping each booking to the leave year handles bookings that span the year end: Amira's leave from 21 December to 4 January counts only its 2026 working days this year — Christmas Day and the substitute Boxing Day holiday on Monday 28 December are skipped, so it costs her 7 days in 2026 rather than 9 — and the rest falls into next year's report. Chloe's booking from 30 March to 8 April would cost a full-timer 6 days, with Good Friday and Easter Monday skipped; she works Monday to Wednesday, so it costs her 5. ",[32,634,75],{}," treats its end date as exclusive, hence the extra day added to it. A half-day booking counts 0.5. Bookings whose last day is before the report date are ",[78,637,638],{},"taken","; the rest are ",[78,641,642],{},"booked",[644,645,653,654,653,658,653,662,653,670,653,679,653,683,653,690,653,694,653,698,653,702,653,706,653,708,653,712,653,714,653,717,653,720,653,724,653,726,653,730,653,732,653,735,653,738,653,742,653,744,653,746,653,748,653,751,653,754,653,758,653,761,653,765,653,768,653,770,653,773,653,775,653,778,653,780,653,783,653,785,653,787,653,789,653,792,653,794,653,797,653,799,653,801,653,803,653,806,653,811,653,815,653,821,653,825,653,832,653,837,653,845],"svg",{"viewBox":646,"role":647,"ariaLabelledBy":648,"xmlns":651,"style":652},"40 0 679 164","img",[649,650],"lv-count-t","lv-count-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:679px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[655,656,657],"title",{"id":649},"The same week, counted for two people",[659,660,661],"desc",{"id":650},"A booking from Monday 30 March to Wednesday 8 April. For a full-time employee it is six working days, because Good Friday and Easter Monday are public holidays. For Chloe, who works Monday to Wednesday, it is five days.",[663,664],"rect",{"x":665,"y":666,"width":667,"height":668,"fill":669},"40","0","679","164","#ffffff",[663,671],{"x":672,"y":673,"width":674,"height":675,"rx":666,"fill":676,"stroke":677,"style":678},"56.8","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[663,680],{"x":681,"y":673,"width":682,"height":675,"rx":666,"fill":676,"stroke":677,"style":678},"88.8","113.7",[684,685,689],"text",{"x":686,"y":687,"style":688},"145.7","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[663,691],{"x":692,"y":673,"width":693,"height":675,"rx":666,"fill":676,"stroke":677,"style":678},"202.6","109.6",[684,695,697],{"x":696,"y":687,"style":688},"257.4","B",[663,699],{"x":672,"y":700,"width":674,"height":701,"rx":666,"fill":676,"stroke":677,"style":678},"64.0","28.0",[684,703,395],{"x":704,"y":705,"style":688},"72.8","83.0",[663,707],{"x":681,"y":700,"width":682,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,709,711],{"x":686,"y":705,"style":710},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Booking",[663,713],{"x":692,"y":700,"width":693,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,715,716],{"x":696,"y":705,"style":710},"Pattern",[663,718],{"x":672,"y":719,"width":674,"height":701,"rx":666,"fill":676,"stroke":677,"style":678},"92.0",[684,721,723],{"x":704,"y":722,"style":688},"111.0","2",[663,725],{"x":681,"y":719,"width":682,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,727,729],{"x":686,"y":722,"style":728},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","30 Mar – 8 Apr",[663,731],{"x":692,"y":719,"width":693,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,733,734],{"x":696,"y":722,"style":728},"Mon–Fri",[663,736],{"x":672,"y":737,"width":674,"height":701,"rx":666,"fill":676,"stroke":677,"style":678},"120.0",[684,739,741],{"x":704,"y":740,"style":688},"139.0","3",[663,743],{"x":681,"y":737,"width":682,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,745,729],{"x":686,"y":740,"style":728},[663,747],{"x":692,"y":737,"width":693,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,749,750],{"x":696,"y":740,"style":728},"Mon Tue Wed",[663,752],{"x":753,"y":673,"width":674,"height":675,"rx":666,"fill":676,"stroke":677,"style":678},"486.2",[663,755],{"x":756,"y":673,"width":757,"height":675,"rx":666,"fill":676,"stroke":677,"style":678},"518.2","130.0",[684,759,689],{"x":760,"y":687,"style":688},"583.2",[663,762],{"x":763,"y":673,"width":764,"height":675,"rx":666,"fill":676,"stroke":677,"style":678},"648.1","55.1",[684,766,697],{"x":767,"y":687,"style":688},"675.7",[663,769],{"x":753,"y":700,"width":674,"height":701,"rx":666,"fill":676,"stroke":677,"style":678},[684,771,395],{"x":772,"y":705,"style":688},"502.2",[663,774],{"x":756,"y":700,"width":757,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,776,777],{"x":760,"y":705,"style":710},"Holidays skipped",[663,779],{"x":763,"y":700,"width":764,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,781,782],{"x":767,"y":705,"style":710},"Days",[663,784],{"x":753,"y":719,"width":674,"height":701,"rx":666,"fill":676,"stroke":677,"style":678},[684,786,723],{"x":772,"y":722,"style":688},[663,788],{"x":756,"y":719,"width":757,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,790,791],{"x":760,"y":722,"style":728},"3 Apr, 6 Apr",[663,793],{"x":763,"y":719,"width":764,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,795,796],{"x":767,"y":722,"style":728},"6",[663,798],{"x":753,"y":737,"width":674,"height":701,"rx":666,"fill":676,"stroke":677,"style":678},[684,800,741],{"x":772,"y":740,"style":688},[663,802],{"x":756,"y":737,"width":757,"height":701,"rx":666,"fill":669,"stroke":677,"style":678},[684,804,805],{"x":760,"y":740,"style":728},"6 Apr",[663,807],{"x":763,"y":737,"width":764,"height":701,"rx":666,"fill":808,"stroke":809,"style":810},"#d9f4f1","var(--teal,#0f9488)","stroke-width:1.5px",[684,812,814],{"x":767,"y":740,"style":813},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","5",[684,816,820],{"x":817,"y":818,"style":819},"184.5","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","before",[684,822,824],{"x":823,"y":818,"style":819},"594.7","after",[37,826],{"x1":827,"y1":828,"x2":829,"y2":828,"stroke":830,"style":831},"322.1","94.0","472.2","var(--brand,#5b5cf0)","stroke-width:2px",[833,834],"polygon",{"points":835,"fill":836},"476.2,94.0 467.2,99.0 467.2,89.0","#5b5cf0",[663,838],{"x":839,"y":840,"width":841,"height":842,"rx":843,"fill":669,"stroke":677,"style":844},"345.5","61.0","107.2","22.0","11","stroke-width:1.2px",[684,846,75],{"x":847,"y":848,"style":849},"399.2","76.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",[20,851,853],{"id":852},"step-2-pro-rata-entitlement-and-carry-over","Step 2 — Pro-rata entitlement and carry-over",[10,855,856],{},"Entitlement depends on how much of the year someone is employed and how many days a week they work. Carried-over days often expire part-way through the year if not used:",[25,858,860],{"className":84,"code":859,"language":86,"meta":30,"style":30},"CARRY_EXPIRY = pd.Timestamp(f\"{YEAR}-03-31\")\n\ndef entitlement(row):\n    start = max(row[\"Start date\"], pd.Timestamp(f\"{YEAR}-01-01\"))\n    end = min(row[\"End date\"] if pd.notna(row[\"End date\"]) else pd.Timestamp(f\"{YEAR}-12-31\"), pd.Timestamp(f\"{YEAR}-12-31\"))\n    year_fraction = ((end - start).days + 1) \u002F 365\n    fte = len(row[\"Work days\"].split()) \u002F 5\n    return round(row[\"Full-time entitlement\"] * fte * year_fraction * 2) \u002F 2      # to the nearest half day\n\nemp[\"Entitlement\"] = emp.apply(entitlement, axis=1)\nused_by_expiry = (book[book[\"From\"] \u003C= CARRY_EXPIRY].groupby(\"Employee\")[\"Days\"].sum()\n                  .reindex(emp[\"Employee\"], fill_value=0).values)\nemp[\"Carry-over used\"] = np.minimum(emp[\"Carried over\"], used_by_expiry)\nemp[\"Carry-over lost\"] = emp[\"Carried over\"] - emp[\"Carry-over used\"]\nprint(emp[[\"Name\", \"Work days\", \"Entitlement\", \"Carried over\", \"Carry-over used\", \"Carry-over lost\"]].to_string(index=False))\n",[32,861,862,886,890,899,930,991,1020,1042,1081,1085,1108,1141,1160,1180,1207],{"__ignoreMap":30},[35,863,864,867,869,871,873,875,877,879,881,884],{"class":37,"line":38},[35,865,866],{"class":137},"CARRY_EXPIRY",[35,868,141],{"class":93},[35,870,563],{"class":97},[35,872,164],{"class":93},[35,874,167],{"class":45},[35,876,171],{"class":170},[35,878,138],{"class":137},[35,880,176],{"class":170},[35,882,883],{"class":45},"-03-31\"",[35,885,203],{"class":97},[35,887,888],{"class":37,"line":100},[35,889,131],{"emptyLinePlaceholder":130},[35,891,892,894,897],{"class":37,"line":114},[35,893,336],{"class":93},[35,895,896],{"class":339}," entitlement",[35,898,343],{"class":97},[35,900,901,903,905,907,910,913,916,918,920,922,924,926,928],{"class":37,"line":127},[35,902,349],{"class":97},[35,904,232],{"class":93},[35,906,354],{"class":137},[35,908,909],{"class":97},"(row[",[35,911,912],{"class":45},"\"Start date\"",[35,914,915],{"class":97},"], pd.Timestamp(",[35,917,164],{"class":93},[35,919,167],{"class":45},[35,921,171],{"class":170},[35,923,138],{"class":137},[35,925,176],{"class":170},[35,927,179],{"class":45},[35,929,629],{"class":97},[35,931,932,934,936,938,940,943,945,948,951,953,956,959,961,963,965,967,969,971,974,977,979,981,983,985,987,989],{"class":37,"line":134},[35,933,373],{"class":97},[35,935,232],{"class":93},[35,937,378],{"class":137},[35,939,909],{"class":97},[35,941,942],{"class":45},"\"End date\"",[35,944,488],{"class":97},[35,946,947],{"class":93},"if",[35,949,950],{"class":97}," pd.notna(row[",[35,952,942],{"class":45},[35,954,955],{"class":97},"]) ",[35,957,958],{"class":93},"else",[35,960,563],{"class":97},[35,962,164],{"class":93},[35,964,167],{"class":45},[35,966,171],{"class":170},[35,968,138],{"class":137},[35,970,176],{"class":170},[35,972,973],{"class":45},"-12-31\"",[35,975,976],{"class":97},"), pd.Timestamp(",[35,978,164],{"class":93},[35,980,167],{"class":45},[35,982,171],{"class":170},[35,984,138],{"class":137},[35,986,176],{"class":170},[35,988,973],{"class":45},[35,990,629],{"class":97},[35,992,993,996,998,1001,1004,1007,1009,1011,1014,1017],{"class":37,"line":147},[35,994,995],{"class":97},"    year_fraction ",[35,997,232],{"class":93},[35,999,1000],{"class":97}," ((end ",[35,1002,1003],{"class":93},"-",[35,1005,1006],{"class":97}," start).days ",[35,1008,389],{"class":93},[35,1010,196],{"class":137},[35,1012,1013],{"class":97},") ",[35,1015,1016],{"class":93},"\u002F",[35,1018,1019],{"class":137}," 365\n",[35,1021,1022,1025,1027,1030,1032,1034,1037,1039],{"class":37,"line":206},[35,1023,1024],{"class":97},"    fte ",[35,1026,232],{"class":93},[35,1028,1029],{"class":137}," len",[35,1031,909],{"class":97},[35,1033,313],{"class":45},[35,1035,1036],{"class":97},"].split()) ",[35,1038,1016],{"class":93},[35,1040,1041],{"class":137}," 5\n",[35,1043,1044,1046,1049,1051,1054,1056,1059,1062,1064,1067,1069,1072,1074,1076,1078],{"class":37,"line":271},[35,1045,473],{"class":93},[35,1047,1048],{"class":137}," round",[35,1050,909],{"class":97},[35,1052,1053],{"class":45},"\"Full-time entitlement\"",[35,1055,488],{"class":97},[35,1057,1058],{"class":93},"*",[35,1060,1061],{"class":97}," fte ",[35,1063,1058],{"class":93},[35,1065,1066],{"class":97}," year_fraction ",[35,1068,1058],{"class":93},[35,1070,1071],{"class":137}," 2",[35,1073,1013],{"class":97},[35,1075,1016],{"class":93},[35,1077,1071],{"class":137},[35,1079,1080],{"class":411},"      # to the nearest half day\n",[35,1082,1083],{"class":37,"line":276},[35,1084,131],{"emptyLinePlaceholder":130},[35,1086,1087,1090,1093,1095,1097,1100,1102,1104,1106],{"class":37,"line":292},[35,1088,1089],{"class":97},"emp[",[35,1091,1092],{"class":45},"\"Entitlement\"",[35,1094,488],{"class":97},[35,1096,232],{"class":93},[35,1098,1099],{"class":97}," emp.apply(entitlement, ",[35,1101,532],{"class":228},[35,1103,232],{"class":93},[35,1105,395],{"class":137},[35,1107,203],{"class":97},[35,1109,1110,1113,1115,1118,1120,1122,1125,1128,1131,1133,1136,1138],{"class":37,"line":328},[35,1111,1112],{"class":97},"used_by_expiry ",[35,1114,232],{"class":93},[35,1116,1117],{"class":97}," (book[book[",[35,1119,360],{"class":45},[35,1121,488],{"class":97},[35,1123,1124],{"class":93},"\u003C=",[35,1126,1127],{"class":137}," CARRY_EXPIRY",[35,1129,1130],{"class":97},"].groupby(",[35,1132,308],{"class":45},[35,1134,1135],{"class":97},")[",[35,1137,522],{"class":45},[35,1139,1140],{"class":97},"].sum()\n",[35,1142,1143,1146,1148,1150,1153,1155,1157],{"class":37,"line":333},[35,1144,1145],{"class":97},"                  .reindex(emp[",[35,1147,308],{"class":45},[35,1149,459],{"class":97},[35,1151,1152],{"class":228},"fill_value",[35,1154,232],{"class":93},[35,1156,666],{"class":137},[35,1158,1159],{"class":97},").values)\n",[35,1161,1162,1164,1167,1169,1171,1174,1177],{"class":37,"line":346},[35,1163,1089],{"class":97},[35,1165,1166],{"class":45},"\"Carry-over used\"",[35,1168,488],{"class":97},[35,1170,232],{"class":93},[35,1172,1173],{"class":97}," np.minimum(emp[",[35,1175,1176],{"class":45},"\"Carried over\"",[35,1178,1179],{"class":97},"], used_by_expiry)\n",[35,1181,1182,1184,1187,1189,1191,1194,1196,1198,1200,1202,1204],{"class":37,"line":370},[35,1183,1089],{"class":97},[35,1185,1186],{"class":45},"\"Carry-over lost\"",[35,1188,488],{"class":97},[35,1190,232],{"class":93},[35,1192,1193],{"class":97}," emp[",[35,1195,1176],{"class":45},[35,1197,488],{"class":97},[35,1199,1003],{"class":93},[35,1201,1193],{"class":97},[35,1203,1166],{"class":45},[35,1205,1206],{"class":97},"]\n",[35,1208,1209,1211,1214,1217,1219,1221,1223,1225,1227,1229,1231,1233,1235,1237,1240,1242,1244,1246],{"class":37,"line":415},[35,1210,584],{"class":137},[35,1212,1213],{"class":97},"(emp[[",[35,1215,1216],{"class":45},"\"Name\"",[35,1218,153],{"class":97},[35,1220,313],{"class":45},[35,1222,153],{"class":97},[35,1224,1092],{"class":45},[35,1226,153],{"class":97},[35,1228,1176],{"class":45},[35,1230,153],{"class":97},[35,1232,1166],{"class":45},[35,1234,153],{"class":97},[35,1236,1186],{"class":45},[35,1238,1239],{"class":97},"]].to_string(",[35,1241,621],{"class":228},[35,1243,232],{"class":93},[35,1245,626],{"class":137},[35,1247,629],{"class":97},[10,1249,1250],{},"Ben started on 15 June, so he gets 200 days' worth of a 25-day year — 13.5 days rounded to the nearest half day. Chloe works three days a week, so her 25-day full-time entitlement becomes 15. Elena left on 31 August, so her entitlement is cut to the part of the year she worked, which matters when her final pay settles any untaken or overtaken leave. Carried-over days count only if used by 31 March; Farid used 5 days in January and keeps all 4 carried-over days, while Dev took his first leave in March and used all 5. Your own rounding and carry-over rules may differ; keep them in these two small functions where they are easy to find and change.",[20,1252,1254],{"id":1253},"step-3-balances-and-flags","Step 3 — Balances and flags",[25,1256,1258],{"className":84,"code":1257,"language":86,"meta":30,"style":30},"days = book.pivot_table(index=\"Employee\", columns=\"Taken\", values=\"Days\", aggfunc=\"sum\", fill_value=0)\nreport = emp.set_index(\"Employee\").join(days).fillna({\"taken\": 0, \"booked\": 0})\nreport[\"Available\"] = report[\"Entitlement\"] + report[\"Carry-over used\"]\nreport[\"Remaining\"] = report[\"Available\"] - report[\"taken\"] - report[\"booked\"]\nleft_in_year = np.busday_count(np.datetime64(\"2026-10-02\"), YEAR_END, holidays=BANK_HOLIDAYS)\n\ndef flag(r):\n    if r[\"Remaining\"] \u003C 0:\n        return \"over-booked\"\n    if pd.isna(r[\"End date\"]) and r[\"Remaining\"] >= 10:\n        return f\"{r['Remaining']:g} days unbooked with {left_in_year} working days left\"\n    return \"\"\n\nreport[\"Flag\"] = report.apply(flag, axis=1)\ncols = [\"Name\", \"Team\", \"Available\", \"taken\", \"booked\", \"Remaining\", \"Flag\"]\nprint(report[cols].to_string())\n",[32,1259,1260,1314,1347,1374,1407,1433,1437,1447,1466,1473,1499,1537,1544,1548,1570,1609],{"__ignoreMap":30},[35,1261,1262,1265,1267,1270,1272,1274,1276,1278,1281,1283,1285,1287,1290,1292,1294,1296,1299,1301,1304,1306,1308,1310,1312],{"class":37,"line":38},[35,1263,1264],{"class":97},"days ",[35,1266,232],{"class":93},[35,1268,1269],{"class":97}," book.pivot_table(",[35,1271,621],{"class":228},[35,1273,232],{"class":93},[35,1275,308],{"class":45},[35,1277,153],{"class":97},[35,1279,1280],{"class":228},"columns",[35,1282,232],{"class":93},[35,1284,546],{"class":45},[35,1286,153],{"class":97},[35,1288,1289],{"class":228},"values",[35,1291,232],{"class":93},[35,1293,522],{"class":45},[35,1295,153],{"class":97},[35,1297,1298],{"class":228},"aggfunc",[35,1300,232],{"class":93},[35,1302,1303],{"class":45},"\"sum\"",[35,1305,153],{"class":97},[35,1307,1152],{"class":228},[35,1309,232],{"class":93},[35,1311,666],{"class":137},[35,1313,203],{"class":97},[35,1315,1316,1319,1321,1324,1326,1329,1331,1334,1336,1338,1340,1342,1344],{"class":37,"line":100},[35,1317,1318],{"class":97},"report ",[35,1320,232],{"class":93},[35,1322,1323],{"class":97}," emp.set_index(",[35,1325,308],{"class":45},[35,1327,1328],{"class":97},").join(days).fillna({",[35,1330,571],{"class":45},[35,1332,1333],{"class":97},": ",[35,1335,666],{"class":137},[35,1337,153],{"class":97},[35,1339,576],{"class":45},[35,1341,1333],{"class":97},[35,1343,666],{"class":137},[35,1345,1346],{"class":97},"})\n",[35,1348,1349,1352,1355,1357,1359,1362,1364,1366,1368,1370,1372],{"class":37,"line":114},[35,1350,1351],{"class":97},"report[",[35,1353,1354],{"class":45},"\"Available\"",[35,1356,488],{"class":97},[35,1358,232],{"class":93},[35,1360,1361],{"class":97}," report[",[35,1363,1092],{"class":45},[35,1365,488],{"class":97},[35,1367,389],{"class":93},[35,1369,1361],{"class":97},[35,1371,1166],{"class":45},[35,1373,1206],{"class":97},[35,1375,1376,1378,1381,1383,1385,1387,1389,1391,1393,1395,1397,1399,1401,1403,1405],{"class":37,"line":127},[35,1377,1351],{"class":97},[35,1379,1380],{"class":45},"\"Remaining\"",[35,1382,488],{"class":97},[35,1384,232],{"class":93},[35,1386,1361],{"class":97},[35,1388,1354],{"class":45},[35,1390,488],{"class":97},[35,1392,1003],{"class":93},[35,1394,1361],{"class":97},[35,1396,571],{"class":45},[35,1398,488],{"class":97},[35,1400,1003],{"class":93},[35,1402,1361],{"class":97},[35,1404,576],{"class":45},[35,1406,1206],{"class":97},[35,1408,1409,1412,1414,1417,1419,1421,1423,1425,1427,1429,1431],{"class":37,"line":134},[35,1410,1411],{"class":97},"left_in_year ",[35,1413,232],{"class":93},[35,1415,1416],{"class":97}," np.busday_count(np.datetime64(",[35,1418,566],{"class":45},[35,1420,403],{"class":97},[35,1422,156],{"class":137},[35,1424,153],{"class":97},[35,1426,64],{"class":228},[35,1428,232],{"class":93},[35,1430,209],{"class":137},[35,1432,203],{"class":97},[35,1434,1435],{"class":37,"line":147},[35,1436,131],{"emptyLinePlaceholder":130},[35,1438,1439,1441,1444],{"class":37,"line":206},[35,1440,336],{"class":93},[35,1442,1443],{"class":339}," flag",[35,1445,1446],{"class":97},"(r):\n",[35,1448,1449,1451,1454,1456,1458,1460,1463],{"class":37,"line":271},[35,1450,418],{"class":93},[35,1452,1453],{"class":97}," r[",[35,1455,1380],{"class":45},[35,1457,488],{"class":97},[35,1459,560],{"class":93},[35,1461,1462],{"class":137}," 0",[35,1464,1465],{"class":97},":\n",[35,1467,1468,1470],{"class":37,"line":276},[35,1469,433],{"class":93},[35,1471,1472],{"class":45}," \"over-booked\"\n",[35,1474,1475,1477,1480,1482,1484,1486,1488,1490,1492,1494,1497],{"class":37,"line":292},[35,1476,418],{"class":93},[35,1478,1479],{"class":97}," pd.isna(r[",[35,1481,942],{"class":45},[35,1483,955],{"class":97},[35,1485,491],{"class":93},[35,1487,1453],{"class":97},[35,1489,1380],{"class":45},[35,1491,488],{"class":97},[35,1493,424],{"class":93},[35,1495,1496],{"class":137}," 10",[35,1498,1465],{"class":97},[35,1500,1501,1503,1506,1508,1510,1513,1516,1519,1522,1524,1527,1529,1532,1534],{"class":37,"line":328},[35,1502,433],{"class":93},[35,1504,1505],{"class":93}," f",[35,1507,167],{"class":45},[35,1509,171],{"class":170},[35,1511,1512],{"class":97},"r[",[35,1514,1515],{"class":45},"'Remaining'",[35,1517,1518],{"class":97},"]",[35,1520,1521],{"class":93},":g",[35,1523,176],{"class":170},[35,1525,1526],{"class":45}," days unbooked with ",[35,1528,171],{"class":170},[35,1530,1531],{"class":97},"left_in_year",[35,1533,176],{"class":170},[35,1535,1536],{"class":45}," working days left\"\n",[35,1538,1539,1541],{"class":37,"line":333},[35,1540,473],{"class":93},[35,1542,1543],{"class":45}," \"\"\n",[35,1545,1546],{"class":37,"line":346},[35,1547,131],{"emptyLinePlaceholder":130},[35,1549,1550,1552,1555,1557,1559,1562,1564,1566,1568],{"class":37,"line":370},[35,1551,1351],{"class":97},[35,1553,1554],{"class":45},"\"Flag\"",[35,1556,488],{"class":97},[35,1558,232],{"class":93},[35,1560,1561],{"class":97}," report.apply(flag, ",[35,1563,532],{"class":228},[35,1565,232],{"class":93},[35,1567,395],{"class":137},[35,1569,203],{"class":97},[35,1571,1572,1575,1577,1580,1582,1584,1587,1589,1591,1593,1595,1597,1599,1601,1603,1605,1607],{"class":37,"line":415},[35,1573,1574],{"class":97},"cols ",[35,1576,232],{"class":93},[35,1578,1579],{"class":97}," [",[35,1581,1216],{"class":45},[35,1583,153],{"class":97},[35,1585,1586],{"class":45},"\"Team\"",[35,1588,153],{"class":97},[35,1590,1354],{"class":45},[35,1592,153],{"class":97},[35,1594,571],{"class":45},[35,1596,153],{"class":97},[35,1598,576],{"class":45},[35,1600,153],{"class":97},[35,1602,1380],{"class":45},[35,1604,153],{"class":97},[35,1606,1554],{"class":45},[35,1608,1206],{"class":97},[35,1610,1611,1613],{"class":37,"line":430},[35,1612,584],{"class":137},[35,1614,1615],{"class":97},"(report[cols].to_string())\n",[10,1617,1618,1619,1622,1623,1626],{},"Remaining balance is entitlement plus usable carry-over, less leave taken and leave already booked for later in the year. Two kinds of balance need someone's attention. A ",[78,1620,1621],{},"negative"," balance means more leave was taken or booked than allowed — Elena, who left at the end of August having taken more than her pro-rated entitlement, is the classic case, and payroll needs to know before her final pay. Farid is the other case: his December booking was approved although it took him six days past his allowance, which suggests bookings are approved without the balance in front of the approver — a process point the report makes visible. A ",[78,1624,1625],{},"large"," unbooked balance late in the year means either a rush of leave in December or days that will be lost, both of which managers would rather know about now.",[644,1628,653,1634,653,1637,653,1640,653,1645,653,1653,653,1659,653,1663,653,1667,653,1670,653,1672,653,1677,653,1681,653,1685,653,1688,653,1691,653,1696,653,1700,653,1704,653,1707,653,1710,653,1714,653,1718,653,1722,653,1725,653,1730,653,1735],{"viewBox":1629,"role":647,"ariaLabelledBy":1630,"xmlns":651,"style":1633},"84 0 592 471",[1631,1632],"lv-balance-t","lv-balance-d","width:100%;max-width:592px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[655,1635,1636],{"id":1631},"How a remaining balance is built",[659,1638,1639],{"id":1632},"Pro-rata entitlement plus carry-over used before it expired gives the leave available. Subtract days already taken and days booked for later in the year to get the remaining balance, which is flagged if negative or still large late in the year.",[663,1641],{"x":1642,"y":666,"width":1643,"height":1644,"fill":669},"84","592","471",[663,1646],{"x":1647,"y":1648,"width":1649,"height":1650,"rx":1651,"fill":1652,"stroke":830,"style":831},"100.0","16.0","560.0","59.0","12","#f0f4ff",[684,1654,1658],{"x":1655,"y":1656,"style":1657},"380.0","41.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Pro-rata entitlement",[684,1660,1662],{"x":1655,"y":840,"style":1661},"font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","employment × work pattern",[37,1664],{"x1":1655,"y1":1665,"x2":1655,"y2":1666,"stroke":830,"style":831},"80.0","102.0",[833,1668],{"points":1669,"fill":836},"380.0,106.0 375.0,97.0 385.0,97.0",[663,1671],{"x":1647,"y":722,"width":1649,"height":1650,"rx":1651,"fill":808,"stroke":809,"style":831},[684,1673,1676],{"x":1655,"y":1674,"style":1675},"136.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","+ carry-over used",[684,1678,1680],{"x":1655,"y":1679,"style":1661},"156.0","by 31 March",[37,1682],{"x1":1655,"y1":1683,"x2":1655,"y2":1684,"stroke":830,"style":831},"175.0","197.0",[833,1686],{"points":1687,"fill":836},"380.0,201.0 375.0,192.0 385.0,192.0",[663,1689],{"x":1647,"y":1690,"width":1649,"height":1650,"rx":1651,"fill":676,"stroke":677,"style":831},"206.0",[684,1692,1695],{"x":1655,"y":1693,"style":1694},"231.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","− taken",[684,1697,1699],{"x":1655,"y":1698,"style":1661},"251.0","bookings before today",[37,1701],{"x1":1655,"y1":1702,"x2":1655,"y2":1703,"stroke":830,"style":831},"270.0","292.0",[833,1705],{"points":1706,"fill":836},"380.0,296.0 375.0,287.0 385.0,287.0",[663,1708],{"x":1647,"y":1709,"width":1649,"height":1650,"rx":1651,"fill":676,"stroke":677,"style":831},"301.0",[684,1711,1713],{"x":1655,"y":1712,"style":1694},"326.5","− booked",[684,1715,1717],{"x":1655,"y":1716,"style":1661},"346.0","future bookings",[37,1719],{"x1":1655,"y1":1720,"x2":1655,"y2":1721,"stroke":830,"style":831},"365.0","387.0",[833,1723],{"points":1724,"fill":836},"380.0,391.0 375.0,382.0 385.0,382.0",[663,1726],{"x":1647,"y":1727,"width":1649,"height":1650,"rx":1651,"fill":1728,"stroke":1729,"style":831},"396.0","#fdefd8","var(--gold,#b4740a)",[684,1731,1734],{"x":1655,"y":1732,"style":1733},"421.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","= remaining",[684,1736,1738],{"x":1655,"y":1737,"style":1661},"441.0","flag if \u003C 0 or ≥ 10 late",[10,1740,1741],{},"Dev, with 17 days still unbooked and only 63 working days left in the year, is the example: unless his carry-over rules allow more than five days into next year, some of that leave will be lost.",[644,1743,653,1749,653,1752,653,1755,653,1760,653,1765,653,1771,653,1775,653,1780,653,1783,653,1787,653,1790,653,1794,653,1797,653,1801,653,1804,653,1807,653,1810,653,1814,653,1817,653,1820,653,1823,653,1827,653,1829,653,1833,653,1836,653,1840,653,1843],{"viewBox":1744,"role":647,"ariaLabelledBy":1745,"xmlns":651,"style":1748},"4 0 697 260",[1746,1747],"lv-remaining-t","lv-remaining-d","width:100%;max-width:697px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[655,1750,1751],{"id":1746},"Remaining leave on 2 October 2026",[659,1753,1754],{"id":1747},"Remaining balances after leave taken and booked. Dev Patel has 17 days left, Ben Okafor 8, Chloe Martin 6 and Amira Haddad 1. Farid Khan is 6 days over and Elena Rossi, who has left, 7.5 days over.",[663,1756],{"x":1757,"y":666,"width":1758,"height":1759,"fill":669},"4","697","260",[663,1761],{"x":1762,"y":1648,"width":1763,"height":701,"rx":1764,"fill":676,"stroke":677,"style":678},"20.0","119.3","7",[684,1766,1770],{"x":1767,"y":1768,"style":1769},"79.6","34.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Dev Patel",[663,1772],{"x":1773,"y":1648,"width":1774,"height":701,"rx":1764,"fill":1728,"stroke":1729,"style":810},"149.3","514.7",[684,1776,1779],{"x":1777,"y":1768,"style":1778},"672.0","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","17",[663,1781],{"x":1762,"y":1782,"width":1763,"height":701,"rx":1764,"fill":676,"stroke":677,"style":678},"56.0",[684,1784,1786],{"x":1767,"y":1785,"style":1769},"74.5","Ben Okafor",[663,1788],{"x":1773,"y":1782,"width":1789,"height":701,"rx":1764,"fill":808,"stroke":809,"style":810},"242.2",[684,1791,615],{"x":1792,"y":1785,"style":1793},"399.5","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start",[663,1795],{"x":1762,"y":1796,"width":1763,"height":701,"rx":1764,"fill":676,"stroke":677,"style":678},"96.0",[684,1798,1800],{"x":1767,"y":1799,"style":1769},"114.5","Chloe Martin",[663,1802],{"x":1773,"y":1796,"width":1803,"height":701,"rx":1764,"fill":808,"stroke":809,"style":810},"181.7",[684,1805,796],{"x":1806,"y":1799,"style":1793},"339.0",[663,1808],{"x":1762,"y":1809,"width":1763,"height":701,"rx":1764,"fill":676,"stroke":677,"style":678},"136.0",[684,1811,1813],{"x":1767,"y":1812,"style":1769},"154.5","Amira Haddad",[663,1815],{"x":1773,"y":1809,"width":1816,"height":701,"rx":1764,"fill":808,"stroke":809,"style":810},"30.3",[684,1818,395],{"x":1819,"y":1812,"style":1793},"187.6",[663,1821],{"x":1762,"y":1822,"width":1763,"height":701,"rx":1764,"fill":676,"stroke":677,"style":678},"176.0",[684,1824,1826],{"x":1767,"y":1825,"style":1769},"194.5","Farid Khan",[663,1828],{"x":1773,"y":1822,"width":1803,"height":701,"rx":1764,"fill":1652,"stroke":830,"style":810},[684,1830,1832],{"x":1806,"y":1825,"style":1831},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","−6",[663,1834],{"x":1762,"y":1835,"width":1763,"height":701,"rx":1764,"fill":676,"stroke":677,"style":678},"216.0",[684,1837,1839],{"x":1767,"y":1838,"style":1769},"234.5","Elena Rossi",[663,1841],{"x":1773,"y":1835,"width":1842,"height":701,"rx":1764,"fill":1652,"stroke":830,"style":810},"227.1",[684,1844,1846],{"x":1845,"y":1838,"style":1831},"384.4","−7.5 (left)",[20,1848,1850],{"id":1849},"step-4-write-the-report","Step 4 — Write the report",[10,1852,1853],{},"Write a summary sheet, one row per person with the flags highlighted, and the bookings behind every figure:",[25,1855,1857],{"className":84,"code":1856,"language":86,"meta":30,"style":30},"from openpyxl import load_workbook\nfrom openpyxl.formatting.rule import FormulaRule\nfrom openpyxl.styles import PatternFill\n\npath = \"leave_balances_2026-10-02.xlsx\"\nout = report.reset_index()[[\"Employee\", \"Name\", \"Team\", \"Entitlement\", \"Carry-over used\", \"Carry-over lost\", \"taken\", \"booked\", \"Remaining\", \"Flag\"]]\nwith pd.ExcelWriter(path, engine=\"openpyxl\", date_format=\"dd mmm yyyy\", datetime_format=\"dd mmm yyyy\") as xw:\n    out.rename(columns={\"taken\": \"Taken\", \"booked\": \"Booked\"}).to_excel(xw, sheet_name=\"Balances\", index=False)\n    book.drop(columns=\"Work days\").to_excel(xw, sheet_name=\"Bookings\", index=False)\n    pd.DataFrame({\"Public holiday\": BANK_HOLIDAYS[(BANK_HOLIDAYS >= YEAR_START) & (BANK_HOLIDAYS \u003C YEAR_END)]}).to_excel(xw, sheet_name=\"Holidays\", index=False)\n\nwb = load_workbook(path)\nws = wb[\"Balances\"]\nn = ws.max_row\nws.conditional_formatting.add(f\"A2:J{n}\", FormulaRule(formula=[\"$I2\u003C0\"], fill=PatternFill(\"solid\", fgColor=\"FFD7D5\")))\nws.conditional_formatting.add(f\"A2:J{n}\", FormulaRule(formula=['AND($I2>=0,$J2\u003C>\"\")'], fill=PatternFill(\"solid\", fgColor=\"FFF4CE\")))\nfor col, width in zip(\"ABCDEFGHIJ\", (10, 16, 12, 12, 15, 15, 8, 8, 11, 44)):\n    ws.column_dimensions[col].width = width\nwb.save(path)\nprint(wb.sheetnames, \"| flagged:\", int((report[\"Flag\"] != \"\").sum()))\n",[32,1858,1859,1872,1884,1896,1900,1910,1961,2003,2050,2081,2140,2144,2154,2168,2178,2236,2284,2352,2362,2367],{"__ignoreMap":30},[35,1860,1861,1864,1867,1869],{"class":37,"line":38},[35,1862,1863],{"class":93},"from",[35,1865,1866],{"class":97}," openpyxl ",[35,1868,94],{"class":93},[35,1870,1871],{"class":97}," load_workbook\n",[35,1873,1874,1876,1879,1881],{"class":37,"line":100},[35,1875,1863],{"class":93},[35,1877,1878],{"class":97}," openpyxl.formatting.rule ",[35,1880,94],{"class":93},[35,1882,1883],{"class":97}," FormulaRule\n",[35,1885,1886,1888,1891,1893],{"class":37,"line":114},[35,1887,1863],{"class":93},[35,1889,1890],{"class":97}," openpyxl.styles ",[35,1892,94],{"class":93},[35,1894,1895],{"class":97}," PatternFill\n",[35,1897,1898],{"class":37,"line":127},[35,1899,131],{"emptyLinePlaceholder":130},[35,1901,1902,1905,1907],{"class":37,"line":134},[35,1903,1904],{"class":97},"path ",[35,1906,232],{"class":93},[35,1908,1909],{"class":45}," \"leave_balances_2026-10-02.xlsx\"\n",[35,1911,1912,1915,1917,1920,1922,1924,1926,1928,1930,1932,1934,1936,1938,1940,1942,1944,1946,1948,1950,1952,1954,1956,1958],{"class":37,"line":147},[35,1913,1914],{"class":97},"out ",[35,1916,232],{"class":93},[35,1918,1919],{"class":97}," report.reset_index()[[",[35,1921,308],{"class":45},[35,1923,153],{"class":97},[35,1925,1216],{"class":45},[35,1927,153],{"class":97},[35,1929,1586],{"class":45},[35,1931,153],{"class":97},[35,1933,1092],{"class":45},[35,1935,153],{"class":97},[35,1937,1166],{"class":45},[35,1939,153],{"class":97},[35,1941,1186],{"class":45},[35,1943,153],{"class":97},[35,1945,571],{"class":45},[35,1947,153],{"class":97},[35,1949,576],{"class":45},[35,1951,153],{"class":97},[35,1953,1380],{"class":45},[35,1955,153],{"class":97},[35,1957,1554],{"class":45},[35,1959,1960],{"class":97},"]]\n",[35,1962,1963,1966,1969,1972,1974,1977,1979,1982,1984,1987,1989,1992,1994,1996,1998,2000],{"class":37,"line":206},[35,1964,1965],{"class":93},"with",[35,1967,1968],{"class":97}," pd.ExcelWriter(path, ",[35,1970,1971],{"class":228},"engine",[35,1973,232],{"class":93},[35,1975,1976],{"class":45},"\"openpyxl\"",[35,1978,153],{"class":97},[35,1980,1981],{"class":228},"date_format",[35,1983,232],{"class":93},[35,1985,1986],{"class":45},"\"dd mmm yyyy\"",[35,1988,153],{"class":97},[35,1990,1991],{"class":228},"datetime_format",[35,1993,232],{"class":93},[35,1995,1986],{"class":45},[35,1997,1013],{"class":97},[35,1999,108],{"class":93},[35,2001,2002],{"class":97}," xw:\n",[35,2004,2005,2008,2010,2012,2014,2016,2018,2020,2022,2024,2026,2029,2032,2035,2037,2040,2042,2044,2046,2048],{"class":37,"line":271},[35,2006,2007],{"class":97},"    out.rename(",[35,2009,1280],{"class":228},[35,2011,232],{"class":93},[35,2013,171],{"class":97},[35,2015,571],{"class":45},[35,2017,1333],{"class":97},[35,2019,546],{"class":45},[35,2021,153],{"class":97},[35,2023,576],{"class":45},[35,2025,1333],{"class":97},[35,2027,2028],{"class":45},"\"Booked\"",[35,2030,2031],{"class":97},"}).to_excel(xw, ",[35,2033,2034],{"class":228},"sheet_name",[35,2036,232],{"class":93},[35,2038,2039],{"class":45},"\"Balances\"",[35,2041,153],{"class":97},[35,2043,621],{"class":228},[35,2045,232],{"class":93},[35,2047,626],{"class":137},[35,2049,203],{"class":97},[35,2051,2052,2055,2057,2059,2061,2064,2066,2068,2071,2073,2075,2077,2079],{"class":37,"line":276},[35,2053,2054],{"class":97},"    book.drop(",[35,2056,1280],{"class":228},[35,2058,232],{"class":93},[35,2060,313],{"class":45},[35,2062,2063],{"class":97},").to_excel(xw, ",[35,2065,2034],{"class":228},[35,2067,232],{"class":93},[35,2069,2070],{"class":45},"\"Bookings\"",[35,2072,153],{"class":97},[35,2074,621],{"class":228},[35,2076,232],{"class":93},[35,2078,626],{"class":137},[35,2080,203],{"class":97},[35,2082,2083,2086,2089,2091,2093,2096,2098,2101,2104,2106,2109,2112,2114,2117,2120,2123,2125,2127,2130,2132,2134,2136,2138],{"class":37,"line":292},[35,2084,2085],{"class":97},"    pd.DataFrame({",[35,2087,2088],{"class":45},"\"Public holiday\"",[35,2090,1333],{"class":97},[35,2092,209],{"class":137},[35,2094,2095],{"class":97},"[(",[35,2097,209],{"class":137},[35,2099,2100],{"class":93}," >=",[35,2102,2103],{"class":137}," YEAR_START",[35,2105,1013],{"class":97},[35,2107,2108],{"class":93},"&",[35,2110,2111],{"class":97}," (",[35,2113,209],{"class":137},[35,2115,2116],{"class":93}," \u003C",[35,2118,2119],{"class":137}," YEAR_END",[35,2121,2122],{"class":97},")]}).to_excel(xw, ",[35,2124,2034],{"class":228},[35,2126,232],{"class":93},[35,2128,2129],{"class":45},"\"Holidays\"",[35,2131,153],{"class":97},[35,2133,621],{"class":228},[35,2135,232],{"class":93},[35,2137,626],{"class":137},[35,2139,203],{"class":97},[35,2141,2142],{"class":37,"line":328},[35,2143,131],{"emptyLinePlaceholder":130},[35,2145,2146,2149,2151],{"class":37,"line":333},[35,2147,2148],{"class":97},"wb ",[35,2150,232],{"class":93},[35,2152,2153],{"class":97}," load_workbook(path)\n",[35,2155,2156,2159,2161,2164,2166],{"class":37,"line":346},[35,2157,2158],{"class":97},"ws ",[35,2160,232],{"class":93},[35,2162,2163],{"class":97}," wb[",[35,2165,2039],{"class":45},[35,2167,1206],{"class":97},[35,2169,2170,2173,2175],{"class":37,"line":370},[35,2171,2172],{"class":97},"n ",[35,2174,232],{"class":93},[35,2176,2177],{"class":97}," ws.max_row\n",[35,2179,2180,2183,2185,2188,2190,2193,2195,2197,2200,2203,2205,2207,2210,2212,2215,2217,2220,2223,2225,2228,2230,2233],{"class":37,"line":415},[35,2181,2182],{"class":97},"ws.conditional_formatting.add(",[35,2184,164],{"class":93},[35,2186,2187],{"class":45},"\"A2:J",[35,2189,171],{"class":170},[35,2191,2192],{"class":97},"n",[35,2194,176],{"class":170},[35,2196,167],{"class":45},[35,2198,2199],{"class":97},", FormulaRule(",[35,2201,2202],{"class":228},"formula",[35,2204,232],{"class":93},[35,2206,245],{"class":97},[35,2208,2209],{"class":45},"\"$I2\u003C0\"",[35,2211,459],{"class":97},[35,2213,2214],{"class":228},"fill",[35,2216,232],{"class":93},[35,2218,2219],{"class":97},"PatternFill(",[35,2221,2222],{"class":45},"\"solid\"",[35,2224,153],{"class":97},[35,2226,2227],{"class":228},"fgColor",[35,2229,232],{"class":93},[35,2231,2232],{"class":45},"\"FFD7D5\"",[35,2234,2235],{"class":97},")))\n",[35,2237,2238,2240,2242,2244,2246,2248,2250,2252,2254,2256,2258,2260,2263,2265,2267,2269,2271,2273,2275,2277,2279,2282],{"class":37,"line":430},[35,2239,2182],{"class":97},[35,2241,164],{"class":93},[35,2243,2187],{"class":45},[35,2245,171],{"class":170},[35,2247,2192],{"class":97},[35,2249,176],{"class":170},[35,2251,167],{"class":45},[35,2253,2199],{"class":97},[35,2255,2202],{"class":228},[35,2257,232],{"class":93},[35,2259,245],{"class":97},[35,2261,2262],{"class":45},"'AND($I2>=0,$J2\u003C>\"\")'",[35,2264,459],{"class":97},[35,2266,2214],{"class":228},[35,2268,232],{"class":93},[35,2270,2219],{"class":97},[35,2272,2222],{"class":45},[35,2274,153],{"class":97},[35,2276,2227],{"class":228},[35,2278,232],{"class":93},[35,2280,2281],{"class":45},"\"FFF4CE\"",[35,2283,2235],{"class":97},[35,2285,2286,2289,2292,2295,2298,2301,2304,2307,2310,2312,2315,2317,2319,2321,2323,2325,2328,2330,2332,2334,2336,2338,2340,2342,2344,2346,2349],{"class":37,"line":439},[35,2287,2288],{"class":93},"for",[35,2290,2291],{"class":97}," col, width ",[35,2293,2294],{"class":93},"in",[35,2296,2297],{"class":137}," zip",[35,2299,2300],{"class":97},"(",[35,2302,2303],{"class":45},"\"ABCDEFGHIJ\"",[35,2305,2306],{"class":97},", (",[35,2308,2309],{"class":137},"10",[35,2311,153],{"class":97},[35,2313,2314],{"class":137},"16",[35,2316,153],{"class":97},[35,2318,1651],{"class":137},[35,2320,153],{"class":97},[35,2322,1651],{"class":137},[35,2324,153],{"class":97},[35,2326,2327],{"class":137},"15",[35,2329,153],{"class":97},[35,2331,2327],{"class":137},[35,2333,153],{"class":97},[35,2335,615],{"class":137},[35,2337,153],{"class":97},[35,2339,615],{"class":137},[35,2341,153],{"class":97},[35,2343,843],{"class":137},[35,2345,153],{"class":97},[35,2347,2348],{"class":137},"44",[35,2350,2351],{"class":97},")):\n",[35,2353,2354,2357,2359],{"class":37,"line":470},[35,2355,2356],{"class":97},"    ws.column_dimensions[col].width ",[35,2358,232],{"class":93},[35,2360,2361],{"class":97}," width\n",[35,2363,2364],{"class":37,"line":511},[35,2365,2366],{"class":97},"wb.save(path)\n",[35,2368,2369,2371,2374,2377,2379,2382,2385,2387,2389,2392,2395],{"class":37,"line":516},[35,2370,584],{"class":137},[35,2372,2373],{"class":97},"(wb.sheetnames, ",[35,2375,2376],{"class":45},"\"| flagged:\"",[35,2378,153],{"class":97},[35,2380,2381],{"class":137},"int",[35,2383,2384],{"class":97},"((report[",[35,2386,1554],{"class":45},[35,2388,488],{"class":97},[35,2390,2391],{"class":93},"!=",[35,2393,2394],{"class":45}," \"\"",[35,2396,2397],{"class":97},").sum()))\n",[10,2399,2400,2401,2404,2405,2408,2409,18],{},"Negative balances are shaded red and other flags amber, using formula rules so the shading follows the numbers if someone corrects a cell. The ",[78,2402,2403],{},"Bookings"," sheet lists every booking with the days it cost, so a disputed balance can be explained line by line, and the ",[78,2406,2407],{},"Holidays"," sheet shows which public holidays were skipped. Sending each manager only their team's rows is the pattern in ",[14,2410,2412],{"href":2411},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002Fgenerate-one-excel-report-per-region-in-a-loop\u002F","Generate One Excel Report per Region in a Loop",[20,2414,2416],{"id":2415},"common-pitfalls","Common pitfalls",[2418,2419,2420,2428,2434,2440,2446],"ul",{},[2421,2422,2423,2427],"li",{},[2424,2425,2426],"strong",{},"Counting calendar days."," Count working days with the person's own work pattern.",[2421,2429,2430,2433],{},[2424,2431,2432],{},"Ignoring public holidays."," Skip them, or a bank-holiday Monday costs a day of leave.",[2421,2435,2436,2439],{},[2424,2437,2438],{},"Full-year entitlement for starters and leavers."," Pro-rate by the days employed.",[2421,2441,2442,2445],{},[2424,2443,2444],{},"Year-end bookings in one year."," Clip each booking to the leave year.",[2421,2447,2448,2451],{},[2424,2449,2450],{},"Carry-over that never expires."," Apply the expiry rule your policy sets.",[20,2453,2455],{"id":2454},"conclusion","Conclusion",[10,2457,2458,2459,2462],{},"To build a leave balance report, count every booking in working days with ",[32,2460,2461],{},"numpy.busday_count",", using each employee's work pattern as the weekmask and the public holiday calendar, clipped to the leave year, with half days as 0.5. Pro-rate entitlement by employment dates and working days, add carry-over only if used before it expires, subtract leave taken and booked, and flag negative and large balances in a workbook that shows the bookings behind every figure.",[20,2464,2466],{"id":2465},"frequently-asked-questions","Frequently asked questions",[10,2468,2469,2472],{},[2424,2470,2471],{},"How do I count working days between two dates in Python?","\nUse numpy.busday_count with the start date and the day after the end date, a weekmask for the working days and a list of public holidays to skip.",[10,2474,2475,2478],{},[2424,2476,2477],{},"How do I count leave for part-time employees?","\nPass their work pattern as the weekmask, for example \"Mon Tue Wed\", so only their working days are counted, and pro-rate their entitlement by days worked per week.",[10,2480,2481,2484],{},[2424,2482,2483],{},"How do I handle leave bookings that span two leave years?","\nClip each booking's start and end to the leave year before counting, so each year counts only its own days.",[10,2486,2487,2490],{},[2424,2488,2489],{},"How is pro-rata annual leave calculated?","\nMultiply full-time entitlement by the share of the leave year employed and by days worked per week divided by five, then round according to policy.",[20,2492,2494],{"id":2493},"related","Related",[2418,2496,2497,2503,2510,2517],{},[2421,2498,2499,2500,2502],{},"Up one level: ",[14,2501,17],{"href":16}," — finance reports from Python.",[2421,2504,2505,2509],{},[14,2506,2508],{"href":2507},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-headcount-and-attrition-report\u002F","Build a Headcount and Attrition Report"," — another HR report.",[2421,2511,2512,2516],{},[14,2513,2515],{"href":2514},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fflag-public-holidays-in-excel-data-with-python\u002F","Flag Public Holidays in Excel Data with Python"," — the holiday calendar.",[2421,2518,2519,2523],{},[14,2520,2522],{"href":2521},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fgenerate-a-staff-rota-in-excel-with-python\u002F","Generate a Staff Rota in Excel with Python"," — planning around leave.",[2525,2526,2527],"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 .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":30,"searchDepth":100,"depth":100,"links":2529},[2530,2531,2532,2533,2534,2535,2536,2537,2538],{"id":22,"depth":100,"text":23},{"id":68,"depth":100,"text":69},{"id":852,"depth":100,"text":853},{"id":1253,"depth":100,"text":1254},{"id":1849,"depth":100,"text":1850},{"id":2415,"depth":100,"text":2416},{"id":2454,"depth":100,"text":2455},{"id":2465,"depth":100,"text":2466},{"id":2493,"depth":100,"text":2494},"2026-10-02","Calculate annual leave balances for every employee from an HR list and a leave bookings export with pandas and NumPy: pro-rata entitlement for starters and part-timers, carried-over days with an expiry date, bookings counted in working days using each person's work pattern and the public holiday calendar, half days, bookings that span the year end, and a workbook that flags negative and unusually high balances.","md",[2543,2545,2547,2549],{"q":2471,"a":2544},"Use numpy.busday_count with the start date and the day after the end date, a weekmask for the working days and a list of public holidays to skip.",{"q":2477,"a":2546},"Pass their work pattern as the weekmask, for example \"Mon Tue Wed\", so only their working days are counted, and pro-rate their entitlement by days worked per week.",{"q":2483,"a":2548},"Clip each booking's start and end to the leave year before counting, so each year counts only its own days.",{"q":2489,"a":2550},"Multiply full-time entitlement by the share of the leave year employed and by days worked per week divided by five, then round according to policy.","employee leave balance report",null,{"breadcrumb":2554},[2555,2557,2560],{"name":2556,"item":1016},"Home",{"name":2558,"item":2559},"Automating Reporting Workflows with Python and Excel","\u002Fautomating-reporting-workflows\u002F",{"name":2561,"item":16},"Building Finance and Operations Reports in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report",{"title":2564,"description":2565},"Build an Employee Leave Balance Report with Python","Annual leave balances with pandas and numpy busday_count: pro-rata entitlement, part-time weekmasks, public holidays, half days, carry-over expiry, year-end splits, and flagged balances in Excel.","build-an-employee-leave-balance-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report\u002Findex",[2569],"report-layouts","how-to","xinBV8qCIlj0PCnp8sPNsAqwUyKFpMChwN1eVVV9X-Q",[2573,2577],{"title":2574,"path":2575,"stem":2576,"children":-1},"Build an Aged Creditors Report","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report\u002Findex",{"title":2578,"path":2579,"stem":2580,"children":-1},"Build an Energy Consumption Report from Meter Readings","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-energy-consumption-report-from-meter-readings","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-energy-consumption-report-from-meter-readings\u002Findex",[2582,2584],{"path":2583,"title":2561},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports",{"path":2585,"title":2558},"\u002Fautomating-reporting-workflows",[],[2588,2592,2595,2598,2601,2604],{"path":2589,"title":2590,"kind":2591},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards","Building Multi-Sheet Excel Dashboards","guide",{"path":2593,"title":2594,"kind":2570},"\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":2596,"title":2597,"kind":2570},"\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":2599,"title":2600,"kind":2570},"\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":2602,"title":2603,"kind":2570},"\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":2605,"title":2606,"kind":2570},"\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",1790972127660]