[{"data":1,"prerenderedAt":2205},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report":3,"surround:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report":2170,"ancestors:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report":2179,"children:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report":2184,"related:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report":2185},{"id":4,"title":5,"body":6,"dateModified":2136,"datePublished":2136,"description":2137,"extension":2138,"faq":2139,"keyword":2148,"kind":2149,"meta":2150,"navigation":88,"path":2159,"seo":2160,"slug":2163,"stem":2164,"topics":2165,"type":2168,"__hash__":2169},"docs\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report\u002Findex.md","Build an Aged Creditors Report",{"type":7,"value":8,"toc":2124},"minimark",[9,19,24,53,56,60,349,372,501,505,809,826,830,833,936,943,1036,1040,1815,1830,1997,2001,2004,2008,2048,2052,2061,2065,2071,2077,2083,2089,2093,2120],[10,11,12,13,18],"p",{},"The aged creditors report — accounts payable ageing — answers the questions a finance team asks about what it owes: how much, to whom, and how late. It lists every open item with each supplier, sorts the amounts into columns by how far past their due date they are, and totals by supplier and overall. It is used to plan payments, to spot suppliers who will soon be chasing, to find credit notes that have been sitting unused, and at month end to prove that the payables ledger agrees with the balance sheet. This page builds it from an open-items export with pandas: ages every invoice, credit note and unallocated payment by due date, keeps credits as negative amounts in the right columns, marks disputed items, summarises by supplier with the overdue share, reconciles the total to the payables control account and writes a formatted workbook with overdue amounts highlighted. 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],{},"The input is the open payables listing at 30 September 2026 — every document not yet fully settled — with supplier, document type (invoice, credit note or payment on account), reference, document and due dates, amount and a status column where disputes are marked. The payables control account in the general ledger shows 52,100.70 at the same date.",[20,57,59],{"id":58},"step-1-age-every-open-item","Step 1 — Age every open item",[25,61,65],{"className":62,"code":63,"language":64,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nREPORT_DATE = pd.Timestamp(\"2026-09-30\")\nitems = pd.read_excel(\"ap_open_items.xlsx\")\nitems[\"Days overdue\"] = (REPORT_DATE - items[\"Due date\"]).dt.days\nBUCKETS = [\"Current\", \"1-30\", \"31-60\", \"61-90\", \"90+\"]\nitems[\"Bucket\"] = pd.cut(items[\"Days overdue\"], bins=[-10_000, 0, 30, 60, 90, 10_000], labels=BUCKETS)\nitems.loc[items[\"Type\"].isin([\"CRN\", \"PAY\"]), \"Bucket\"] = \"Current\"\nprint(items[[\"Supplier\", \"Type\", \"Reference\", \"Due date\", \"Days overdue\", \"Bucket\", \"Amount\"]].to_string(index=False))\n","python",[32,66,67,83,90,109,126,157,195,265,297],{"__ignoreMap":30},[35,68,69,73,77,80],{"class":37,"line":38},[35,70,72],{"class":71},"s-kum","import",[35,74,76],{"class":75},"skGVy"," pandas ",[35,78,79],{"class":71},"as",[35,81,82],{"class":75}," pd\n",[35,84,86],{"class":37,"line":85},2,[35,87,89],{"emptyLinePlaceholder":88},true,"\n",[35,91,93,97,100,103,106],{"class":37,"line":92},3,[35,94,96],{"class":95},"sP0c6","REPORT_DATE",[35,98,99],{"class":71}," =",[35,101,102],{"class":75}," pd.Timestamp(",[35,104,105],{"class":45},"\"2026-09-30\"",[35,107,108],{"class":75},")\n",[35,110,112,115,118,121,124],{"class":37,"line":111},4,[35,113,114],{"class":75},"items ",[35,116,117],{"class":71},"=",[35,119,120],{"class":75}," pd.read_excel(",[35,122,123],{"class":45},"\"ap_open_items.xlsx\"",[35,125,108],{"class":75},[35,127,129,132,135,138,140,143,145,148,151,154],{"class":37,"line":128},5,[35,130,131],{"class":75},"items[",[35,133,134],{"class":45},"\"Days overdue\"",[35,136,137],{"class":75},"] ",[35,139,117],{"class":71},[35,141,142],{"class":75}," (",[35,144,96],{"class":95},[35,146,147],{"class":71}," -",[35,149,150],{"class":75}," items[",[35,152,153],{"class":45},"\"Due date\"",[35,155,156],{"class":75},"]).dt.days\n",[35,158,160,163,165,168,171,174,177,179,182,184,187,189,192],{"class":37,"line":159},6,[35,161,162],{"class":95},"BUCKETS",[35,164,99],{"class":71},[35,166,167],{"class":75}," [",[35,169,170],{"class":45},"\"Current\"",[35,172,173],{"class":75},", ",[35,175,176],{"class":45},"\"1-30\"",[35,178,173],{"class":75},[35,180,181],{"class":45},"\"31-60\"",[35,183,173],{"class":75},[35,185,186],{"class":45},"\"61-90\"",[35,188,173],{"class":75},[35,190,191],{"class":45},"\"90+\"",[35,193,194],{"class":75},"]\n",[35,196,198,200,203,205,207,210,212,215,219,221,224,227,230,232,235,237,240,242,245,247,250,252,254,256,259,261,263],{"class":37,"line":197},7,[35,199,131],{"class":75},[35,201,202],{"class":45},"\"Bucket\"",[35,204,137],{"class":75},[35,206,117],{"class":71},[35,208,209],{"class":75}," pd.cut(items[",[35,211,134],{"class":45},[35,213,214],{"class":75},"], ",[35,216,218],{"class":217},"sa561","bins",[35,220,117],{"class":71},[35,222,223],{"class":75},"[",[35,225,226],{"class":71},"-",[35,228,229],{"class":95},"10_000",[35,231,173],{"class":75},[35,233,234],{"class":95},"0",[35,236,173],{"class":75},[35,238,239],{"class":95},"30",[35,241,173],{"class":75},[35,243,244],{"class":95},"60",[35,246,173],{"class":75},[35,248,249],{"class":95},"90",[35,251,173],{"class":75},[35,253,229],{"class":95},[35,255,214],{"class":75},[35,257,258],{"class":217},"labels",[35,260,117],{"class":71},[35,262,162],{"class":95},[35,264,108],{"class":75},[35,266,268,271,274,277,280,282,285,288,290,292,294],{"class":37,"line":267},8,[35,269,270],{"class":75},"items.loc[items[",[35,272,273],{"class":45},"\"Type\"",[35,275,276],{"class":75},"].isin([",[35,278,279],{"class":45},"\"CRN\"",[35,281,173],{"class":75},[35,283,284],{"class":45},"\"PAY\"",[35,286,287],{"class":75},"]), ",[35,289,202],{"class":45},[35,291,137],{"class":75},[35,293,117],{"class":71},[35,295,296],{"class":45}," \"Current\"\n",[35,298,300,303,306,309,311,313,315,318,320,322,324,326,328,330,332,335,338,341,343,346],{"class":37,"line":299},9,[35,301,302],{"class":95},"print",[35,304,305],{"class":75},"(items[[",[35,307,308],{"class":45},"\"Supplier\"",[35,310,173],{"class":75},[35,312,273],{"class":45},[35,314,173],{"class":75},[35,316,317],{"class":45},"\"Reference\"",[35,319,173],{"class":75},[35,321,153],{"class":45},[35,323,173],{"class":75},[35,325,134],{"class":45},[35,327,173],{"class":75},[35,329,202],{"class":45},[35,331,173],{"class":75},[35,333,334],{"class":45},"\"Amount\"",[35,336,337],{"class":75},"]].to_string(",[35,339,340],{"class":217},"index",[35,342,117],{"class":71},[35,344,345],{"class":95},"False",[35,347,348],{"class":75},"))\n",[10,350,351,352,356,357,360,361,364,365,368,369,371],{},"Age is measured from the ",[353,354,355],"em",{},"due date",", because the question is how late a payment is; some teams age from the document date instead, which shows how old the debt is regardless of terms — pick one and say which in the report heading. ",[32,358,359],{},"pd.cut"," with explicit edges sorts the days into buckets, and the bins are right-closed, so an invoice due today (0 days) is still ",[353,362,363],{},"Current"," while one due yesterday is in ",[353,366,367],{},"1–30",". Credit notes and unallocated payments are amounts the company can set against what it owes, so they are kept as negatives and placed in ",[353,370,363],{},": ageing them would make it look as if credits were overdue.",[373,374,382,383,382,387,382,391,382,398,382,405,382,415,382,421,382,426,382,430,382,434,382,440,382,445,382,449,382,451,382,453,382,458,382,463,382,466,382,468,382,470,382,473,382,477,382,480,382,482,382,484,382,489,382,494,382,497,382,499],"svg",{"viewBox":375,"role":376,"ariaLabelledBy":377,"xmlns":380,"style":381},"4 0 752 211","img",[378,379],"ap-buckets-t","ap-buckets-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  ",[384,385,386],"title",{"id":378},"Ageing buckets by days past due",[388,389,390],"desc",{"id":379},"Items not yet due or due today are current. Items 1 to 30 days past due, 31 to 60, 61 to 90 and over 90 days fall into the following buckets. Credit notes and unallocated payments are kept as negatives in the current column.",[392,393],"rect",{"x":394,"y":234,"width":395,"height":396,"fill":397},"4","752","211","#ffffff",[37,399],{"x1":400,"y1":401,"x2":402,"y2":401,"stroke":403,"style":404},"76.0","105.5","684.0","var(--muted,#5b6780)","stroke-width:2.5px",[392,406],{"x":407,"y":408,"width":409,"height":410,"rx":411,"fill":412,"stroke":413,"style":414},"20.0","16.0","136.0","57.5","12","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[416,417,363],"text",{"x":418,"y":419,"style":420},"88.0","40.5","font-size:12.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[416,422,425],{"x":418,"y":423,"style":424},"59.0","font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","not yet due, credits",[37,427],{"x1":418,"y1":428,"x2":418,"y2":401,"stroke":403,"style":429},"73.5","stroke-width:1.5px",[431,432],"circle",{"cx":418,"cy":401,"r":433,"fill":413,"stroke":397,"style":414},"7.0",[392,435],{"x":436,"y":437,"width":409,"height":410,"rx":411,"fill":438,"stroke":439,"style":414},"166.0","137.5","#e7ebef","var(--line,#cdd5e6)",[416,441,367],{"x":442,"y":443,"style":444},"234.0","162.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[416,446,448],{"x":442,"y":447,"style":424},"180.5","just overdue",[37,450],{"x1":442,"y1":401,"x2":442,"y2":437,"stroke":403,"style":429},[431,452],{"cx":442,"cy":401,"r":433,"fill":403,"stroke":397,"style":414},[392,454],{"x":455,"y":408,"width":409,"height":410,"rx":411,"fill":456,"stroke":457,"style":414},"312.0","#fdefd8","var(--gold,#b4740a)",[416,459,462],{"x":460,"y":419,"style":461},"380.0","font-size:12.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","31–60",[416,464,465],{"x":460,"y":423,"style":424},"chase risk",[37,467],{"x1":460,"y1":428,"x2":460,"y2":401,"stroke":403,"style":429},[431,469],{"cx":460,"cy":401,"r":433,"fill":457,"stroke":397,"style":414},[392,471],{"x":472,"y":437,"width":409,"height":410,"rx":411,"fill":456,"stroke":457,"style":414},"458.0",[416,474,476],{"x":475,"y":443,"style":461},"526.0","61–90",[416,478,479],{"x":475,"y":447,"style":424},"relationship risk",[37,481],{"x1":475,"y1":401,"x2":475,"y2":437,"stroke":403,"style":429},[431,483],{"cx":475,"cy":401,"r":433,"fill":457,"stroke":397,"style":414},[392,485],{"x":486,"y":408,"width":409,"height":410,"rx":411,"fill":487,"stroke":488,"style":414},"604.0","#f0f4ff","var(--brand,#5b5cf0)",[416,490,493],{"x":491,"y":419,"style":492},"672.0","font-size:12.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","90+",[416,495,496],{"x":491,"y":423,"style":424},"investigate",[37,498],{"x1":491,"y1":428,"x2":491,"y2":401,"stroke":403,"style":429},[431,500],{"cx":491,"cy":401,"r":433,"fill":488,"stroke":397,"style":414},[20,502,504],{"id":503},"step-2-summarise-by-supplier","Step 2 — Summarise by supplier",[25,506,508],{"className":62,"code":507,"language":64,"meta":30,"style":30},"by_supplier = items.pivot_table(index=\"Supplier\", columns=\"Bucket\", values=\"Amount\", aggfunc=\"sum\",\n                                fill_value=0, observed=False)[BUCKETS]\nby_supplier[\"Total\"] = by_supplier.sum(axis=1)\nby_supplier[\"Overdue\"] = by_supplier[BUCKETS[1:]].sum(axis=1)\nby_supplier[\"Overdue %\"] = (by_supplier[\"Overdue\"] \u002F by_supplier[\"Total\"]).where(by_supplier[\"Total\"] > 0)\ndisputed = items[items[\"Status\"].eq(\"disputed\")].groupby(\"Supplier\")[\"Amount\"].sum()\nby_supplier[\"In dispute\"] = disputed.reindex(by_supplier.index, fill_value=0)\nby_supplier = by_supplier.sort_values(\"Overdue\", ascending=False)\ntotals = by_supplier[BUCKETS + [\"Total\", \"Overdue\", \"In dispute\"]].sum()\nprint(by_supplier.round(2).to_string())\nprint(totals.round(2).to_string())\n",[32,509,510,557,582,607,638,678,709,732,754,783,797],{"__ignoreMap":30},[35,511,512,515,517,520,522,524,526,528,531,533,535,537,540,542,544,546,549,551,554],{"class":37,"line":38},[35,513,514],{"class":75},"by_supplier ",[35,516,117],{"class":71},[35,518,519],{"class":75}," items.pivot_table(",[35,521,340],{"class":217},[35,523,117],{"class":71},[35,525,308],{"class":45},[35,527,173],{"class":75},[35,529,530],{"class":217},"columns",[35,532,117],{"class":71},[35,534,202],{"class":45},[35,536,173],{"class":75},[35,538,539],{"class":217},"values",[35,541,117],{"class":71},[35,543,334],{"class":45},[35,545,173],{"class":75},[35,547,548],{"class":217},"aggfunc",[35,550,117],{"class":71},[35,552,553],{"class":45},"\"sum\"",[35,555,556],{"class":75},",\n",[35,558,559,562,564,566,568,571,573,575,578,580],{"class":37,"line":85},[35,560,561],{"class":217},"                                fill_value",[35,563,117],{"class":71},[35,565,234],{"class":95},[35,567,173],{"class":75},[35,569,570],{"class":217},"observed",[35,572,117],{"class":71},[35,574,345],{"class":95},[35,576,577],{"class":75},")[",[35,579,162],{"class":95},[35,581,194],{"class":75},[35,583,584,587,590,592,594,597,600,602,605],{"class":37,"line":92},[35,585,586],{"class":75},"by_supplier[",[35,588,589],{"class":45},"\"Total\"",[35,591,137],{"class":75},[35,593,117],{"class":71},[35,595,596],{"class":75}," by_supplier.sum(",[35,598,599],{"class":217},"axis",[35,601,117],{"class":71},[35,603,604],{"class":95},"1",[35,606,108],{"class":75},[35,608,609,611,614,616,618,621,623,625,627,630,632,634,636],{"class":37,"line":111},[35,610,586],{"class":75},[35,612,613],{"class":45},"\"Overdue\"",[35,615,137],{"class":75},[35,617,117],{"class":71},[35,619,620],{"class":75}," by_supplier[",[35,622,162],{"class":95},[35,624,223],{"class":75},[35,626,604],{"class":95},[35,628,629],{"class":75},":]].sum(",[35,631,599],{"class":217},[35,633,117],{"class":71},[35,635,604],{"class":95},[35,637,108],{"class":75},[35,639,640,642,645,647,649,652,654,656,659,661,663,666,668,670,673,676],{"class":37,"line":128},[35,641,586],{"class":75},[35,643,644],{"class":45},"\"Overdue %\"",[35,646,137],{"class":75},[35,648,117],{"class":71},[35,650,651],{"class":75}," (by_supplier[",[35,653,613],{"class":45},[35,655,137],{"class":75},[35,657,658],{"class":71},"\u002F",[35,660,620],{"class":75},[35,662,589],{"class":45},[35,664,665],{"class":75},"]).where(by_supplier[",[35,667,589],{"class":45},[35,669,137],{"class":75},[35,671,672],{"class":71},">",[35,674,675],{"class":95}," 0",[35,677,108],{"class":75},[35,679,680,683,685,688,691,694,697,700,702,704,706],{"class":37,"line":159},[35,681,682],{"class":75},"disputed ",[35,684,117],{"class":71},[35,686,687],{"class":75}," items[items[",[35,689,690],{"class":45},"\"Status\"",[35,692,693],{"class":75},"].eq(",[35,695,696],{"class":45},"\"disputed\"",[35,698,699],{"class":75},")].groupby(",[35,701,308],{"class":45},[35,703,577],{"class":75},[35,705,334],{"class":45},[35,707,708],{"class":75},"].sum()\n",[35,710,711,713,716,718,720,723,726,728,730],{"class":37,"line":197},[35,712,586],{"class":75},[35,714,715],{"class":45},"\"In dispute\"",[35,717,137],{"class":75},[35,719,117],{"class":71},[35,721,722],{"class":75}," disputed.reindex(by_supplier.index, ",[35,724,725],{"class":217},"fill_value",[35,727,117],{"class":71},[35,729,234],{"class":95},[35,731,108],{"class":75},[35,733,734,736,738,741,743,745,748,750,752],{"class":37,"line":267},[35,735,514],{"class":75},[35,737,117],{"class":71},[35,739,740],{"class":75}," by_supplier.sort_values(",[35,742,613],{"class":45},[35,744,173],{"class":75},[35,746,747],{"class":217},"ascending",[35,749,117],{"class":71},[35,751,345],{"class":95},[35,753,108],{"class":75},[35,755,756,759,761,763,765,768,770,772,774,776,778,780],{"class":37,"line":299},[35,757,758],{"class":75},"totals ",[35,760,117],{"class":71},[35,762,620],{"class":75},[35,764,162],{"class":95},[35,766,767],{"class":71}," +",[35,769,167],{"class":75},[35,771,589],{"class":45},[35,773,173],{"class":75},[35,775,613],{"class":45},[35,777,173],{"class":75},[35,779,715],{"class":45},[35,781,782],{"class":75},"]].sum()\n",[35,784,786,788,791,794],{"class":37,"line":785},10,[35,787,302],{"class":95},[35,789,790],{"class":75},"(by_supplier.round(",[35,792,793],{"class":95},"2",[35,795,796],{"class":75},").to_string())\n",[35,798,800,802,805,807],{"class":37,"line":799},11,[35,801,302],{"class":95},[35,803,804],{"class":75},"(totals.round(",[35,806,793],{"class":95},[35,808,796],{"class":75},[10,810,811,812,815,816,819,820,822,823,825],{},"A pivot with the buckets as columns gives the classic layout, one row per supplier; ",[32,813,814],{},"observed=False"," keeps every bucket as a column even when no supplier has an item in it, so the report always has the same shape. Sorting by overdue amount puts the suppliers most likely to be on the phone at the top. The ",[353,817,818],{},"In dispute"," column separates amounts that are overdue on purpose — the Brightline invoice under query — from those that are simply unpaid; a payment run should pay the second and resolve the first. Corex's unallocated payment sits as a negative in ",[353,821,363],{}," while their invoice ages in ",[353,824,476],{},": the payment has been made but not matched to the invoice, which is a housekeeping job for the payables team, and the report makes it visible — it also pushes Corex's overdue share above 100%, a figure that only makes sense once the payment is allocated. Evergreen tops the list with 12,400 overdue by sixteen days.",[20,827,829],{"id":828},"step-3-reconcile-to-the-control-account","Step 3 — Reconcile to the control account",[10,831,832],{},"The total of the ageing must equal the payables balance in the general ledger. Any difference means an item is missing from one or the other:",[25,834,836],{"className":62,"code":835,"language":64,"meta":30,"style":30},"CONTROL_ACCOUNT = 52_100.70\ndifference = round(totals[\"Total\"] - CONTROL_ACCOUNT, 2)\nprint(f\"ageing total {totals['Total']:,.2f} | control account {CONTROL_ACCOUNT:,.2f} | difference {difference:,.2f}\")\n",[32,837,838,848,876],{"__ignoreMap":30},[35,839,840,843,845],{"class":37,"line":38},[35,841,842],{"class":95},"CONTROL_ACCOUNT",[35,844,99],{"class":71},[35,846,847],{"class":95}," 52_100.70\n",[35,849,850,853,855,858,861,863,865,867,870,872,874],{"class":37,"line":85},[35,851,852],{"class":75},"difference ",[35,854,117],{"class":71},[35,856,857],{"class":95}," round",[35,859,860],{"class":75},"(totals[",[35,862,589],{"class":45},[35,864,137],{"class":75},[35,866,226],{"class":71},[35,868,869],{"class":95}," CONTROL_ACCOUNT",[35,871,173],{"class":75},[35,873,793],{"class":95},[35,875,108],{"class":75},[35,877,878,880,883,886,889,893,896,899,902,905,908,911,913,915,917,919,922,924,927,929,931,934],{"class":37,"line":92},[35,879,302],{"class":95},[35,881,882],{"class":75},"(",[35,884,885],{"class":71},"f",[35,887,888],{"class":45},"\"ageing total ",[35,890,892],{"class":891},"sSjpA","{",[35,894,895],{"class":75},"totals[",[35,897,898],{"class":45},"'Total'",[35,900,901],{"class":75},"]",[35,903,904],{"class":71},":,.2f",[35,906,907],{"class":891},"}",[35,909,910],{"class":45}," | control account ",[35,912,892],{"class":891},[35,914,842],{"class":95},[35,916,904],{"class":71},[35,918,907],{"class":891},[35,920,921],{"class":45}," | difference ",[35,923,892],{"class":891},[35,925,926],{"class":75},"difference",[35,928,904],{"class":71},[35,930,907],{"class":891},[35,932,933],{"class":45},"\"",[35,935,108],{"class":75},[10,937,938,939,18],{},"The ageing totals 52,200.70; the control account shows 52,100.70. The difference of exactly 100.00 is the kind a month-end review exists to find. The usual causes are a document posted directly to the control account without a supplier — a manual journal correcting a supplier balance, say — a cut-off difference between when the listing and the ledger were run, or a supplier item posted to the wrong account. A round figure points to a manual journal, so the next step is to list journals to the control account in the period. The reconciliation line goes on the report whether or not it is zero, because a reviewer will want to see it, and a non-zero difference is a finding to resolve before the figures are signed off. The ledger side of this is covered in ",[14,940,942],{"href":941},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-trial-balance-from-a-general-ledger\u002F","Build a Trial Balance from a General Ledger",[373,944,382,950,382,953,382,956,382,960,382,966,382,970,382,974,382,979,382,982,382,986,382,989,382,994,382,997,382,1001,382,1004,382,1009,382,1011,382,1015,382,1018,382,1022,382,1025,382,1028,382,1031],{"viewBox":945,"role":376,"ariaLabelledBy":946,"xmlns":380,"style":949},"4 0 744 220",[947,948],"ap-totals-t","ap-totals-d","width:100%;max-width:744px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[384,951,952],{"id":947},"What is owed, by age",[388,954,955],{"id":948},"Of the 52,200.70 in the ageing at 30 September 2026, 22,690.20 is current after credits and payments on account, 13,650.00 is 1 to 30 days overdue, nothing is 31 to 60 days, 12,960.50 is 61 to 90 days and 2,900.00 is over 90 days.",[392,957],{"x":394,"y":234,"width":958,"height":959,"fill":397},"744","220",[392,961],{"x":407,"y":408,"width":962,"height":963,"rx":964,"fill":438,"stroke":439,"style":965},"77.4","28.0","7","stroke-width:1px",[416,967,363],{"x":968,"y":969,"style":444},"58.7","34.5",[392,971],{"x":972,"y":408,"width":973,"height":963,"rx":964,"fill":412,"stroke":413,"style":429},"107.4","551.1",[416,975,978],{"x":976,"y":969,"style":977},"666.4","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","22,690.20",[392,980],{"x":407,"y":981,"width":962,"height":963,"rx":964,"fill":438,"stroke":439,"style":965},"56.0",[416,983,985],{"x":968,"y":984,"style":444},"74.5","1-30",[392,987],{"x":972,"y":981,"width":988,"height":963,"rx":964,"fill":438,"stroke":439,"style":429},"331.5",[416,990,993],{"x":991,"y":984,"style":992},"446.9","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:start","13,650.00",[392,995],{"x":407,"y":996,"width":962,"height":963,"rx":964,"fill":438,"stroke":439,"style":965},"96.0",[416,998,1000],{"x":968,"y":999,"style":444},"114.5","31-60",[392,1002],{"x":972,"y":996,"width":1003,"height":963,"rx":964,"fill":456,"stroke":457,"style":429},"6.0",[416,1005,1008],{"x":1006,"y":999,"style":1007},"121.4","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","0.00",[392,1010],{"x":407,"y":409,"width":962,"height":963,"rx":964,"fill":438,"stroke":439,"style":965},[416,1012,1014],{"x":968,"y":1013,"style":444},"154.5","61-90",[392,1016],{"x":972,"y":409,"width":1017,"height":963,"rx":964,"fill":456,"stroke":457,"style":429},"314.8",[416,1019,1021],{"x":1020,"y":1013,"style":1007},"430.1","12,960.50",[392,1023],{"x":407,"y":1024,"width":962,"height":963,"rx":964,"fill":438,"stroke":439,"style":965},"176.0",[416,1026,493],{"x":968,"y":1027,"style":444},"194.5",[392,1029],{"x":972,"y":1024,"width":1030,"height":963,"rx":964,"fill":487,"stroke":488,"style":429},"70.4",[416,1032,1035],{"x":1033,"y":1027,"style":1034},"185.8","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","2,900.00",[20,1037,1039],{"id":1038},"step-4-write-the-report","Step 4 — Write the report",[25,1041,1043],{"className":62,"code":1042,"language":64,"meta":30,"style":30},"from openpyxl import load_workbook\nfrom openpyxl.styles import Font, PatternFill\n\npath = \"aged_creditors_2026-09-30.xlsx\"\nwith pd.ExcelWriter(path, engine=\"openpyxl\", date_format=\"dd mmm yyyy\", datetime_format=\"dd mmm yyyy\") as xw:\n    by_supplier.to_excel(xw, sheet_name=\"Summary\", startrow=2)\n    items.sort_values([\"Supplier\", \"Due date\"]).to_excel(xw, sheet_name=\"Open items\", index=False)\nwb = load_workbook(path)\nws = wb[\"Summary\"]\nws[\"A1\"] = f\"Aged creditors at {REPORT_DATE:%d %B %Y} — aged by due date\"\nws[\"A1\"].font = Font(bold=True, size=13)\nlast = ws.max_row\nws.cell(last + 1, 1, \"Total\").font = Font(bold=True)\nfor col in range(2, 2 + len(BUCKETS) + 2):\n    letter = ws.cell(3, col).column_letter\n    ws.cell(last + 1, col, f\"=SUM({letter}4:{letter}{last})\").font = Font(bold=True)\nws.cell(last + 3, 1, \"Control account\"), ws.cell(last + 3, 2 + len(BUCKETS), CONTROL_ACCOUNT)\nws.cell(last + 4, 1, \"Difference\"), ws.cell(last + 4, 2 + len(BUCKETS), f\"={ws.cell(last + 1, 2 + len(BUCKETS)).coordinate}-{ws.cell(last + 3, 2 + len(BUCKETS)).coordinate}\")\nlate = PatternFill(\"solid\", fgColor=\"FCE4D6\")\nfor row in ws.iter_rows(min_row=4, max_row=last + 4, min_col=2, max_col=ws.max_column):\n    for cell in row:\n        cell.number_format = \"0.0%\" if ws.cell(3, cell.column).value == \"Overdue %\" else \"#,##0.00;[Red]-#,##0.00;-\"\n        if ws.cell(3, cell.column).value in (\"61-90\", \"90+\") and isinstance(cell.value, (int, float)) and cell.value > 0:\n            cell.fill = late\nws.column_dimensions[\"A\"].width = 24\nwb.save(path)\nprint(wb.sheetnames)\n",[32,1044,1045,1058,1070,1074,1084,1127,1151,1182,1192,1206,1252,1286,1297,1332,1374,1391,1448,1493,1592,1618,1670,1684,1717,1773,1784,1801,1807],{"__ignoreMap":30},[35,1046,1047,1050,1053,1055],{"class":37,"line":38},[35,1048,1049],{"class":71},"from",[35,1051,1052],{"class":75}," openpyxl ",[35,1054,72],{"class":71},[35,1056,1057],{"class":75}," load_workbook\n",[35,1059,1060,1062,1065,1067],{"class":37,"line":85},[35,1061,1049],{"class":71},[35,1063,1064],{"class":75}," openpyxl.styles ",[35,1066,72],{"class":71},[35,1068,1069],{"class":75}," Font, PatternFill\n",[35,1071,1072],{"class":37,"line":92},[35,1073,89],{"emptyLinePlaceholder":88},[35,1075,1076,1079,1081],{"class":37,"line":111},[35,1077,1078],{"class":75},"path ",[35,1080,117],{"class":71},[35,1082,1083],{"class":45}," \"aged_creditors_2026-09-30.xlsx\"\n",[35,1085,1086,1089,1092,1095,1097,1100,1102,1105,1107,1110,1112,1115,1117,1119,1122,1124],{"class":37,"line":128},[35,1087,1088],{"class":71},"with",[35,1090,1091],{"class":75}," pd.ExcelWriter(path, ",[35,1093,1094],{"class":217},"engine",[35,1096,117],{"class":71},[35,1098,1099],{"class":45},"\"openpyxl\"",[35,1101,173],{"class":75},[35,1103,1104],{"class":217},"date_format",[35,1106,117],{"class":71},[35,1108,1109],{"class":45},"\"dd mmm yyyy\"",[35,1111,173],{"class":75},[35,1113,1114],{"class":217},"datetime_format",[35,1116,117],{"class":71},[35,1118,1109],{"class":45},[35,1120,1121],{"class":75},") ",[35,1123,79],{"class":71},[35,1125,1126],{"class":75}," xw:\n",[35,1128,1129,1132,1135,1137,1140,1142,1145,1147,1149],{"class":37,"line":159},[35,1130,1131],{"class":75},"    by_supplier.to_excel(xw, ",[35,1133,1134],{"class":217},"sheet_name",[35,1136,117],{"class":71},[35,1138,1139],{"class":45},"\"Summary\"",[35,1141,173],{"class":75},[35,1143,1144],{"class":217},"startrow",[35,1146,117],{"class":71},[35,1148,793],{"class":95},[35,1150,108],{"class":75},[35,1152,1153,1156,1158,1160,1162,1165,1167,1169,1172,1174,1176,1178,1180],{"class":37,"line":197},[35,1154,1155],{"class":75},"    items.sort_values([",[35,1157,308],{"class":45},[35,1159,173],{"class":75},[35,1161,153],{"class":45},[35,1163,1164],{"class":75},"]).to_excel(xw, ",[35,1166,1134],{"class":217},[35,1168,117],{"class":71},[35,1170,1171],{"class":45},"\"Open items\"",[35,1173,173],{"class":75},[35,1175,340],{"class":217},[35,1177,117],{"class":71},[35,1179,345],{"class":95},[35,1181,108],{"class":75},[35,1183,1184,1187,1189],{"class":37,"line":267},[35,1185,1186],{"class":75},"wb ",[35,1188,117],{"class":71},[35,1190,1191],{"class":75}," load_workbook(path)\n",[35,1193,1194,1197,1199,1202,1204],{"class":37,"line":299},[35,1195,1196],{"class":75},"ws ",[35,1198,117],{"class":71},[35,1200,1201],{"class":75}," wb[",[35,1203,1139],{"class":45},[35,1205,194],{"class":75},[35,1207,1208,1211,1214,1216,1218,1221,1224,1226,1228,1231,1234,1237,1239,1242,1244,1247,1249],{"class":37,"line":785},[35,1209,1210],{"class":75},"ws[",[35,1212,1213],{"class":45},"\"A1\"",[35,1215,137],{"class":75},[35,1217,117],{"class":71},[35,1219,1220],{"class":71}," f",[35,1222,1223],{"class":45},"\"Aged creditors at ",[35,1225,892],{"class":891},[35,1227,96],{"class":95},[35,1229,1230],{"class":75},":",[35,1232,1233],{"class":71},"%",[35,1235,1236],{"class":75},"d ",[35,1238,1233],{"class":71},[35,1240,1241],{"class":75},"B ",[35,1243,1233],{"class":71},[35,1245,1246],{"class":75},"Y",[35,1248,907],{"class":891},[35,1250,1251],{"class":45}," — aged by due date\"\n",[35,1253,1254,1256,1258,1261,1263,1266,1269,1271,1274,1276,1279,1281,1284],{"class":37,"line":799},[35,1255,1210],{"class":75},[35,1257,1213],{"class":45},[35,1259,1260],{"class":75},"].font ",[35,1262,117],{"class":71},[35,1264,1265],{"class":75}," Font(",[35,1267,1268],{"class":217},"bold",[35,1270,117],{"class":71},[35,1272,1273],{"class":95},"True",[35,1275,173],{"class":75},[35,1277,1278],{"class":217},"size",[35,1280,117],{"class":71},[35,1282,1283],{"class":95},"13",[35,1285,108],{"class":75},[35,1287,1289,1292,1294],{"class":37,"line":1288},12,[35,1290,1291],{"class":75},"last ",[35,1293,117],{"class":71},[35,1295,1296],{"class":75}," ws.max_row\n",[35,1298,1300,1303,1306,1309,1311,1313,1315,1317,1320,1322,1324,1326,1328,1330],{"class":37,"line":1299},13,[35,1301,1302],{"class":75},"ws.cell(last ",[35,1304,1305],{"class":71},"+",[35,1307,1308],{"class":95}," 1",[35,1310,173],{"class":75},[35,1312,604],{"class":95},[35,1314,173],{"class":75},[35,1316,589],{"class":45},[35,1318,1319],{"class":75},").font ",[35,1321,117],{"class":71},[35,1323,1265],{"class":75},[35,1325,1268],{"class":217},[35,1327,117],{"class":71},[35,1329,1273],{"class":95},[35,1331,108],{"class":75},[35,1333,1335,1338,1341,1344,1347,1349,1351,1353,1355,1357,1360,1362,1364,1366,1368,1371],{"class":37,"line":1334},14,[35,1336,1337],{"class":71},"for",[35,1339,1340],{"class":75}," col ",[35,1342,1343],{"class":71},"in",[35,1345,1346],{"class":95}," range",[35,1348,882],{"class":75},[35,1350,793],{"class":95},[35,1352,173],{"class":75},[35,1354,793],{"class":95},[35,1356,767],{"class":71},[35,1358,1359],{"class":95}," len",[35,1361,882],{"class":75},[35,1363,162],{"class":95},[35,1365,1121],{"class":75},[35,1367,1305],{"class":71},[35,1369,1370],{"class":95}," 2",[35,1372,1373],{"class":75},"):\n",[35,1375,1377,1380,1382,1385,1388],{"class":37,"line":1376},15,[35,1378,1379],{"class":75},"    letter ",[35,1381,117],{"class":71},[35,1383,1384],{"class":75}," ws.cell(",[35,1386,1387],{"class":95},"3",[35,1389,1390],{"class":75},", col).column_letter\n",[35,1392,1394,1397,1399,1401,1404,1406,1409,1411,1414,1416,1419,1421,1423,1426,1429,1431,1434,1436,1438,1440,1442,1444,1446],{"class":37,"line":1393},16,[35,1395,1396],{"class":75},"    ws.cell(last ",[35,1398,1305],{"class":71},[35,1400,1308],{"class":95},[35,1402,1403],{"class":75},", col, ",[35,1405,885],{"class":71},[35,1407,1408],{"class":45},"\"=SUM(",[35,1410,892],{"class":891},[35,1412,1413],{"class":75},"letter",[35,1415,907],{"class":891},[35,1417,1418],{"class":45},"4:",[35,1420,892],{"class":891},[35,1422,1413],{"class":75},[35,1424,1425],{"class":891},"}{",[35,1427,1428],{"class":75},"last",[35,1430,907],{"class":891},[35,1432,1433],{"class":45},")\"",[35,1435,1319],{"class":75},[35,1437,117],{"class":71},[35,1439,1265],{"class":75},[35,1441,1268],{"class":217},[35,1443,117],{"class":71},[35,1445,1273],{"class":95},[35,1447,108],{"class":75},[35,1449,1451,1453,1455,1458,1460,1462,1464,1467,1470,1472,1474,1476,1478,1480,1482,1484,1486,1489,1491],{"class":37,"line":1450},17,[35,1452,1302],{"class":75},[35,1454,1305],{"class":71},[35,1456,1457],{"class":95}," 3",[35,1459,173],{"class":75},[35,1461,604],{"class":95},[35,1463,173],{"class":75},[35,1465,1466],{"class":45},"\"Control account\"",[35,1468,1469],{"class":75},"), ws.cell(last ",[35,1471,1305],{"class":71},[35,1473,1457],{"class":95},[35,1475,173],{"class":75},[35,1477,793],{"class":95},[35,1479,767],{"class":71},[35,1481,1359],{"class":95},[35,1483,882],{"class":75},[35,1485,162],{"class":95},[35,1487,1488],{"class":75},"), ",[35,1490,842],{"class":95},[35,1492,108],{"class":75},[35,1494,1496,1498,1500,1503,1505,1507,1509,1512,1514,1516,1518,1520,1522,1524,1526,1528,1530,1532,1534,1537,1539,1541,1543,1545,1547,1549,1551,1553,1555,1557,1560,1562,1564,1566,1568,1570,1572,1574,1576,1578,1580,1582,1584,1586,1588,1590],{"class":37,"line":1495},18,[35,1497,1302],{"class":75},[35,1499,1305],{"class":71},[35,1501,1502],{"class":95}," 4",[35,1504,173],{"class":75},[35,1506,604],{"class":95},[35,1508,173],{"class":75},[35,1510,1511],{"class":45},"\"Difference\"",[35,1513,1469],{"class":75},[35,1515,1305],{"class":71},[35,1517,1502],{"class":95},[35,1519,173],{"class":75},[35,1521,793],{"class":95},[35,1523,767],{"class":71},[35,1525,1359],{"class":95},[35,1527,882],{"class":75},[35,1529,162],{"class":95},[35,1531,1488],{"class":75},[35,1533,885],{"class":71},[35,1535,1536],{"class":45},"\"=",[35,1538,892],{"class":891},[35,1540,1302],{"class":75},[35,1542,1305],{"class":71},[35,1544,1308],{"class":95},[35,1546,173],{"class":75},[35,1548,793],{"class":95},[35,1550,767],{"class":71},[35,1552,1359],{"class":95},[35,1554,882],{"class":75},[35,1556,162],{"class":95},[35,1558,1559],{"class":75},")).coordinate",[35,1561,907],{"class":891},[35,1563,226],{"class":45},[35,1565,892],{"class":891},[35,1567,1302],{"class":75},[35,1569,1305],{"class":71},[35,1571,1457],{"class":95},[35,1573,173],{"class":75},[35,1575,793],{"class":95},[35,1577,767],{"class":71},[35,1579,1359],{"class":95},[35,1581,882],{"class":75},[35,1583,162],{"class":95},[35,1585,1559],{"class":75},[35,1587,907],{"class":891},[35,1589,933],{"class":45},[35,1591,108],{"class":75},[35,1593,1595,1598,1600,1603,1606,1608,1611,1613,1616],{"class":37,"line":1594},19,[35,1596,1597],{"class":75},"late ",[35,1599,117],{"class":71},[35,1601,1602],{"class":75}," PatternFill(",[35,1604,1605],{"class":45},"\"solid\"",[35,1607,173],{"class":75},[35,1609,1610],{"class":217},"fgColor",[35,1612,117],{"class":71},[35,1614,1615],{"class":45},"\"FCE4D6\"",[35,1617,108],{"class":75},[35,1619,1621,1623,1626,1628,1631,1634,1636,1638,1640,1643,1645,1647,1649,1651,1653,1656,1658,1660,1662,1665,1667],{"class":37,"line":1620},20,[35,1622,1337],{"class":71},[35,1624,1625],{"class":75}," row ",[35,1627,1343],{"class":71},[35,1629,1630],{"class":75}," ws.iter_rows(",[35,1632,1633],{"class":217},"min_row",[35,1635,117],{"class":71},[35,1637,394],{"class":95},[35,1639,173],{"class":75},[35,1641,1642],{"class":217},"max_row",[35,1644,117],{"class":71},[35,1646,1291],{"class":75},[35,1648,1305],{"class":71},[35,1650,1502],{"class":95},[35,1652,173],{"class":75},[35,1654,1655],{"class":217},"min_col",[35,1657,117],{"class":71},[35,1659,793],{"class":95},[35,1661,173],{"class":75},[35,1663,1664],{"class":217},"max_col",[35,1666,117],{"class":71},[35,1668,1669],{"class":75},"ws.max_column):\n",[35,1671,1673,1676,1679,1681],{"class":37,"line":1672},21,[35,1674,1675],{"class":71},"    for",[35,1677,1678],{"class":75}," cell ",[35,1680,1343],{"class":71},[35,1682,1683],{"class":75}," row:\n",[35,1685,1687,1690,1692,1695,1698,1700,1702,1705,1708,1711,1714],{"class":37,"line":1686},22,[35,1688,1689],{"class":75},"        cell.number_format ",[35,1691,117],{"class":71},[35,1693,1694],{"class":45}," \"0.0%\"",[35,1696,1697],{"class":71}," if",[35,1699,1384],{"class":75},[35,1701,1387],{"class":95},[35,1703,1704],{"class":75},", cell.column).value ",[35,1706,1707],{"class":71},"==",[35,1709,1710],{"class":45}," \"Overdue %\"",[35,1712,1713],{"class":71}," else",[35,1715,1716],{"class":45}," \"#,##0.00;[Red]-#,##0.00;-\"\n",[35,1718,1720,1723,1725,1727,1729,1731,1733,1735,1737,1739,1741,1744,1747,1750,1753,1755,1758,1761,1763,1766,1768,1770],{"class":37,"line":1719},23,[35,1721,1722],{"class":71},"        if",[35,1724,1384],{"class":75},[35,1726,1387],{"class":95},[35,1728,1704],{"class":75},[35,1730,1343],{"class":71},[35,1732,142],{"class":75},[35,1734,186],{"class":45},[35,1736,173],{"class":75},[35,1738,191],{"class":45},[35,1740,1121],{"class":75},[35,1742,1743],{"class":71},"and",[35,1745,1746],{"class":95}," isinstance",[35,1748,1749],{"class":75},"(cell.value, (",[35,1751,1752],{"class":95},"int",[35,1754,173],{"class":75},[35,1756,1757],{"class":95},"float",[35,1759,1760],{"class":75},")) ",[35,1762,1743],{"class":71},[35,1764,1765],{"class":75}," cell.value ",[35,1767,672],{"class":71},[35,1769,675],{"class":95},[35,1771,1772],{"class":75},":\n",[35,1774,1776,1779,1781],{"class":37,"line":1775},24,[35,1777,1778],{"class":75},"            cell.fill ",[35,1780,117],{"class":71},[35,1782,1783],{"class":75}," late\n",[35,1785,1787,1790,1793,1796,1798],{"class":37,"line":1786},25,[35,1788,1789],{"class":75},"ws.column_dimensions[",[35,1791,1792],{"class":45},"\"A\"",[35,1794,1795],{"class":75},"].width ",[35,1797,117],{"class":71},[35,1799,1800],{"class":95}," 24\n",[35,1802,1804],{"class":37,"line":1803},26,[35,1805,1806],{"class":75},"wb.save(path)\n",[35,1808,1810,1812],{"class":37,"line":1809},27,[35,1811,302],{"class":95},[35,1813,1814],{"class":75},"(wb.sheetnames)\n",[10,1816,1817,1818,1821,1822,1825,1826,18],{},"The summary sheet has a title stating the date and the ageing basis, the supplier rows, a total row with ",[32,1819,1820],{},"SUM"," formulas — so anyone who adjusts a figure sees the total follow — and the control account and difference beneath. Amounts more than 60 days overdue are shaded, negatives show in red and zeros as dashes. The ",[353,1823,1824],{},"Open items"," sheet lists every document behind the figures, sorted by supplier and due date, so each number can be traced. The receivables equivalent, with its dunning follow-up, is in ",[14,1827,1829],{"href":1828},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-accounts-receivable-aging-report\u002F","Build an Accounts Receivable Aging Report",[373,1831,382,1836,382,1839,382,1842,382,1845,382,1849,382,1860,382,1865,382,1870,382,1874,382,1878,382,1883,382,1888,382,1891,382,1898,382,1903,382,1907,382,1910,382,1912,382,1916,382,1919,382,1922,382,1929,382,1934,382,1938,382,1942,382,1946,382,1949,382,1952,382,1959,382,1964,382,1967,382,1970,382,1974,382,1977,382,1980,382,1986,382,1990,382,1994],{"viewBox":1832,"role":376,"ariaLabelledBy":1833,"xmlns":380,"style":381},"4 0 752 160",[1834,1835],"ap-flow-t","ap-flow-d",[384,1837,1838],{"id":1834},"Building the aged creditors report",[388,1840,1841],{"id":1835},"Load the open payables listing, compute days past due, assign ageing buckets with credits in current, pivot by supplier with overdue and disputed columns, reconcile the total to the control account and write a formatted workbook with the open items behind it.",[392,1843],{"x":394,"y":234,"width":395,"height":1844,"fill":397},"160",[392,1846],{"x":407,"y":408,"width":1847,"height":1848,"rx":411,"fill":438,"stroke":439,"style":414},"115.2","128.0",[1850,1851,1853],"g",{"transform":1852},"translate(65.6,29.0) scale(1.000)",[1854,1855],"path",{"d":1856,"fill":1857,"stroke":1858,"style":1859},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[416,1861,1824],{"x":1862,"y":1863,"style":1864},"77.6","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[416,1866,1869],{"x":1862,"y":1867,"style":1868},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","invoices,",[416,1871,1873],{"x":1862,"y":1872,"style":1868},"112.5","credits,",[416,1875,1877],{"x":1862,"y":1876,"style":1868},"130.0","payments",[37,1879],{"x1":1880,"y1":1881,"x2":1882,"y2":1881,"stroke":488,"style":414},"140.2","80.0","162.2",[1884,1885],"polygon",{"points":1886,"fill":1887},"166.2,80.0 157.2,85.0 157.2,75.0","#5b5cf0",[392,1889],{"x":1890,"y":408,"width":1847,"height":1848,"rx":411,"fill":487,"stroke":488,"style":414},"171.2",[1850,1892,1894],{"transform":1893},"translate(216.8,29.0) scale(1.000)",[1854,1895],{"d":1896,"fill":1857,"stroke":1897,"style":1859},"M4 5h16v15H4z M4 10h16 M8 3v4 M16 3v4","var(--brand-strong,#4338ca)",[416,1899,1902],{"x":1900,"y":1863,"style":1901},"228.8","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Days past",[416,1904,1906],{"x":1900,"y":1905,"style":1901},"93.0","due",[416,1908,1909],{"x":1900,"y":1872,"style":1868},"report date −",[416,1911,355],{"x":1900,"y":1876,"style":1868},[37,1913],{"x1":1914,"y1":1881,"x2":1915,"y2":1881,"stroke":488,"style":414},"291.4","313.4",[1884,1917],{"points":1918,"fill":1887},"317.4,80.0 308.4,85.0 308.4,75.0",[392,1920],{"x":1921,"y":408,"width":1847,"height":1848,"rx":411,"fill":456,"stroke":457,"style":414},"322.4",[1850,1923,1925],{"transform":1924},"translate(368.0,37.8) scale(1.000)",[1854,1926],{"d":1927,"fill":1857,"stroke":1928,"style":1859},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5","var(--gold-ink,#7a4e06)",[416,1930,1933],{"x":460,"y":1931,"style":1932},"84.2","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Buckets",[416,1935,1937],{"x":460,"y":1936,"style":1868},"103.8","pd.cut, credits",[416,1939,1941],{"x":460,"y":1940,"style":1868},"121.2","current",[37,1943],{"x1":1944,"y1":1881,"x2":1945,"y2":1881,"stroke":488,"style":414},"442.6","464.6",[1884,1947],{"points":1948,"fill":1887},"468.6,80.0 459.6,85.0 459.6,75.0",[392,1950],{"x":1951,"y":408,"width":1847,"height":1848,"rx":411,"fill":412,"stroke":413,"style":414},"473.6",[1850,1953,1955],{"transform":1954},"translate(519.2,37.8) scale(1.000)",[1854,1956],{"d":1957,"fill":1857,"stroke":1958,"style":1859},"M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z M2.5 20c0-3.6 2.9-6 6.5-6s6.5 2.4 6.5 6 M16 4.5a3.3 3.3 0 0 1 0 6.3 M18 14.3c2.2.7 3.5 2.8 3.5 5.7","var(--teal-ink,#0b6157)",[416,1960,1963],{"x":1961,"y":1931,"style":1962},"531.2","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","By supplier",[416,1965,1966],{"x":1961,"y":1936,"style":1868},"overdue, in",[416,1968,1969],{"x":1961,"y":1940,"style":1868},"dispute",[37,1971],{"x1":1972,"y1":1881,"x2":1973,"y2":1881,"stroke":488,"style":414},"593.8","615.8",[1884,1975],{"points":1976,"fill":1887},"619.8,80.0 610.8,85.0 610.8,75.0",[392,1978],{"x":1979,"y":408,"width":1847,"height":1848,"rx":411,"fill":438,"stroke":439,"style":414},"624.8",[1850,1981,1983],{"transform":1982},"translate(670.4,37.8) scale(1.000)",[1854,1984],{"d":1985,"fill":1857,"stroke":1858,"style":1859},"M5 12.5l4.5 4.5L19 7",[416,1987,1989],{"x":1988,"y":1931,"style":1864},"682.4","Reconcile +",[416,1991,1993],{"x":1988,"y":1992,"style":1864},"101.8","write",[416,1995,1996],{"x":1988,"y":1940,"style":1868},"control account",[20,1998,2000],{"id":1999},"reading-the-report","Reading the report",[10,2002,2003],{},"A good aged creditors report is read top-down. Start at the reconciliation: if the difference is not zero, nothing below can be relied on. Then look at the old buckets. Amounts over 90 days are rarely just slow payment — here the Fjord IT invoice from May is probably a missing approval, a goods-received problem or an invoice nobody can match, and each such line deserves a named owner and a date. Amounts in dispute should have a matching query log. Then check the negatives: credit notes and payments on account that have sat unallocated for weeks are money the company is entitled to use, and they often signal duplicate payments or invoices that were paid without being matched. Finally, the current column is the cash requirement for the coming weeks, which is what the next payment run will draw on.",[20,2005,2007],{"id":2006},"common-pitfalls","Common pitfalls",[2009,2010,2011,2021,2027,2036,2042],"ul",{},[2012,2013,2014,2018,2019,18],"li",{},[2015,2016,2017],"strong",{},"Ageing credits."," Keep credit notes and payments on account as negatives in ",[353,2020,363],{},[2012,2022,2023,2026],{},[2015,2024,2025],{},"Mixing ageing bases."," Age by due date or document date, and say which.",[2012,2028,2029,2032,2033,2035],{},[2015,2030,2031],{},"Missing buckets."," Use a categorical with ",[32,2034,814],{}," so every column always appears.",[2012,2037,2038,2041],{},[2015,2039,2040],{},"No reconciliation."," The ageing total must match the control account.",[2012,2043,2044,2047],{},[2015,2045,2046],{},"Disputes hidden among overdue items."," Show them in their own column.",[20,2049,2051],{"id":2050},"conclusion","Conclusion",[10,2053,2054,2055,2057,2058,2060],{},"An aged creditors report ages each open payable by its due date into current, 1–30, 31–60, 61–90 and 90+ day buckets with ",[32,2056,359],{},", keeps credit notes and unallocated payments as negatives in ",[353,2059,363],{},", pivots by supplier with total, overdue and in-dispute columns, and reconciles its total to the payables control account. Written to Excel with formula totals, highlighted old balances and the open items behind them, it supports payment planning, supplier conversations and month-end close.",[20,2062,2064],{"id":2063},"frequently-asked-questions","Frequently asked questions",[10,2066,2067,2070],{},[2015,2068,2069],{},"How do I age accounts payable in pandas?","\nSubtract each item's due date from the report date to get days overdue, then use pd.cut with bucket edges such as 0, 30, 60 and 90 days to assign an ageing bucket.",[10,2072,2073,2076],{},[2015,2074,2075],{},"Where do credit notes go in an aged creditors report?","\nKeep them as negative amounts, usually in the current column, so they reduce what is owed without appearing overdue.",[10,2078,2079,2082],{},[2015,2080,2081],{},"Should payables be aged by invoice date or due date?","\nDue date shows how late payments are and is the usual choice for payment planning; invoice date shows the age of the debt. State which one the report uses.",[10,2084,2085,2088],{},[2015,2086,2087],{},"How do I check the aged creditors report is complete?","\nReconcile its total to the accounts payable control account in the general ledger; any difference means items are missing from one side.",[20,2090,2092],{"id":2091},"related","Related",[2009,2094,2095,2101,2108,2115],{},[2012,2096,2097,2098,2100],{},"Up one level: ",[14,2099,17],{"href":16}," — finance reports from Python.",[2012,2102,2103,2107],{},[14,2104,2106],{"href":2105},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-supplier-payment-run-proposal\u002F","Build a Supplier Payment Run Proposal"," — paying what the report shows is due.",[2012,2109,2110,2114],{},[14,2111,2113],{"href":2112},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fdetect-possible-duplicate-invoices\u002F","Detect Possible Duplicate Invoices"," — checking the open items first.",[2012,2116,2117,2119],{},[14,2118,1829],{"href":1828}," — the receivables side.",[2121,2122,2123],"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 .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":30,"searchDepth":85,"depth":85,"links":2125},[2126,2127,2128,2129,2130,2131,2132,2133,2134,2135],{"id":22,"depth":85,"text":23},{"id":58,"depth":85,"text":59},{"id":503,"depth":85,"text":504},{"id":828,"depth":85,"text":829},{"id":1038,"depth":85,"text":1039},{"id":1999,"depth":85,"text":2000},{"id":2006,"depth":85,"text":2007},{"id":2050,"depth":85,"text":2051},{"id":2063,"depth":85,"text":2064},{"id":2091,"depth":85,"text":2092},"2026-10-02","Build an aged creditors (accounts payable ageing) report from an open payables export with pandas and openpyxl: age every open invoice, credit note and unallocated payment by due date into current, 1–30, 31–60, 61–90 and over-90-day buckets, show credits as negatives, mark disputed items, summarise by supplier, reconcile to the payables control account and highlight what is overdue.","md",[2140,2142,2144,2146],{"q":2069,"a":2141},"Subtract each item's due date from the report date to get days overdue, then use pd.cut with bucket edges such as 0, 30, 60 and 90 days to assign an ageing bucket.",{"q":2075,"a":2143},"Keep them as negative amounts, usually in the current column, so they reduce what is owed without appearing overdue.",{"q":2081,"a":2145},"Due date shows how late payments are and is the usual choice for payment planning; invoice date shows the age of the debt. State which one the report uses.",{"q":2087,"a":2147},"Reconcile its total to the accounts payable control account in the general ledger; any difference means items are missing from one side.","aged creditors report python",null,{"breadcrumb":2151},[2152,2154,2157],{"name":2153,"item":658},"Home",{"name":2155,"item":2156},"Automating Reporting Workflows with Python and Excel","\u002Fautomating-reporting-workflows\u002F",{"name":2158,"item":16},"Building Finance and Operations Reports in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report",{"title":2161,"description":2162},"Build an Aged Creditors (AP Ageing) Report with Python","Accounts payable ageing with pandas: days overdue by due date, ageing buckets with pd.cut, credit notes and unallocated payments as negatives, disputed items, supplier summary, reconciliation to the control account and an Excel report.","build-an-aged-creditors-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-aged-creditors-report\u002Findex",[2166,2167],"report-layouts","pivots-and-summaries","how-to","49tT16kfkiRGaep48iqr43whM4pE8uy9QfPhjnFT5wo",[2171,2175],{"title":2172,"path":2173,"stem":2174,"children":-1},"Build an Accruals and Prepayments Schedule","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-accruals-and-prepayments-schedule","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-accruals-and-prepayments-schedule\u002Findex",{"title":2176,"path":2177,"stem":2178,"children":-1},"Build an Employee Leave Balance Report","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-an-employee-leave-balance-report\u002Findex",[2180,2182],{"path":2181,"title":2158},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports",{"path":2183,"title":2155},"\u002Fautomating-reporting-workflows",[],[2186,2190,2193,2196,2199,2202],{"path":2187,"title":2188,"kind":2189},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards","Building Multi-Sheet Excel Dashboards","guide",{"path":2191,"title":2192,"kind":2168},"\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":2194,"title":2195,"kind":2168},"\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":2197,"title":2198,"kind":2168},"\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":2200,"title":2201,"kind":2168},"\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":2203,"title":2204,"kind":2168},"\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",1790972127636]