[{"data":1,"prerenderedAt":3187},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fixed-asset-depreciation-schedule":3,"surround:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fixed-asset-depreciation-schedule":3152,"ancestors:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fixed-asset-depreciation-schedule":3161,"children:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fixed-asset-depreciation-schedule":3166,"related:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fixed-asset-depreciation-schedule":3167},{"id":4,"title":5,"body":6,"dateModified":3118,"datePublished":3118,"description":3119,"extension":3120,"faq":3121,"keyword":3130,"kind":3131,"meta":3132,"navigation":326,"path":3141,"seo":3142,"slug":3145,"stem":3146,"topics":3147,"type":3150,"__hash__":3151},"docs\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fixed-asset-depreciation-schedule\u002Findex.md","Build a Fixed Asset Depreciation Schedule with Python",{"type":7,"value":8,"toc":3104},"minimark",[9,19,24,53,67,71,74,101,291,295,298,845,856,860,863,1070,1358,1361,1365,1368,1558,1561,1565,1568,2056,2059,2201,2205,2224,2502,2556,2713,2731,2735,2747,2981,2985,3020,3024,3034,3038,3044,3050,3056,3062,3066,3100],[10,11,12,13,18],"p",{},"The fixed asset register is a list; the depreciation schedule is what turns it into numbers for the accounts: how much each asset depreciates each month, what it is worth at the year end, and how the totals moved from opening to closing. Spreadsheets that do this by hand grow a column per month and a formula per cell, and break when an asset is sold mid-year or someone copies a formula one row too far. Python computes every asset's monthly charge from a few rules, and the output is a schedule the auditors can follow. This page is part of ",[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,58,59,62,63,66],{},[32,56,57],{},"asset_register.xlsx"," lists eight assets with their in-service date, cost, salvage (residual) value, useful life in months and method: ",[32,60,61],{},"SL"," for straight line, ",[32,64,65],{},"DDB"," for double-declining balance. One asset, the company car, was sold on 31 August 2026. The schedule is for the financial year January to December 2026.",[20,68,70],{"id":69},"the-rules","The rules",[10,72,73],{},"Three decisions shape every number, and they belong at the top of the script where an accountant can read them:",[75,76,77,85,95],"ul",{},[78,79,80,84],"li",{},[81,82,83],"strong",{},"When depreciation starts."," Here: the month after the asset is put into service (full-month convention). Other common choices are the month of purchase or a half-month in the first month.",[78,86,87,90,91,94],{},[81,88,89],{},"Declining balance."," Double-declining balance charges ",[32,92,93],{},"2 \u002F life"," of the current book value each period and switches to straight line over the remaining life once that gives the larger charge, so the asset reaches its salvage value exactly at the end of its life.",[78,96,97,100],{},[81,98,99],{},"Disposals."," Depreciation runs up to and including the month of disposal; after that the asset leaves the register, and the gain or loss is the proceeds minus the book value at that point.",[102,103,111,112,111,116,111,120,111,128,111,137,111,144,111,149,111,153,111,160,111,166,111,170,111,174,111,177,111,181,111,184,111,188,111,191,111,197,111,201,111,205,111,209,111,213,111,219,111,225,111,228,111,231,111,234,111,237,111,242,111,246,111,250,111,254,111,258,111,261,111,263,111,266,111,269,111,272,111,274,111,277,111,281,111,285,111,289],"svg",{"viewBox":104,"role":105,"ariaLabelledBy":106,"xmlns":109,"style":110},"4 0 748 280","img",[107,108],"fa-methods-t","fa-methods-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:748px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[113,114,115],"title",{"id":107},"Book value of a 21,900 server rack under each method",[117,118,119],"desc",{"id":108},"A line chart of the net book value of a server rack costing 21,900 with 1,500 salvage over 48 months, at yearly points. Straight line falls evenly, 5,100 a year, to 1,500. Double-declining balance falls faster in the first two years, switches to straight line in month 31, and reaches the same 1,500 at the end of year four.",[121,122],"rect",{"x":123,"y":124,"width":125,"height":126,"fill":127},"4","0","748","280","#ffffff",[121,129],{"x":130,"y":131,"width":132,"height":132,"rx":133,"fill":134,"stroke":135,"style":136},"64.0","18.0","14.0","3","#d9f4f1","var(--teal,#0f9488)","stroke-width:1.5px",[138,139,143],"text",{"x":140,"y":141,"style":142},"84.0","29.5","font-size:12px;font-weight:600;fill:var(--text,#172033);text-anchor:start","Straight line",[121,145],{"x":146,"y":131,"width":132,"height":132,"rx":133,"fill":147,"stroke":148,"style":136},"186.3","#f0f4ff","var(--brand,#5b5cf0)",[138,150,152],{"x":151,"y":141,"style":142},"206.3","Double-declining",[37,154],{"x1":155,"y1":156,"x2":157,"y2":156,"stroke":158,"style":159},"52.8","242.0","736.0","var(--line,#cdd5e6)","stroke-width:1px",[138,161,165],{"x":162,"y":163,"style":164},"30.4","246.0","font-size:11px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","0k",[37,167],{"x1":155,"y1":168,"x2":157,"y2":168,"stroke":158,"style":169},"178.7","stroke-width:1px;stroke-dasharray:5 4",[138,171,173],{"x":162,"y":172,"style":164},"182.7","10k",[37,175],{"x1":155,"y1":176,"x2":157,"y2":176,"stroke":158,"style":169},"115.3",[138,178,180],{"x":162,"y":179,"style":164},"119.3","20k",[37,182],{"x1":155,"y1":183,"x2":157,"y2":183,"stroke":158,"style":169},"52.0",[138,185,187],{"x":162,"y":186,"style":164},"56.0","30k",[37,189],{"x1":155,"y1":156,"x2":157,"y2":156,"stroke":190,"style":136},"var(--muted,#5b6780)",[138,192,196],{"x":193,"y":194,"style":195},"121.1","260.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Start",[138,198,200],{"x":199,"y":194,"style":195},"257.7","Year 1",[138,202,204],{"x":203,"y":194,"style":195},"394.4","Year 2",[138,206,208],{"x":207,"y":194,"style":195},"531.0","Year 3",[138,210,212],{"x":211,"y":194,"style":195},"667.7","Year 4",[214,215],"path",{"d":216,"fill":217,"stroke":135,"style":218},"M121.1,103.3 L257.7,135.6 L394.4,167.9 L531.0,200.2 L667.7,232.5","none","stroke-width:2.5px;stroke-linejoin:round;stroke-linecap:round",[220,221],"circle",{"cx":193,"cy":222,"r":223,"fill":127,"stroke":135,"style":224},"103.3","4.0","stroke-width:2px",[220,226],{"cx":199,"cy":227,"r":223,"fill":127,"stroke":135,"style":224},"135.6",[220,229],{"cx":203,"cy":230,"r":223,"fill":127,"stroke":135,"style":224},"167.9",[220,232],{"cx":207,"cy":233,"r":223,"fill":127,"stroke":135,"style":224},"200.2",[220,235],{"cx":211,"cy":236,"r":223,"fill":127,"stroke":135,"style":224},"232.5",[138,238,241],{"x":193,"y":239,"style":240},"93.3","font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","21.9",[138,243,245],{"x":199,"y":244,"style":240},"125.6","16.8",[138,247,249],{"x":203,"y":248,"style":240},"157.9","11.7",[138,251,253],{"x":207,"y":252,"style":240},"190.2","6.6",[138,255,257],{"x":211,"y":256,"style":240},"222.5","1.5",[214,259],{"d":260,"fill":217,"stroke":148,"style":218},"M121.1,103.3 L257.7,159.0 L394.4,192.0 L531.0,212.9 L667.7,232.5",[220,262],{"cx":193,"cy":222,"r":223,"fill":127,"stroke":148,"style":224},[220,264],{"cx":199,"cy":265,"r":223,"fill":127,"stroke":148,"style":224},"159.0",[220,267],{"cx":203,"cy":268,"r":223,"fill":127,"stroke":148,"style":224},"192.0",[220,270],{"cx":207,"cy":271,"r":223,"fill":127,"stroke":148,"style":224},"212.9",[220,273],{"cx":211,"cy":236,"r":223,"fill":127,"stroke":148,"style":224},[138,275,241],{"x":193,"y":239,"style":276},"font-size:10.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[138,278,280],{"x":199,"y":279,"style":276},"149.0","13.1",[138,282,284],{"x":203,"y":283,"style":276},"182.0","7.9",[138,286,288],{"x":207,"y":287,"style":276},"202.9","4.6",[138,290,257],{"x":211,"y":256,"style":276},[20,292,294],{"id":293},"step-1-one-function-for-any-asset-and-month","Step 1 — One function for any asset and month",[10,296,297],{},"Compute each asset's full life, month by month, then keep the months of the year being reported. Computing the full life, rather than only this year, is what makes declining balance correct: this year's charge depends on every charge before it.",[25,299,303],{"className":300,"code":301,"language":302,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nregister = pd.read_excel(\"asset_register.xlsx\", parse_dates=[\"InService\", \"Disposed\"])\nYEAR_START, YEAR_END = pd.Period(\"2026-01\", \"M\"), pd.Period(\"2026-12\", \"M\")\n\ndef monthly_schedule(asset):\n    \"\"\"Depreciation for every month of the asset's life, as a DataFrame.\"\"\"\n    first = asset.InService.to_period(\"M\") + 1            # full-month convention\n    cost, salvage, life = asset.Cost, asset.Salvage, int(asset.LifeMonths)\n    rows, book = [], cost\n    for i in range(life):\n        remaining = life - i\n        straight = (book - salvage) \u002F remaining\n        if asset.Method == \"DDB\":\n            charge = max(book * 2 \u002F life, straight)          # switch when straight line is larger\n            charge = min(charge, book - salvage)             # never below salvage\n        else:\n            charge = (cost - salvage) \u002F life\n        book -= charge\n        rows.append((first + i, charge, book))\n    out = pd.DataFrame(rows, columns=[\"Month\", \"Depreciation\", \"BookValue\"])\n    out.insert(0, \"AssetID\", asset.AssetID)\n    if pd.notna(asset.Disposed):\n        out = out[out[\"Month\"] \u003C= asset.Disposed.to_period(\"M\")]\n    return out\n\nlife = pd.concat([monthly_schedule(a) for a in register.itertuples()], ignore_index=True)\nprint(life[life[\"AssetID\"] == \"FA-104\"].head(3).round({\"Depreciation\": 2, \"BookValue\": 2}).to_string(index=False))\n","python",[32,304,305,321,328,366,405,410,423,429,455,472,483,501,518,540,558,587,608,616,635,647,658,691,707,716,743,752,757,789],{"__ignoreMap":30},[35,306,307,311,315,318],{"class":37,"line":38},[35,308,310],{"class":309},"s-kum","import",[35,312,314],{"class":313},"skGVy"," pandas ",[35,316,317],{"class":309},"as",[35,319,320],{"class":313}," pd\n",[35,322,324],{"class":37,"line":323},2,[35,325,327],{"emptyLinePlaceholder":326},true,"\n",[35,329,331,334,337,340,343,346,350,352,355,358,360,363],{"class":37,"line":330},3,[35,332,333],{"class":313},"register ",[35,335,336],{"class":309},"=",[35,338,339],{"class":313}," pd.read_excel(",[35,341,342],{"class":45},"\"asset_register.xlsx\"",[35,344,345],{"class":313},", ",[35,347,349],{"class":348},"sa561","parse_dates",[35,351,336],{"class":309},[35,353,354],{"class":313},"[",[35,356,357],{"class":45},"\"InService\"",[35,359,345],{"class":313},[35,361,362],{"class":45},"\"Disposed\"",[35,364,365],{"class":313},"])\n",[35,367,369,373,375,378,381,384,387,389,392,395,398,400,402],{"class":37,"line":368},4,[35,370,372],{"class":371},"sP0c6","YEAR_START",[35,374,345],{"class":313},[35,376,377],{"class":371},"YEAR_END",[35,379,380],{"class":309}," =",[35,382,383],{"class":313}," pd.Period(",[35,385,386],{"class":45},"\"2026-01\"",[35,388,345],{"class":313},[35,390,391],{"class":45},"\"M\"",[35,393,394],{"class":313},"), pd.Period(",[35,396,397],{"class":45},"\"2026-12\"",[35,399,345],{"class":313},[35,401,391],{"class":45},[35,403,404],{"class":313},")\n",[35,406,408],{"class":37,"line":407},5,[35,409,327],{"emptyLinePlaceholder":326},[35,411,413,416,420],{"class":37,"line":412},6,[35,414,415],{"class":309},"def",[35,417,419],{"class":418},"s_Opv"," monthly_schedule",[35,421,422],{"class":313},"(asset):\n",[35,424,426],{"class":37,"line":425},7,[35,427,428],{"class":45},"    \"\"\"Depreciation for every month of the asset's life, as a DataFrame.\"\"\"\n",[35,430,432,435,437,440,442,445,448,451],{"class":37,"line":431},8,[35,433,434],{"class":313},"    first ",[35,436,336],{"class":309},[35,438,439],{"class":313}," asset.InService.to_period(",[35,441,391],{"class":45},[35,443,444],{"class":313},") ",[35,446,447],{"class":309},"+",[35,449,450],{"class":371}," 1",[35,452,454],{"class":453},"s-wDw","            # full-month convention\n",[35,456,458,461,463,466,469],{"class":37,"line":457},9,[35,459,460],{"class":313},"    cost, salvage, life ",[35,462,336],{"class":309},[35,464,465],{"class":313}," asset.Cost, asset.Salvage, ",[35,467,468],{"class":371},"int",[35,470,471],{"class":313},"(asset.LifeMonths)\n",[35,473,475,478,480],{"class":37,"line":474},10,[35,476,477],{"class":313},"    rows, book ",[35,479,336],{"class":309},[35,481,482],{"class":313}," [], cost\n",[35,484,486,489,492,495,498],{"class":37,"line":485},11,[35,487,488],{"class":309},"    for",[35,490,491],{"class":313}," i ",[35,493,494],{"class":309},"in",[35,496,497],{"class":371}," range",[35,499,500],{"class":313},"(life):\n",[35,502,504,507,509,512,515],{"class":37,"line":503},12,[35,505,506],{"class":313},"        remaining ",[35,508,336],{"class":309},[35,510,511],{"class":313}," life ",[35,513,514],{"class":309},"-",[35,516,517],{"class":313}," i\n",[35,519,521,524,526,529,531,534,537],{"class":37,"line":520},13,[35,522,523],{"class":313},"        straight ",[35,525,336],{"class":309},[35,527,528],{"class":313}," (book ",[35,530,514],{"class":309},[35,532,533],{"class":313}," salvage) ",[35,535,536],{"class":309},"\u002F",[35,538,539],{"class":313}," remaining\n",[35,541,543,546,549,552,555],{"class":37,"line":542},14,[35,544,545],{"class":309},"        if",[35,547,548],{"class":313}," asset.Method ",[35,550,551],{"class":309},"==",[35,553,554],{"class":45}," \"DDB\"",[35,556,557],{"class":313},":\n",[35,559,561,564,566,569,572,575,578,581,584],{"class":37,"line":560},15,[35,562,563],{"class":313},"            charge ",[35,565,336],{"class":309},[35,567,568],{"class":371}," max",[35,570,571],{"class":313},"(book ",[35,573,574],{"class":309},"*",[35,576,577],{"class":371}," 2",[35,579,580],{"class":309}," \u002F",[35,582,583],{"class":313}," life, straight)          ",[35,585,586],{"class":453},"# switch when straight line is larger\n",[35,588,590,592,594,597,600,602,605],{"class":37,"line":589},16,[35,591,563],{"class":313},[35,593,336],{"class":309},[35,595,596],{"class":371}," min",[35,598,599],{"class":313},"(charge, book ",[35,601,514],{"class":309},[35,603,604],{"class":313}," salvage)             ",[35,606,607],{"class":453},"# never below salvage\n",[35,609,611,614],{"class":37,"line":610},17,[35,612,613],{"class":309},"        else",[35,615,557],{"class":313},[35,617,619,621,623,626,628,630,632],{"class":37,"line":618},18,[35,620,563],{"class":313},[35,622,336],{"class":309},[35,624,625],{"class":313}," (cost ",[35,627,514],{"class":309},[35,629,533],{"class":313},[35,631,536],{"class":309},[35,633,634],{"class":313}," life\n",[35,636,638,641,644],{"class":37,"line":637},19,[35,639,640],{"class":313},"        book ",[35,642,643],{"class":309},"-=",[35,645,646],{"class":313}," charge\n",[35,648,650,653,655],{"class":37,"line":649},20,[35,651,652],{"class":313},"        rows.append((first ",[35,654,447],{"class":309},[35,656,657],{"class":313}," i, charge, book))\n",[35,659,661,664,666,669,672,674,676,679,681,684,686,689],{"class":37,"line":660},21,[35,662,663],{"class":313},"    out ",[35,665,336],{"class":309},[35,667,668],{"class":313}," pd.DataFrame(rows, ",[35,670,671],{"class":348},"columns",[35,673,336],{"class":309},[35,675,354],{"class":313},[35,677,678],{"class":45},"\"Month\"",[35,680,345],{"class":313},[35,682,683],{"class":45},"\"Depreciation\"",[35,685,345],{"class":313},[35,687,688],{"class":45},"\"BookValue\"",[35,690,365],{"class":313},[35,692,694,697,699,701,704],{"class":37,"line":693},22,[35,695,696],{"class":313},"    out.insert(",[35,698,124],{"class":371},[35,700,345],{"class":313},[35,702,703],{"class":45},"\"AssetID\"",[35,705,706],{"class":313},", asset.AssetID)\n",[35,708,710,713],{"class":37,"line":709},23,[35,711,712],{"class":309},"    if",[35,714,715],{"class":313}," pd.notna(asset.Disposed):\n",[35,717,719,722,724,727,729,732,735,738,740],{"class":37,"line":718},24,[35,720,721],{"class":313},"        out ",[35,723,336],{"class":309},[35,725,726],{"class":313}," out[out[",[35,728,678],{"class":45},[35,730,731],{"class":313},"] ",[35,733,734],{"class":309},"\u003C=",[35,736,737],{"class":313}," asset.Disposed.to_period(",[35,739,391],{"class":45},[35,741,742],{"class":313},")]\n",[35,744,746,749],{"class":37,"line":745},25,[35,747,748],{"class":309},"    return",[35,750,751],{"class":313}," out\n",[35,753,755],{"class":37,"line":754},26,[35,756,327],{"emptyLinePlaceholder":326},[35,758,760,763,765,768,771,774,776,779,782,784,787],{"class":37,"line":759},27,[35,761,762],{"class":313},"life ",[35,764,336],{"class":309},[35,766,767],{"class":313}," pd.concat([monthly_schedule(a) ",[35,769,770],{"class":309},"for",[35,772,773],{"class":313}," a ",[35,775,494],{"class":309},[35,777,778],{"class":313}," register.itertuples()], ",[35,780,781],{"class":348},"ignore_index",[35,783,336],{"class":309},[35,785,786],{"class":371},"True",[35,788,404],{"class":313},[35,790,792,795,798,800,802,804,807,810,812,815,817,820,823,825,827,829,831,834,837,839,842],{"class":37,"line":791},28,[35,793,794],{"class":371},"print",[35,796,797],{"class":313},"(life[life[",[35,799,703],{"class":45},[35,801,731],{"class":313},[35,803,551],{"class":309},[35,805,806],{"class":45}," \"FA-104\"",[35,808,809],{"class":313},"].head(",[35,811,133],{"class":371},[35,813,814],{"class":313},").round({",[35,816,683],{"class":45},[35,818,819],{"class":313},": ",[35,821,822],{"class":371},"2",[35,824,345],{"class":313},[35,826,688],{"class":45},[35,828,819],{"class":313},[35,830,822],{"class":371},[35,832,833],{"class":313},"}).to_string(",[35,835,836],{"class":348},"index",[35,838,336],{"class":309},[35,840,841],{"class":371},"False",[35,843,844],{"class":313},"))\n",[10,846,847,848,851,852,855],{},"The DDB switch is the line ",[32,849,850],{},"max(book * 2 \u002F life, straight)",": early on the declining charge is larger; later, as book value falls, the straight-line charge over the remaining months overtakes it, and from then on the asset depreciates evenly to its salvage value. For the server rack that happens in month 31. An asset with a high salvage value may never switch: the delivery van, with 6,000 salvage on 38,500, reaches its salvage value in month 56 while the declining charge is still the larger one, and the ",[32,853,854],{},"min(..., book - salvage)"," cap stops it there.",[20,857,859],{"id":858},"step-2-the-years-schedule-one-column-per-month","Step 2 — The year's schedule, one column per month",[10,861,862],{},"Keep the months of 2026 and pivot to the familiar layout: assets down, months across, a total column:",[25,864,866],{"className":300,"code":865,"language":302,"meta":30,"style":30},"year = life[life[\"Month\"].between(YEAR_START, YEAR_END)]\nschedule = (year.pivot_table(index=\"AssetID\", columns=\"Month\", values=\"Depreciation\", aggfunc=\"sum\", fill_value=0)\n                .reindex(register[\"AssetID\"], fill_value=0))\nschedule.columns = [m.strftime(\"%b\") for m in schedule.columns]\nschedule[\"FY2026\"] = schedule.sum(axis=1)\nprint(schedule.round(0).astype(int).iloc[:, [0, 1, 6, 7, 8, 11, 12]].to_string())\n",[32,867,868,891,945,963,994,1019],{"__ignoreMap":30},[35,869,870,873,875,878,880,883,885,887,889],{"class":37,"line":38},[35,871,872],{"class":313},"year ",[35,874,336],{"class":309},[35,876,877],{"class":313}," life[life[",[35,879,678],{"class":45},[35,881,882],{"class":313},"].between(",[35,884,372],{"class":371},[35,886,345],{"class":313},[35,888,377],{"class":371},[35,890,742],{"class":313},[35,892,893,896,898,901,903,905,907,909,911,913,915,917,920,922,924,926,929,931,934,936,939,941,943],{"class":37,"line":323},[35,894,895],{"class":313},"schedule ",[35,897,336],{"class":309},[35,899,900],{"class":313}," (year.pivot_table(",[35,902,836],{"class":348},[35,904,336],{"class":309},[35,906,703],{"class":45},[35,908,345],{"class":313},[35,910,671],{"class":348},[35,912,336],{"class":309},[35,914,678],{"class":45},[35,916,345],{"class":313},[35,918,919],{"class":348},"values",[35,921,336],{"class":309},[35,923,683],{"class":45},[35,925,345],{"class":313},[35,927,928],{"class":348},"aggfunc",[35,930,336],{"class":309},[35,932,933],{"class":45},"\"sum\"",[35,935,345],{"class":313},[35,937,938],{"class":348},"fill_value",[35,940,336],{"class":309},[35,942,124],{"class":371},[35,944,404],{"class":313},[35,946,947,950,952,955,957,959,961],{"class":37,"line":330},[35,948,949],{"class":313},"                .reindex(register[",[35,951,703],{"class":45},[35,953,954],{"class":313},"], ",[35,956,938],{"class":348},[35,958,336],{"class":309},[35,960,124],{"class":371},[35,962,844],{"class":313},[35,964,965,968,970,973,976,980,982,984,986,989,991],{"class":37,"line":368},[35,966,967],{"class":313},"schedule.columns ",[35,969,336],{"class":309},[35,971,972],{"class":313}," [m.strftime(",[35,974,975],{"class":45},"\"",[35,977,979],{"class":978},"sSjpA","%b",[35,981,975],{"class":45},[35,983,444],{"class":313},[35,985,770],{"class":309},[35,987,988],{"class":313}," m ",[35,990,494],{"class":309},[35,992,993],{"class":313}," schedule.columns]\n",[35,995,996,999,1002,1004,1006,1009,1012,1014,1017],{"class":37,"line":407},[35,997,998],{"class":313},"schedule[",[35,1000,1001],{"class":45},"\"FY2026\"",[35,1003,731],{"class":313},[35,1005,336],{"class":309},[35,1007,1008],{"class":313}," schedule.sum(",[35,1010,1011],{"class":348},"axis",[35,1013,336],{"class":309},[35,1015,1016],{"class":371},"1",[35,1018,404],{"class":313},[35,1020,1021,1023,1026,1028,1031,1033,1036,1038,1040,1042,1044,1047,1049,1052,1054,1057,1059,1062,1064,1067],{"class":37,"line":412},[35,1022,794],{"class":371},[35,1024,1025],{"class":313},"(schedule.round(",[35,1027,124],{"class":371},[35,1029,1030],{"class":313},").astype(",[35,1032,468],{"class":371},[35,1034,1035],{"class":313},").iloc[:, [",[35,1037,124],{"class":371},[35,1039,345],{"class":313},[35,1041,1016],{"class":371},[35,1043,345],{"class":313},[35,1045,1046],{"class":371},"6",[35,1048,345],{"class":313},[35,1050,1051],{"class":371},"7",[35,1053,345],{"class":313},[35,1055,1056],{"class":371},"8",[35,1058,345],{"class":313},[35,1060,1061],{"class":371},"11",[35,1063,345],{"class":313},[35,1065,1066],{"class":371},"12",[35,1068,1069],{"class":313},"]].to_string())\n",[102,1071,111,1077,111,1080,111,1083,111,1088,111,1094,111,1100,111,1104,111,1108,111,1111,111,1115,111,1118,111,1122,111,1126,111,1130,111,1134,111,1138,111,1142,111,1146,111,1150,111,1154,111,1157,111,1162,111,1164,111,1167,111,1169,111,1172,111,1174,111,1177,111,1179,111,1182,111,1184,111,1187,111,1189,111,1192,111,1194,111,1197,111,1200,111,1204,111,1206,111,1209,111,1211,111,1214,111,1216,111,1219,111,1221,111,1224,111,1226,111,1229,111,1231,111,1234,111,1236,111,1239,111,1242,111,1246,111,1249,111,1252,111,1254,111,1256,111,1258,111,1261,111,1263,111,1266,111,1268,111,1271,111,1273,111,1276,111,1278,111,1281,111,1284,111,1288,111,1290,111,1293,111,1295,111,1297,111,1299,111,1301,111,1303,111,1305,111,1309,111,1312,111,1314,111,1316,111,1318,111,1321,111,1324,111,1328,111,1330,111,1332,111,1334,111,1336,111,1338,111,1340,111,1342,111,1345,111,1347,111,1349,111,1351,111,1353,111,1355],{"viewBox":1072,"role":105,"ariaLabelledBy":1073,"xmlns":109,"style":1076},"118 0 524 200",[1074,1075],"fa-sched-t","fa-sched-d","width:100%;max-width:524px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[113,1078,1079],{"id":1074},"Part of the FY2026 schedule",[117,1081,1082],{"id":1075},"A sheet with assets down and months across. The packing machine starts in March and the workstations in August; the company car stops after August, the month it was sold. Declining balance assets show a falling charge each month.",[121,1084],{"x":1085,"y":124,"width":1086,"height":1087,"fill":127},"118","524","200",[121,1089],{"x":1090,"y":1091,"width":1092,"height":1093,"rx":124,"fill":147,"stroke":148,"style":136},"134.4","16.0","141.6","28.0",[138,1095,1099],{"x":1096,"y":1097,"style":1098},"205.2","35.0","font-size:11px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Asset",[121,1101],{"x":1102,"y":1091,"width":1103,"height":1093,"rx":124,"fill":147,"stroke":148,"style":136},"276.0","46.8",[138,1105,1107],{"x":1106,"y":1097,"style":1098},"299.4","Jan",[121,1109],{"x":1110,"y":1091,"width":1103,"height":1093,"rx":124,"fill":147,"stroke":148,"style":136},"322.8",[138,1112,1114],{"x":1113,"y":1097,"style":1098},"346.2","Feb",[121,1116],{"x":1117,"y":1091,"width":1103,"height":1093,"rx":124,"fill":147,"stroke":148,"style":136},"369.6",[138,1119,1121],{"x":1120,"y":1097,"style":1098},"393.0","Jul",[121,1123],{"x":1124,"y":1091,"width":1125,"height":1093,"rx":124,"fill":147,"stroke":148,"style":136},"416.4","47.1",[138,1127,1129],{"x":1128,"y":1097,"style":1098},"439.9","Aug",[121,1131],{"x":1132,"y":1091,"width":1133,"height":1093,"rx":124,"fill":147,"stroke":148,"style":136},"463.5","46.6",[138,1135,1137],{"x":1136,"y":1097,"style":1098},"486.8","Sep",[121,1139],{"x":1140,"y":1091,"width":1141,"height":1093,"rx":124,"fill":147,"stroke":148,"style":136},"510.1","46.5",[138,1143,1145],{"x":1144,"y":1097,"style":1098},"533.3","Dec",[121,1147],{"x":1148,"y":1091,"width":1149,"height":1093,"rx":124,"fill":147,"stroke":148,"style":136},"556.6","69.1",[138,1151,1153],{"x":1152,"y":1097,"style":1098},"591.1","FY2026",[121,1155],{"x":1090,"y":1156,"width":1092,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},"44.0",[138,1158,1161],{"x":1096,"y":1159,"style":1160},"63.0","font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","FA-101 van",[121,1163],{"x":1102,"y":1156,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1165,1166],{"x":1106,"y":1159,"style":1160},"419",[121,1168],{"x":1110,"y":1156,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1170,1171],{"x":1113,"y":1159,"style":1160},"405",[121,1173],{"x":1117,"y":1156,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1175,1176],{"x":1120,"y":1159,"style":1160},"342",[121,1178],{"x":1124,"y":1156,"width":1125,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1180,1181],{"x":1128,"y":1159,"style":1160},"331",[121,1183],{"x":1132,"y":1156,"width":1133,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1185,1186],{"x":1136,"y":1159,"style":1160},"320",[121,1188],{"x":1140,"y":1156,"width":1141,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1190,1191],{"x":1144,"y":1159,"style":1160},"289",[121,1193],{"x":1148,"y":1156,"width":1149,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1195,1196],{"x":1152,"y":1159,"style":1160},"4,204",[121,1198],{"x":1090,"y":1199,"width":1092,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},"72.0",[138,1201,1203],{"x":1096,"y":1202,"style":1160},"91.0","FA-104 server",[121,1205],{"x":1102,"y":1199,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1207,1208],{"x":1106,"y":1202,"style":1160},"874",[121,1210],{"x":1110,"y":1199,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1212,1213],{"x":1113,"y":1202,"style":1160},"838",[121,1215],{"x":1117,"y":1199,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1217,1218],{"x":1120,"y":1202,"style":1160},"677",[121,1220],{"x":1124,"y":1199,"width":1125,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1222,1223],{"x":1128,"y":1202,"style":1160},"649",[121,1225],{"x":1132,"y":1199,"width":1133,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1227,1228],{"x":1136,"y":1202,"style":1160},"622",[121,1230],{"x":1140,"y":1199,"width":1141,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1232,1233],{"x":1144,"y":1202,"style":1160},"548",[121,1235],{"x":1148,"y":1199,"width":1149,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1237,1238],{"x":1152,"y":1202,"style":1160},"8,394",[121,1240],{"x":1090,"y":1241,"width":1092,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},"100.0",[138,1243,1245],{"x":1096,"y":1244,"style":1160},"119.0","FA-106 packer",[121,1247],{"x":1102,"y":1241,"width":1103,"height":1093,"rx":124,"fill":1248,"stroke":158,"style":136},"#e7ebef",[138,1250,124],{"x":1106,"y":1244,"style":1251},"font-size:11px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[121,1253],{"x":1110,"y":1241,"width":1103,"height":1093,"rx":124,"fill":1248,"stroke":158,"style":136},[138,1255,124],{"x":1113,"y":1244,"style":1251},[121,1257],{"x":1117,"y":1241,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1259,1260],{"x":1120,"y":1244,"style":1160},"974",[121,1262],{"x":1124,"y":1241,"width":1125,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1264,1265],{"x":1128,"y":1244,"style":1160},"958",[121,1267],{"x":1132,"y":1241,"width":1133,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1269,1270],{"x":1136,"y":1244,"style":1160},"942",[121,1272],{"x":1140,"y":1241,"width":1141,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1274,1275],{"x":1144,"y":1244,"style":1160},"895",[121,1277],{"x":1148,"y":1241,"width":1149,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1279,1280],{"x":1152,"y":1244,"style":1160},"9,669",[121,1282],{"x":1090,"y":1283,"width":1092,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},"128.0",[138,1285,1287],{"x":1096,"y":1286,"style":1160},"147.0","FA-107 car",[121,1289],{"x":1102,"y":1283,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1291,1292],{"x":1106,"y":1286,"style":1160},"483",[121,1294],{"x":1110,"y":1283,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1296,1292],{"x":1113,"y":1286,"style":1160},[121,1298],{"x":1117,"y":1283,"width":1103,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1300,1292],{"x":1120,"y":1286,"style":1160},[121,1302],{"x":1124,"y":1283,"width":1125,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1304,1292],{"x":1128,"y":1286,"style":1160},[121,1306],{"x":1132,"y":1283,"width":1133,"height":1093,"rx":124,"fill":1307,"stroke":1308,"style":136},"#fdefd8","var(--gold,#b4740a)",[138,1310,124],{"x":1136,"y":1286,"style":1311},"font-size:11px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle",[121,1313],{"x":1140,"y":1283,"width":1141,"height":1093,"rx":124,"fill":1307,"stroke":1308,"style":136},[138,1315,124],{"x":1144,"y":1286,"style":1311},[121,1317],{"x":1148,"y":1283,"width":1149,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1319,1320],{"x":1152,"y":1286,"style":1160},"3,867",[121,1322],{"x":1090,"y":1323,"width":1092,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},"156.0",[138,1325,1327],{"x":1096,"y":1326,"style":1160},"175.0","FA-108 workstations",[121,1329],{"x":1102,"y":1323,"width":1103,"height":1093,"rx":124,"fill":1248,"stroke":158,"style":136},[138,1331,124],{"x":1106,"y":1326,"style":1251},[121,1333],{"x":1110,"y":1323,"width":1103,"height":1093,"rx":124,"fill":1248,"stroke":158,"style":136},[138,1335,124],{"x":1113,"y":1326,"style":1251},[121,1337],{"x":1117,"y":1323,"width":1103,"height":1093,"rx":124,"fill":1248,"stroke":158,"style":136},[138,1339,124],{"x":1120,"y":1326,"style":1251},[121,1341],{"x":1124,"y":1323,"width":1125,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1343,1344],{"x":1128,"y":1326,"style":1160},"267",[121,1346],{"x":1132,"y":1323,"width":1133,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1348,1344],{"x":1136,"y":1326,"style":1160},[121,1350],{"x":1140,"y":1323,"width":1141,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1352,1344],{"x":1144,"y":1326,"style":1160},[121,1354],{"x":1148,"y":1323,"width":1149,"height":1093,"rx":124,"fill":127,"stroke":158,"style":159},[138,1356,1357],{"x":1152,"y":1326,"style":1160},"1,333",[10,1359,1360],{},"The packing machine (FA-106) starts in March because it went into service in February; the workstations (FA-108) start in August; the car (FA-107) stops after August, the month it was sold.",[20,1362,1364],{"id":1363},"step-3-net-book-value-and-disposals","Step 3 — Net book value and disposals",[10,1366,1367],{},"Book value at the year end, or at disposal, comes from the last computed month. Assets whose depreciation had not started by the year end are carried at cost:",[25,1369,1371],{"className":300,"code":1370,"language":302,"meta":30,"style":30},"last = life[life[\"Month\"] \u003C= YEAR_END].groupby(\"AssetID\").tail(1).set_index(\"AssetID\")\nreg = register.set_index(\"AssetID\")\nreg[\"BookValue\"] = last[\"BookValue\"].reindex(reg.index).fillna(reg[\"Cost\"])\nreg[\"AccumDep\"] = reg[\"Cost\"] - reg[\"BookValue\"]\n\nsold = reg[reg[\"Disposed\"].notna()].copy()\nsold[\"GainLoss\"] = sold[\"Proceeds\"] - sold[\"BookValue\"]\nprint(sold[[\"Description\", \"Cost\", \"AccumDep\", \"BookValue\", \"Proceeds\", \"GainLoss\"]].round(2).to_string())\n",[32,1372,1373,1408,1422,1446,1473,1477,1492,1520],{"__ignoreMap":30},[35,1374,1375,1378,1380,1382,1384,1386,1388,1391,1394,1396,1399,1401,1404,1406],{"class":37,"line":38},[35,1376,1377],{"class":313},"last ",[35,1379,336],{"class":309},[35,1381,877],{"class":313},[35,1383,678],{"class":45},[35,1385,731],{"class":313},[35,1387,734],{"class":309},[35,1389,1390],{"class":371}," YEAR_END",[35,1392,1393],{"class":313},"].groupby(",[35,1395,703],{"class":45},[35,1397,1398],{"class":313},").tail(",[35,1400,1016],{"class":371},[35,1402,1403],{"class":313},").set_index(",[35,1405,703],{"class":45},[35,1407,404],{"class":313},[35,1409,1410,1413,1415,1418,1420],{"class":37,"line":323},[35,1411,1412],{"class":313},"reg ",[35,1414,336],{"class":309},[35,1416,1417],{"class":313}," register.set_index(",[35,1419,703],{"class":45},[35,1421,404],{"class":313},[35,1423,1424,1427,1429,1431,1433,1436,1438,1441,1444],{"class":37,"line":330},[35,1425,1426],{"class":313},"reg[",[35,1428,688],{"class":45},[35,1430,731],{"class":313},[35,1432,336],{"class":309},[35,1434,1435],{"class":313}," last[",[35,1437,688],{"class":45},[35,1439,1440],{"class":313},"].reindex(reg.index).fillna(reg[",[35,1442,1443],{"class":45},"\"Cost\"",[35,1445,365],{"class":313},[35,1447,1448,1450,1453,1455,1457,1460,1462,1464,1466,1468,1470],{"class":37,"line":368},[35,1449,1426],{"class":313},[35,1451,1452],{"class":45},"\"AccumDep\"",[35,1454,731],{"class":313},[35,1456,336],{"class":309},[35,1458,1459],{"class":313}," reg[",[35,1461,1443],{"class":45},[35,1463,731],{"class":313},[35,1465,514],{"class":309},[35,1467,1459],{"class":313},[35,1469,688],{"class":45},[35,1471,1472],{"class":313},"]\n",[35,1474,1475],{"class":37,"line":407},[35,1476,327],{"emptyLinePlaceholder":326},[35,1478,1479,1482,1484,1487,1489],{"class":37,"line":412},[35,1480,1481],{"class":313},"sold ",[35,1483,336],{"class":309},[35,1485,1486],{"class":313}," reg[reg[",[35,1488,362],{"class":45},[35,1490,1491],{"class":313},"].notna()].copy()\n",[35,1493,1494,1497,1500,1502,1504,1507,1510,1512,1514,1516,1518],{"class":37,"line":425},[35,1495,1496],{"class":313},"sold[",[35,1498,1499],{"class":45},"\"GainLoss\"",[35,1501,731],{"class":313},[35,1503,336],{"class":309},[35,1505,1506],{"class":313}," sold[",[35,1508,1509],{"class":45},"\"Proceeds\"",[35,1511,731],{"class":313},[35,1513,514],{"class":309},[35,1515,1506],{"class":313},[35,1517,688],{"class":45},[35,1519,1472],{"class":313},[35,1521,1522,1524,1527,1530,1532,1534,1536,1538,1540,1542,1544,1546,1548,1550,1553,1555],{"class":37,"line":431},[35,1523,794],{"class":371},[35,1525,1526],{"class":313},"(sold[[",[35,1528,1529],{"class":45},"\"Description\"",[35,1531,345],{"class":313},[35,1533,1443],{"class":45},[35,1535,345],{"class":313},[35,1537,1452],{"class":45},[35,1539,345],{"class":313},[35,1541,688],{"class":45},[35,1543,345],{"class":313},[35,1545,1509],{"class":45},[35,1547,345],{"class":313},[35,1549,1499],{"class":45},[35,1551,1552],{"class":313},"]].round(",[35,1554,822],{"class":371},[35,1556,1557],{"class":313},").to_string())\n",[10,1559,1560],{},"A negative figure is a loss on disposal: the car sold for 716.67 less than its book value of 16,216.67. Gains and losses go to the P&L as other income or expense, separately from the depreciation charge.",[20,1562,1564],{"id":1563},"step-4-the-roll-forward-by-category","Step 4 — The roll-forward by category",[10,1566,1567],{},"Auditors and the balance sheet want movements, not just balances: cost and accumulated depreciation at the start of the year, additions, disposals, the year's charge, and the closing figures. Every column is derived from the register and the life schedule:",[25,1569,1571],{"className":300,"code":1570,"language":302,"meta":30,"style":30},"start = YEAR_START - 1                          # December 2025\ndep_before = life[life[\"Month\"] \u003C= start].groupby(\"AssetID\")[\"Depreciation\"].sum()\ndep_year = year.groupby(\"AssetID\")[\"Depreciation\"].sum()\nreg[\"OpeningAccum\"] = dep_before.reindex(reg.index).fillna(0)\nreg[\"Charge\"] = dep_year.reindex(reg.index).fillna(0)\nadded = reg[\"InService\"].dt.year == 2026\ngone = reg[\"Disposed\"].dt.year == 2026\n\nroll = pd.DataFrame({\n    \"Opening cost\": reg[\"Cost\"].where(~added, 0),\n    \"Additions\": reg[\"Cost\"].where(added, 0),\n    \"Disposals\": -reg[\"Cost\"].where(gone, 0),\n    \"Opening dep\": reg[\"OpeningAccum\"],\n    \"Charge\": reg[\"Charge\"],\n    \"Dep on disposals\": -(reg[\"OpeningAccum\"] + reg[\"Charge\"]).where(gone, 0),\n}).groupby(reg[\"Category\"]).sum()\nroll[\"Closing cost\"] = roll[\"Opening cost\"] + roll[\"Additions\"] + roll[\"Disposals\"]\nroll[\"Closing dep\"] = roll[\"Opening dep\"] + roll[\"Charge\"] + roll[\"Dep on disposals\"]\nroll[\"Closing NBV\"] = roll[\"Closing cost\"] - roll[\"Closing dep\"]\nroll.loc[\"Total\"] = roll.sum()\nprint(roll.round(0).astype(int).to_string())\n\ncheck = reg.loc[~gone, \"BookValue\"].sum()\nprint(f\"closing NBV from the roll-forward {roll.loc['Total', 'Closing NBV']:.2f}; \"\n      f\"sum of assets still held {check:.2f}\")\n",[32,1572,1573,1591,1619,1637,1655,1673,1692,1709,1713,1723,1747,1763,1783,1795,1806,1835,1846,1884,1919,1944,1959,1974,1978,1997,2035],{"__ignoreMap":30},[35,1574,1575,1578,1580,1583,1586,1588],{"class":37,"line":38},[35,1576,1577],{"class":313},"start ",[35,1579,336],{"class":309},[35,1581,1582],{"class":371}," YEAR_START",[35,1584,1585],{"class":309}," -",[35,1587,450],{"class":371},[35,1589,1590],{"class":453},"                          # December 2025\n",[35,1592,1593,1596,1598,1600,1602,1604,1606,1609,1611,1614,1616],{"class":37,"line":323},[35,1594,1595],{"class":313},"dep_before ",[35,1597,336],{"class":309},[35,1599,877],{"class":313},[35,1601,678],{"class":45},[35,1603,731],{"class":313},[35,1605,734],{"class":309},[35,1607,1608],{"class":313}," start].groupby(",[35,1610,703],{"class":45},[35,1612,1613],{"class":313},")[",[35,1615,683],{"class":45},[35,1617,1618],{"class":313},"].sum()\n",[35,1620,1621,1624,1626,1629,1631,1633,1635],{"class":37,"line":330},[35,1622,1623],{"class":313},"dep_year ",[35,1625,336],{"class":309},[35,1627,1628],{"class":313}," year.groupby(",[35,1630,703],{"class":45},[35,1632,1613],{"class":313},[35,1634,683],{"class":45},[35,1636,1618],{"class":313},[35,1638,1639,1641,1644,1646,1648,1651,1653],{"class":37,"line":368},[35,1640,1426],{"class":313},[35,1642,1643],{"class":45},"\"OpeningAccum\"",[35,1645,731],{"class":313},[35,1647,336],{"class":309},[35,1649,1650],{"class":313}," dep_before.reindex(reg.index).fillna(",[35,1652,124],{"class":371},[35,1654,404],{"class":313},[35,1656,1657,1659,1662,1664,1666,1669,1671],{"class":37,"line":407},[35,1658,1426],{"class":313},[35,1660,1661],{"class":45},"\"Charge\"",[35,1663,731],{"class":313},[35,1665,336],{"class":309},[35,1667,1668],{"class":313}," dep_year.reindex(reg.index).fillna(",[35,1670,124],{"class":371},[35,1672,404],{"class":313},[35,1674,1675,1678,1680,1682,1684,1687,1689],{"class":37,"line":412},[35,1676,1677],{"class":313},"added ",[35,1679,336],{"class":309},[35,1681,1459],{"class":313},[35,1683,357],{"class":45},[35,1685,1686],{"class":313},"].dt.year ",[35,1688,551],{"class":309},[35,1690,1691],{"class":371}," 2026\n",[35,1693,1694,1697,1699,1701,1703,1705,1707],{"class":37,"line":425},[35,1695,1696],{"class":313},"gone ",[35,1698,336],{"class":309},[35,1700,1459],{"class":313},[35,1702,362],{"class":45},[35,1704,1686],{"class":313},[35,1706,551],{"class":309},[35,1708,1691],{"class":371},[35,1710,1711],{"class":37,"line":431},[35,1712,327],{"emptyLinePlaceholder":326},[35,1714,1715,1718,1720],{"class":37,"line":457},[35,1716,1717],{"class":313},"roll ",[35,1719,336],{"class":309},[35,1721,1722],{"class":313}," pd.DataFrame({\n",[35,1724,1725,1728,1731,1733,1736,1739,1742,1744],{"class":37,"line":474},[35,1726,1727],{"class":45},"    \"Opening cost\"",[35,1729,1730],{"class":313},": reg[",[35,1732,1443],{"class":45},[35,1734,1735],{"class":313},"].where(",[35,1737,1738],{"class":309},"~",[35,1740,1741],{"class":313},"added, ",[35,1743,124],{"class":371},[35,1745,1746],{"class":313},"),\n",[35,1748,1749,1752,1754,1756,1759,1761],{"class":37,"line":485},[35,1750,1751],{"class":45},"    \"Additions\"",[35,1753,1730],{"class":313},[35,1755,1443],{"class":45},[35,1757,1758],{"class":313},"].where(added, ",[35,1760,124],{"class":371},[35,1762,1746],{"class":313},[35,1764,1765,1768,1770,1772,1774,1776,1779,1781],{"class":37,"line":503},[35,1766,1767],{"class":45},"    \"Disposals\"",[35,1769,819],{"class":313},[35,1771,514],{"class":309},[35,1773,1426],{"class":313},[35,1775,1443],{"class":45},[35,1777,1778],{"class":313},"].where(gone, ",[35,1780,124],{"class":371},[35,1782,1746],{"class":313},[35,1784,1785,1788,1790,1792],{"class":37,"line":520},[35,1786,1787],{"class":45},"    \"Opening dep\"",[35,1789,1730],{"class":313},[35,1791,1643],{"class":45},[35,1793,1794],{"class":313},"],\n",[35,1796,1797,1800,1802,1804],{"class":37,"line":542},[35,1798,1799],{"class":45},"    \"Charge\"",[35,1801,1730],{"class":313},[35,1803,1661],{"class":45},[35,1805,1794],{"class":313},[35,1807,1808,1811,1813,1815,1818,1820,1822,1824,1826,1828,1831,1833],{"class":37,"line":560},[35,1809,1810],{"class":45},"    \"Dep on disposals\"",[35,1812,819],{"class":313},[35,1814,514],{"class":309},[35,1816,1817],{"class":313},"(reg[",[35,1819,1643],{"class":45},[35,1821,731],{"class":313},[35,1823,447],{"class":309},[35,1825,1459],{"class":313},[35,1827,1661],{"class":45},[35,1829,1830],{"class":313},"]).where(gone, ",[35,1832,124],{"class":371},[35,1834,1746],{"class":313},[35,1836,1837,1840,1843],{"class":37,"line":589},[35,1838,1839],{"class":313},"}).groupby(reg[",[35,1841,1842],{"class":45},"\"Category\"",[35,1844,1845],{"class":313},"]).sum()\n",[35,1847,1848,1851,1854,1856,1858,1861,1864,1866,1868,1870,1873,1875,1877,1879,1882],{"class":37,"line":610},[35,1849,1850],{"class":313},"roll[",[35,1852,1853],{"class":45},"\"Closing cost\"",[35,1855,731],{"class":313},[35,1857,336],{"class":309},[35,1859,1860],{"class":313}," roll[",[35,1862,1863],{"class":45},"\"Opening cost\"",[35,1865,731],{"class":313},[35,1867,447],{"class":309},[35,1869,1860],{"class":313},[35,1871,1872],{"class":45},"\"Additions\"",[35,1874,731],{"class":313},[35,1876,447],{"class":309},[35,1878,1860],{"class":313},[35,1880,1881],{"class":45},"\"Disposals\"",[35,1883,1472],{"class":313},[35,1885,1886,1888,1891,1893,1895,1897,1900,1902,1904,1906,1908,1910,1912,1914,1917],{"class":37,"line":618},[35,1887,1850],{"class":313},[35,1889,1890],{"class":45},"\"Closing dep\"",[35,1892,731],{"class":313},[35,1894,336],{"class":309},[35,1896,1860],{"class":313},[35,1898,1899],{"class":45},"\"Opening dep\"",[35,1901,731],{"class":313},[35,1903,447],{"class":309},[35,1905,1860],{"class":313},[35,1907,1661],{"class":45},[35,1909,731],{"class":313},[35,1911,447],{"class":309},[35,1913,1860],{"class":313},[35,1915,1916],{"class":45},"\"Dep on disposals\"",[35,1918,1472],{"class":313},[35,1920,1921,1923,1926,1928,1930,1932,1934,1936,1938,1940,1942],{"class":37,"line":637},[35,1922,1850],{"class":313},[35,1924,1925],{"class":45},"\"Closing NBV\"",[35,1927,731],{"class":313},[35,1929,336],{"class":309},[35,1931,1860],{"class":313},[35,1933,1853],{"class":45},[35,1935,731],{"class":313},[35,1937,514],{"class":309},[35,1939,1860],{"class":313},[35,1941,1890],{"class":45},[35,1943,1472],{"class":313},[35,1945,1946,1949,1952,1954,1956],{"class":37,"line":649},[35,1947,1948],{"class":313},"roll.loc[",[35,1950,1951],{"class":45},"\"Total\"",[35,1953,731],{"class":313},[35,1955,336],{"class":309},[35,1957,1958],{"class":313}," roll.sum()\n",[35,1960,1961,1963,1966,1968,1970,1972],{"class":37,"line":660},[35,1962,794],{"class":371},[35,1964,1965],{"class":313},"(roll.round(",[35,1967,124],{"class":371},[35,1969,1030],{"class":313},[35,1971,468],{"class":371},[35,1973,1557],{"class":313},[35,1975,1976],{"class":37,"line":693},[35,1977,327],{"emptyLinePlaceholder":326},[35,1979,1980,1983,1985,1988,1990,1993,1995],{"class":37,"line":709},[35,1981,1982],{"class":313},"check ",[35,1984,336],{"class":309},[35,1986,1987],{"class":313}," reg.loc[",[35,1989,1738],{"class":309},[35,1991,1992],{"class":313},"gone, ",[35,1994,688],{"class":45},[35,1996,1618],{"class":313},[35,1998,1999,2001,2004,2007,2010,2013,2015,2018,2020,2023,2026,2029,2032],{"class":37,"line":718},[35,2000,794],{"class":371},[35,2002,2003],{"class":313},"(",[35,2005,2006],{"class":309},"f",[35,2008,2009],{"class":45},"\"closing NBV from the roll-forward ",[35,2011,2012],{"class":978},"{",[35,2014,1948],{"class":313},[35,2016,2017],{"class":45},"'Total'",[35,2019,345],{"class":313},[35,2021,2022],{"class":45},"'Closing NBV'",[35,2024,2025],{"class":313},"]",[35,2027,2028],{"class":309},":.2f",[35,2030,2031],{"class":978},"}",[35,2033,2034],{"class":45},"; \"\n",[35,2036,2037,2040,2043,2045,2048,2050,2052,2054],{"class":37,"line":745},[35,2038,2039],{"class":309},"      f",[35,2041,2042],{"class":45},"\"sum of assets still held ",[35,2044,2012],{"class":978},[35,2046,2047],{"class":313},"check",[35,2049,2028],{"class":309},[35,2051,2031],{"class":978},[35,2053,975],{"class":45},[35,2055,404],{"class":313},[10,2057,2058],{},"The last line is the check that matters: the roll-forward's closing net book value must equal the sum of the book values of the assets still held. If they differ, an asset is being counted twice or not at all.",[102,2060,111,2066,111,2069,111,2072,111,2076,111,2081,111,2090,111,2096,111,2100,111,2105,111,2110,111,2113,111,2120,111,2125,111,2128,111,2132,111,2135,111,2138,111,2145,111,2150,111,2153,111,2157,111,2160,111,2163,111,2170,111,2175,111,2178,111,2182,111,2185,111,2188,111,2194,111,2198],{"viewBox":2061,"role":105,"ariaLabelledBy":2062,"xmlns":109,"style":2065},"4 0 752 125",[2063,2064],"fa-roll-t","fa-roll-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[113,2067,2068],{"id":2063},"How the roll-forward moves",[117,2070,2071],{"id":2064},"Opening net book value plus additions, less disposals at book value, less the year's depreciation charge, equals closing net book value, which must match the sum of the assets still held.",[121,2073],{"x":123,"y":124,"width":2074,"height":2075,"fill":127},"752","125",[121,2077],{"x":2078,"y":1091,"width":2079,"height":2080,"rx":1066,"fill":1248,"stroke":158,"style":224},"20.0","115.2","93.0",[2082,2083,2085],"g",{"transform":2084},"translate(65.6,29.0) scale(1.000)",[214,2086],{"d":2087,"fill":217,"stroke":2088,"style":2089},"M4 5h16v15H4z M4 10h16 M8 3v4 M16 3v4","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[138,2091,2095],{"x":2092,"y":2093,"style":2094},"77.6","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Opening NBV",[138,2097,2099],{"x":2092,"y":2098,"style":195},"95.0","1 Jan 2026",[37,2101],{"x1":2102,"y1":2103,"x2":2104,"y2":2103,"stroke":148,"style":224},"140.2","62.5","162.2",[2106,2107],"polygon",{"points":2108,"fill":2109},"166.2,62.5 157.2,67.5 157.2,57.5","#5b5cf0",[121,2111],{"x":2112,"y":1091,"width":2079,"height":2080,"rx":1066,"fill":134,"stroke":135,"style":224},"171.2",[2082,2114,2116],{"transform":2115},"translate(216.8,29.0) scale(1.000)",[214,2117],{"d":2118,"fill":217,"stroke":2119,"style":2089},"M12 2.5l8.5 4.7v9.6L12 21.5l-8.5-4.7V7.2z M3.5 7.2l8.5 4.7 8.5-4.7 M12 11.9v9.6","var(--teal-ink,#0b6157)",[138,2121,2124],{"x":2122,"y":2093,"style":2123},"228.8","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","+ Additions",[138,2126,2127],{"x":2122,"y":2098,"style":195},"at cost",[37,2129],{"x1":2130,"y1":2103,"x2":2131,"y2":2103,"stroke":148,"style":224},"291.4","313.4",[2106,2133],{"points":2134,"fill":2109},"317.4,62.5 308.4,67.5 308.4,57.5",[121,2136],{"x":2137,"y":1091,"width":2079,"height":2080,"rx":1066,"fill":1307,"stroke":1308,"style":224},"322.4",[2082,2139,2141],{"transform":2140},"translate(368.0,29.0) scale(1.000)",[214,2142],{"d":2143,"fill":217,"stroke":2144,"style":2089},"M4 7h16 M10 11v6 M14 11v6 M6 7l1 13h10l1-13 M9 7V4h6v3","var(--gold-ink,#7a4e06)",[138,2146,2149],{"x":2147,"y":2093,"style":2148},"380.0","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","− Disposals",[138,2151,2152],{"x":2147,"y":2098,"style":195},"at book value",[37,2154],{"x1":2155,"y1":2103,"x2":2156,"y2":2103,"stroke":148,"style":224},"442.6","464.6",[2106,2158],{"points":2159,"fill":2109},"468.6,62.5 459.6,67.5 459.6,57.5",[121,2161],{"x":2162,"y":1091,"width":2079,"height":2080,"rx":1066,"fill":147,"stroke":148,"style":224},"473.6",[2082,2164,2166],{"transform":2165},"translate(519.2,29.0) scale(1.000)",[214,2167],{"d":2168,"fill":217,"stroke":2169,"style":2089},"M4 20h16 M7 17v-5 M12 17V7 M17 17v-8","var(--brand-strong,#4338ca)",[138,2171,2174],{"x":2172,"y":2093,"style":2173},"531.2","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","− Charge",[138,2176,2177],{"x":2172,"y":2098,"style":195},"this year",[37,2179],{"x1":2180,"y1":2103,"x2":2181,"y2":2103,"stroke":148,"style":224},"593.8","615.8",[2106,2183],{"points":2184,"fill":2109},"619.8,62.5 610.8,67.5 610.8,57.5",[121,2186],{"x":2187,"y":1091,"width":2079,"height":2080,"rx":1066,"fill":147,"stroke":148,"style":224},"624.8",[2082,2189,2191],{"transform":2190},"translate(670.4,29.0) scale(1.000)",[214,2192],{"d":2193,"fill":217,"stroke":2169,"style":2089},"M5 12.5l4.5 4.5L19 7",[138,2195,2197],{"x":2196,"y":2093,"style":2173},"682.4","Closing NBV",[138,2199,2200],{"x":2196,"y":2098,"style":195},"= assets held",[20,2202,2204],{"id":2203},"step-5-check-against-excels-sln-and-vdb","Step 5 — Check against Excel's SLN and VDB",[10,2206,2207,2208,2211,2212,2215,2216,2219,2220,2223],{},"Excel has the same calculations built in: ",[32,2209,2210],{},"SLN(cost, salvage, life)"," for the straight-line charge and ",[32,2213,2214],{},"VDB(cost, salvage, life, start, end, factor)"," for the declining balance total between two periods, switching to straight line by default. Using months as the periods, ",[32,2217,2218],{},"VDB(cost, salvage, 60, 0, k, 2)"," is the accumulated depreciation after month ",[32,2221,2222],{},"k",". Writing those formulas next to the Python numbers and recalculating with LibreOffice is a quick independent check:",[25,2225,2227],{"className":300,"code":2226,"language":302,"meta":30,"style":30},"from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.append([\"AssetID\", \"Months to Dec 2026\", \"Python accumulated\", \"Excel formula\"])\nfor a in register.itertuples():\n    months = life[(life[\"AssetID\"] == a.AssetID) & (life[\"Month\"] \u003C= YEAR_END)]\n    k = len(months)\n    python_acc = round(months[\"Depreciation\"].sum(), 2)\n    if a.Method == \"DDB\":\n        formula = f\"=VDB({a.Cost},{a.Salvage},{a.LifeMonths},0,{k},2)\"\n    else:\n        formula = f\"=SLN({a.Cost},{a.Salvage},{a.LifeMonths})*{k}\"\n    ws.append([a.AssetID, k, python_acc, formula])\nwb.save(\"depreciation_check.xlsx\")\n",[32,2228,2229,2242,2246,2256,2266,2290,2301,2336,2349,2371,2384,2435,2442,2487,2492],{"__ignoreMap":30},[35,2230,2231,2234,2237,2239],{"class":37,"line":38},[35,2232,2233],{"class":309},"from",[35,2235,2236],{"class":313}," openpyxl ",[35,2238,310],{"class":309},[35,2240,2241],{"class":313}," Workbook\n",[35,2243,2244],{"class":37,"line":323},[35,2245,327],{"emptyLinePlaceholder":326},[35,2247,2248,2251,2253],{"class":37,"line":330},[35,2249,2250],{"class":313},"wb ",[35,2252,336],{"class":309},[35,2254,2255],{"class":313}," Workbook()\n",[35,2257,2258,2261,2263],{"class":37,"line":368},[35,2259,2260],{"class":313},"ws ",[35,2262,336],{"class":309},[35,2264,2265],{"class":313}," wb.active\n",[35,2267,2268,2271,2273,2275,2278,2280,2283,2285,2288],{"class":37,"line":407},[35,2269,2270],{"class":313},"ws.append([",[35,2272,703],{"class":45},[35,2274,345],{"class":313},[35,2276,2277],{"class":45},"\"Months to Dec 2026\"",[35,2279,345],{"class":313},[35,2281,2282],{"class":45},"\"Python accumulated\"",[35,2284,345],{"class":313},[35,2286,2287],{"class":45},"\"Excel formula\"",[35,2289,365],{"class":313},[35,2291,2292,2294,2296,2298],{"class":37,"line":412},[35,2293,770],{"class":309},[35,2295,773],{"class":313},[35,2297,494],{"class":309},[35,2299,2300],{"class":313}," register.itertuples():\n",[35,2302,2303,2306,2308,2311,2313,2315,2317,2320,2323,2326,2328,2330,2332,2334],{"class":37,"line":425},[35,2304,2305],{"class":313},"    months ",[35,2307,336],{"class":309},[35,2309,2310],{"class":313}," life[(life[",[35,2312,703],{"class":45},[35,2314,731],{"class":313},[35,2316,551],{"class":309},[35,2318,2319],{"class":313}," a.AssetID) ",[35,2321,2322],{"class":309},"&",[35,2324,2325],{"class":313}," (life[",[35,2327,678],{"class":45},[35,2329,731],{"class":313},[35,2331,734],{"class":309},[35,2333,1390],{"class":371},[35,2335,742],{"class":313},[35,2337,2338,2341,2343,2346],{"class":37,"line":431},[35,2339,2340],{"class":313},"    k ",[35,2342,336],{"class":309},[35,2344,2345],{"class":371}," len",[35,2347,2348],{"class":313},"(months)\n",[35,2350,2351,2354,2356,2359,2362,2364,2367,2369],{"class":37,"line":457},[35,2352,2353],{"class":313},"    python_acc ",[35,2355,336],{"class":309},[35,2357,2358],{"class":371}," round",[35,2360,2361],{"class":313},"(months[",[35,2363,683],{"class":45},[35,2365,2366],{"class":313},"].sum(), ",[35,2368,822],{"class":371},[35,2370,404],{"class":313},[35,2372,2373,2375,2378,2380,2382],{"class":37,"line":474},[35,2374,712],{"class":309},[35,2376,2377],{"class":313}," a.Method ",[35,2379,551],{"class":309},[35,2381,554],{"class":45},[35,2383,557],{"class":313},[35,2385,2386,2389,2391,2394,2397,2399,2402,2404,2407,2409,2412,2414,2416,2418,2421,2423,2426,2428,2430,2432],{"class":37,"line":485},[35,2387,2388],{"class":313},"        formula ",[35,2390,336],{"class":309},[35,2392,2393],{"class":309}," f",[35,2395,2396],{"class":45},"\"=VDB(",[35,2398,2012],{"class":978},[35,2400,2401],{"class":313},"a.Cost",[35,2403,2031],{"class":978},[35,2405,2406],{"class":45},",",[35,2408,2012],{"class":978},[35,2410,2411],{"class":313},"a.Salvage",[35,2413,2031],{"class":978},[35,2415,2406],{"class":45},[35,2417,2012],{"class":978},[35,2419,2420],{"class":313},"a.LifeMonths",[35,2422,2031],{"class":978},[35,2424,2425],{"class":45},",0,",[35,2427,2012],{"class":978},[35,2429,2222],{"class":313},[35,2431,2031],{"class":978},[35,2433,2434],{"class":45},",2)\"\n",[35,2436,2437,2440],{"class":37,"line":503},[35,2438,2439],{"class":309},"    else",[35,2441,557],{"class":313},[35,2443,2444,2446,2448,2450,2453,2455,2457,2459,2461,2463,2465,2467,2469,2471,2473,2475,2478,2480,2482,2484],{"class":37,"line":520},[35,2445,2388],{"class":313},[35,2447,336],{"class":309},[35,2449,2393],{"class":309},[35,2451,2452],{"class":45},"\"=SLN(",[35,2454,2012],{"class":978},[35,2456,2401],{"class":313},[35,2458,2031],{"class":978},[35,2460,2406],{"class":45},[35,2462,2012],{"class":978},[35,2464,2411],{"class":313},[35,2466,2031],{"class":978},[35,2468,2406],{"class":45},[35,2470,2012],{"class":978},[35,2472,2420],{"class":313},[35,2474,2031],{"class":978},[35,2476,2477],{"class":45},")*",[35,2479,2012],{"class":978},[35,2481,2222],{"class":313},[35,2483,2031],{"class":978},[35,2485,2486],{"class":45},"\"\n",[35,2488,2489],{"class":37,"line":542},[35,2490,2491],{"class":313},"    ws.append([a.AssetID, k, python_acc, formula])\n",[35,2493,2494,2497,2500],{"class":37,"line":560},[35,2495,2496],{"class":313},"wb.save(",[35,2498,2499],{"class":45},"\"depreciation_check.xlsx\"",[35,2501,404],{"class":313},[25,2503,2505],{"className":27,"code":2504,"language":29,"meta":30,"style":30},"soffice -env:UserInstallation=file:\u002F\u002F$PWD\u002Flo_profile --headless --convert-to xlsx --outdir recalculated depreciation_check.xlsx > \u002Fdev\u002Fnull 2>&1\nls recalculated\n",[32,2506,2507,2548],{"__ignoreMap":30},[35,2508,2509,2512,2515,2518,2521,2524,2527,2530,2533,2536,2539,2542,2545],{"class":37,"line":38},[35,2510,2511],{"class":41},"soffice",[35,2513,2514],{"class":371}," -env:UserInstallation=file:\u002F\u002F",[35,2516,2517],{"class":313},"$PWD",[35,2519,2520],{"class":371},"\u002Flo_profile",[35,2522,2523],{"class":371}," --headless",[35,2525,2526],{"class":371}," --convert-to",[35,2528,2529],{"class":45}," xlsx",[35,2531,2532],{"class":371}," --outdir",[35,2534,2535],{"class":45}," recalculated",[35,2537,2538],{"class":45}," depreciation_check.xlsx",[35,2540,2541],{"class":309}," >",[35,2543,2544],{"class":45}," \u002Fdev\u002Fnull",[35,2546,2547],{"class":309}," 2>&1\n",[35,2549,2550,2553],{"class":37,"line":323},[35,2551,2552],{"class":41},"ls",[35,2554,2555],{"class":45}," recalculated\n",[25,2557,2559],{"className":300,"code":2558,"language":302,"meta":30,"style":30},"from openpyxl import load_workbook\n\nrows = list(load_workbook(\"recalculated\u002Fdepreciation_check.xlsx\", data_only=True).active.iter_rows(min_row=2, values_only=True))\nfor asset_id, k, py, xl in rows:\n    print(f\"{asset_id}: {k:3} months  python {py:10,.2f}  excel {xl:10,.2f}  diff {abs(py - xl):.4f}\")\n",[32,2560,2561,2572,2576,2622,2634],{"__ignoreMap":30},[35,2562,2563,2565,2567,2569],{"class":37,"line":38},[35,2564,2233],{"class":309},[35,2566,2236],{"class":313},[35,2568,310],{"class":309},[35,2570,2571],{"class":313}," load_workbook\n",[35,2573,2574],{"class":37,"line":323},[35,2575,327],{"emptyLinePlaceholder":326},[35,2577,2578,2581,2583,2586,2589,2592,2594,2597,2599,2601,2604,2607,2609,2611,2613,2616,2618,2620],{"class":37,"line":330},[35,2579,2580],{"class":313},"rows ",[35,2582,336],{"class":309},[35,2584,2585],{"class":371}," list",[35,2587,2588],{"class":313},"(load_workbook(",[35,2590,2591],{"class":45},"\"recalculated\u002Fdepreciation_check.xlsx\"",[35,2593,345],{"class":313},[35,2595,2596],{"class":348},"data_only",[35,2598,336],{"class":309},[35,2600,786],{"class":371},[35,2602,2603],{"class":313},").active.iter_rows(",[35,2605,2606],{"class":348},"min_row",[35,2608,336],{"class":309},[35,2610,822],{"class":371},[35,2612,345],{"class":313},[35,2614,2615],{"class":348},"values_only",[35,2617,336],{"class":309},[35,2619,786],{"class":371},[35,2621,844],{"class":313},[35,2623,2624,2626,2629,2631],{"class":37,"line":368},[35,2625,770],{"class":309},[35,2627,2628],{"class":313}," asset_id, k, py, xl ",[35,2630,494],{"class":309},[35,2632,2633],{"class":313}," rows:\n",[35,2635,2636,2639,2641,2643,2645,2647,2650,2652,2654,2656,2658,2661,2663,2666,2668,2671,2674,2676,2679,2681,2684,2686,2688,2691,2693,2696,2699,2701,2704,2707,2709,2711],{"class":37,"line":407},[35,2637,2638],{"class":371},"    print",[35,2640,2003],{"class":313},[35,2642,2006],{"class":309},[35,2644,975],{"class":45},[35,2646,2012],{"class":978},[35,2648,2649],{"class":313},"asset_id",[35,2651,2031],{"class":978},[35,2653,819],{"class":45},[35,2655,2012],{"class":978},[35,2657,2222],{"class":313},[35,2659,2660],{"class":309},":3",[35,2662,2031],{"class":978},[35,2664,2665],{"class":45}," months  python ",[35,2667,2012],{"class":978},[35,2669,2670],{"class":313},"py",[35,2672,2673],{"class":309},":10,.2f",[35,2675,2031],{"class":978},[35,2677,2678],{"class":45},"  excel ",[35,2680,2012],{"class":978},[35,2682,2683],{"class":313},"xl",[35,2685,2673],{"class":309},[35,2687,2031],{"class":978},[35,2689,2690],{"class":45},"  diff ",[35,2692,2012],{"class":978},[35,2694,2695],{"class":371},"abs",[35,2697,2698],{"class":313},"(py ",[35,2700,514],{"class":309},[35,2702,2703],{"class":313}," xl)",[35,2705,2706],{"class":309},":.4f",[35,2708,2031],{"class":978},[35,2710,975],{"class":45},[35,2712,404],{"class":313},[10,2714,2715,2716,2719,2720,2722,2723,2727,2728,2730],{},"Every asset agrees to the cent (the small differences are the Python totals' rounding to two decimals). Straight line agrees trivially; the declining balance assets agree too, which confirms the switch rule matches Excel's ",[32,2717,2718],{},"VDB"," with its default switch. (Excel's ",[32,2721,65],{}," function does ",[2724,2725,2726],"em",{},"not"," switch to straight line, so its totals never quite reach the salvage value — use ",[32,2729,2718],{}," when comparing.)",[20,2732,2734],{"id":2733},"writing-the-report","Writing the report",[10,2736,2737,2738,2742,2743,2746],{},"The workbook has three sheets: the monthly schedule, the roll-forward, and the register with book values and disposal results. The pattern is the same as in ",[14,2739,2741],{"href":2740},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-budget-vs-actual-variance-report\u002F","Build a Budget vs Actual Variance Report",": numbers written as values from pandas, totals as ",[32,2744,2745],{},"SUM"," formulas, a number format with thousands separators and negatives in brackets:",[25,2748,2750],{"className":300,"code":2749,"language":302,"meta":30,"style":30},"with pd.ExcelWriter(\"fixed_assets_fy2026.xlsx\", engine=\"xlsxwriter\") as xw:\n    schedule.round(2).to_excel(xw, sheet_name=\"Schedule\")\n    roll.round(2).to_excel(xw, sheet_name=\"Roll-forward\")\n    reg[[\"Description\", \"Category\", \"InService\", \"Cost\", \"Method\", \"LifeMonths\", \"AccumDep\", \"BookValue\", \"Disposed\"]] \\\n        .round({\"AccumDep\": 2, \"BookValue\": 2}).to_excel(xw, sheet_name=\"Register\")\n    fmt = xw.book.add_format({\"num_format\": \"#,##0.00;(#,##0.00)\"})\n    for name in (\"Schedule\", \"Roll-forward\"):\n        xw.sheets[name].set_column(1, 14, 12, fmt)\n        xw.sheets[name].set_column(0, 0, 14)\nprint(\"wrote fixed_assets_fy2026.xlsx\")\n",[32,2751,2752,2780,2800,2818,2862,2893,2914,2935,2954,2970],{"__ignoreMap":30},[35,2753,2754,2757,2760,2763,2765,2768,2770,2773,2775,2777],{"class":37,"line":38},[35,2755,2756],{"class":309},"with",[35,2758,2759],{"class":313}," pd.ExcelWriter(",[35,2761,2762],{"class":45},"\"fixed_assets_fy2026.xlsx\"",[35,2764,345],{"class":313},[35,2766,2767],{"class":348},"engine",[35,2769,336],{"class":309},[35,2771,2772],{"class":45},"\"xlsxwriter\"",[35,2774,444],{"class":313},[35,2776,317],{"class":309},[35,2778,2779],{"class":313}," xw:\n",[35,2781,2782,2785,2787,2790,2793,2795,2798],{"class":37,"line":323},[35,2783,2784],{"class":313},"    schedule.round(",[35,2786,822],{"class":371},[35,2788,2789],{"class":313},").to_excel(xw, ",[35,2791,2792],{"class":348},"sheet_name",[35,2794,336],{"class":309},[35,2796,2797],{"class":45},"\"Schedule\"",[35,2799,404],{"class":313},[35,2801,2802,2805,2807,2809,2811,2813,2816],{"class":37,"line":330},[35,2803,2804],{"class":313},"    roll.round(",[35,2806,822],{"class":371},[35,2808,2789],{"class":313},[35,2810,2792],{"class":348},[35,2812,336],{"class":309},[35,2814,2815],{"class":45},"\"Roll-forward\"",[35,2817,404],{"class":313},[35,2819,2820,2823,2825,2827,2829,2831,2833,2835,2837,2839,2842,2844,2847,2849,2851,2853,2855,2857,2859],{"class":37,"line":368},[35,2821,2822],{"class":313},"    reg[[",[35,2824,1529],{"class":45},[35,2826,345],{"class":313},[35,2828,1842],{"class":45},[35,2830,345],{"class":313},[35,2832,357],{"class":45},[35,2834,345],{"class":313},[35,2836,1443],{"class":45},[35,2838,345],{"class":313},[35,2840,2841],{"class":45},"\"Method\"",[35,2843,345],{"class":313},[35,2845,2846],{"class":45},"\"LifeMonths\"",[35,2848,345],{"class":313},[35,2850,1452],{"class":45},[35,2852,345],{"class":313},[35,2854,688],{"class":45},[35,2856,345],{"class":313},[35,2858,362],{"class":45},[35,2860,2861],{"class":313},"]] \\\n",[35,2863,2864,2867,2869,2871,2873,2875,2877,2879,2881,2884,2886,2888,2891],{"class":37,"line":407},[35,2865,2866],{"class":313},"        .round({",[35,2868,1452],{"class":45},[35,2870,819],{"class":313},[35,2872,822],{"class":371},[35,2874,345],{"class":313},[35,2876,688],{"class":45},[35,2878,819],{"class":313},[35,2880,822],{"class":371},[35,2882,2883],{"class":313},"}).to_excel(xw, ",[35,2885,2792],{"class":348},[35,2887,336],{"class":309},[35,2889,2890],{"class":45},"\"Register\"",[35,2892,404],{"class":313},[35,2894,2895,2898,2900,2903,2906,2908,2911],{"class":37,"line":412},[35,2896,2897],{"class":313},"    fmt ",[35,2899,336],{"class":309},[35,2901,2902],{"class":313}," xw.book.add_format({",[35,2904,2905],{"class":45},"\"num_format\"",[35,2907,819],{"class":313},[35,2909,2910],{"class":45},"\"#,##0.00;(#,##0.00)\"",[35,2912,2913],{"class":313},"})\n",[35,2915,2916,2918,2921,2923,2926,2928,2930,2932],{"class":37,"line":425},[35,2917,488],{"class":309},[35,2919,2920],{"class":313}," name ",[35,2922,494],{"class":309},[35,2924,2925],{"class":313}," (",[35,2927,2797],{"class":45},[35,2929,345],{"class":313},[35,2931,2815],{"class":45},[35,2933,2934],{"class":313},"):\n",[35,2936,2937,2940,2942,2944,2947,2949,2951],{"class":37,"line":431},[35,2938,2939],{"class":313},"        xw.sheets[name].set_column(",[35,2941,1016],{"class":371},[35,2943,345],{"class":313},[35,2945,2946],{"class":371},"14",[35,2948,345],{"class":313},[35,2950,1066],{"class":371},[35,2952,2953],{"class":313},", fmt)\n",[35,2955,2956,2958,2960,2962,2964,2966,2968],{"class":37,"line":457},[35,2957,2939],{"class":313},[35,2959,124],{"class":371},[35,2961,345],{"class":313},[35,2963,124],{"class":371},[35,2965,345],{"class":313},[35,2967,2946],{"class":371},[35,2969,404],{"class":313},[35,2971,2972,2974,2976,2979],{"class":37,"line":474},[35,2973,794],{"class":371},[35,2975,2003],{"class":313},[35,2977,2978],{"class":45},"\"wrote fixed_assets_fy2026.xlsx\"",[35,2980,404],{"class":313},[20,2982,2984],{"id":2983},"common-pitfalls","Common pitfalls",[75,2986,2987,2993,3002,3008,3014],{},[78,2988,2989,2992],{},[81,2990,2991],{},"Computing only the current year for declining balance."," The charge depends on every previous period; compute from the in-service date.",[78,2994,2995,2998,2999,3001],{},[81,2996,2997],{},"Using Excel's DDB for comparison."," It does not switch to straight line; ",[32,3000,2718],{}," does.",[78,3003,3004,3007],{},[81,3005,3006],{},"Depreciating below salvage."," Cap each charge at book value minus salvage.",[78,3009,3010,3013],{},[81,3011,3012],{},"Forgetting disposals in the roll-forward."," Remove both the cost and the accumulated depreciation of sold assets, or the closing figures carry assets that are gone.",[78,3015,3016,3019],{},[81,3017,3018],{},"An undocumented convention."," Full-month, mid-month and half-year conventions all give different numbers; state which one the schedule uses.",[20,3021,3023],{"id":3022},"conclusion","Conclusion",[10,3025,3026,3027,3030,3031,3033],{},"Compute each asset's depreciation for its whole life month by month — straight line, or double-declining balance with the switch to straight line and a salvage floor — then keep the year being reported. Pivot to a monthly schedule, take book values from the last month to date, calculate gains and losses on disposals, and build a roll-forward whose closing net book value matches the assets still held. Check the totals once against Excel's ",[32,3028,3029],{},"SLN"," and ",[32,3032,2718],{}," to confirm the rules match.",[20,3035,3037],{"id":3036},"frequently-asked-questions","Frequently asked questions",[10,3039,3040,3043],{},[81,3041,3042],{},"How do I calculate double-declining balance depreciation in Python?","\nEach period, charge 2 divided by the life in periods times the current book value, but no less than the straight-line charge over the remaining periods and no more than book value minus salvage. Compute from the start of the asset's life, not just the current year.",[10,3045,3046,3049],{},[81,3047,3048],{},"Which Excel function matches declining balance with a switch to straight line?","\nVDB. With the factor set to 2 and no_switch left as FALSE, VDB switches to straight line when that gives a larger charge, which is the usual accounting treatment. DDB does not switch.",[10,3051,3052,3055],{},[81,3053,3054],{},"How are disposals handled in a depreciation schedule?","\nDepreciate up to the disposal month, then remove the asset's cost and accumulated depreciation. The gain or loss is the proceeds minus the book value at disposal.",[10,3057,3058,3061],{},[81,3059,3060],{},"Should depreciation start in the month of purchase?","\nIt depends on the policy: the month after, the month of purchase, or half a month are all used. Pick one, apply it to every asset and state it on the report.",[20,3063,3065],{"id":3064},"related","Related",[75,3067,3068,3074,3081,3088,3093],{},[78,3069,3070,3071,3073],{},"Up one level: ",[14,3072,17],{"href":16}," — the rest of the finance reports.",[78,3075,3076,3080],{},[14,3077,3079],{"href":3078},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-loan-amortization-schedule-in-excel\u002F","Build a Loan Amortization Schedule in Excel"," — the financing side of an asset purchase.",[78,3082,3083,3087],{},[14,3084,3086],{"href":3085},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-profit-and-loss-statement-from-a-general-ledger\u002F","Build a Profit and Loss Statement from a General Ledger"," — where the charge lands.",[78,3089,3090,3092],{},[14,3091,2741],{"href":2740}," — the same report layout.",[78,3094,3095,3099],{},[14,3096,3098],{"href":3097},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frecalculate-excel-formulas-without-excel-in-python\u002F","Recalculate Excel Formulas Without Excel in Python"," — the LibreOffice check.",[3101,3102,3103],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .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}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":30,"searchDepth":323,"depth":323,"links":3105},[3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117],{"id":22,"depth":323,"text":23},{"id":69,"depth":323,"text":70},{"id":293,"depth":323,"text":294},{"id":858,"depth":323,"text":859},{"id":1363,"depth":323,"text":1364},{"id":1563,"depth":323,"text":1564},{"id":2203,"depth":323,"text":2204},{"id":2733,"depth":323,"text":2734},{"id":2983,"depth":323,"text":2984},{"id":3022,"depth":323,"text":3023},{"id":3036,"depth":323,"text":3037},{"id":3064,"depth":323,"text":3065},"2026-09-29","Turn a fixed asset register into a monthly depreciation schedule: straight-line and double-declining balance with the switch to straight line, a start-of-depreciation convention, disposals part way through the year, net book values, a cost and depreciation roll-forward by category, and a check against Excel's SLN and VDB functions.","md",[3122,3124,3126,3128],{"q":3042,"a":3123},"Each period, charge 2 divided by the life in periods times the current book value, but no less than the straight-line charge over the remaining periods and no more than book value minus salvage. Compute from the start of the asset's life, not just the current year.",{"q":3048,"a":3125},"VDB. With the factor set to 2 and no_switch left as FALSE, VDB switches to straight line when that gives a larger charge, which is the usual accounting treatment. DDB does not switch.",{"q":3054,"a":3127},"Depreciate up to the disposal month, then remove the asset's cost and accumulated depreciation. The gain or loss is the proceeds minus the book value at disposal.",{"q":3060,"a":3129},"It depends on the policy: the month after, the month of purchase, or half a month are all used. Pick one, apply it to every asset and state it on the report.","build a fixed asset depreciation schedule",null,{"breadcrumb":3133},[3134,3136,3139],{"name":3135,"item":536},"Home",{"name":3137,"item":3138},"Automating Reporting Workflows with Python and Excel","\u002Fautomating-reporting-workflows\u002F",{"name":3140,"item":16},"Building Finance and Operations Reports in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fixed-asset-depreciation-schedule",{"title":3143,"description":3144},"Fixed Asset Depreciation Schedule in Excel with Python","Build a monthly depreciation schedule from an asset register with pandas: straight-line, declining balance with SL switch, salvage value floor, disposals, NBV, roll-forward by category, verified against Excel SLN and VDB.","build-a-fixed-asset-depreciation-schedule","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fixed-asset-depreciation-schedule\u002Findex",[3148,3149],"report-layouts","formula-equivalents","how-to","wn96f7Xwmlhm5up-qNSDoO6ZgHMv0LkCjR7VAKFtDGE",[3153,3157],{"title":3154,"path":3155,"stem":3156,"children":-1},"Build a Discount Leakage Report","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-discount-leakage-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-discount-leakage-report\u002Findex",{"title":3158,"path":3159,"stem":3160,"children":-1},"Build a Fleet Mileage and Fuel Report","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fleet-mileage-and-fuel-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-fleet-mileage-and-fuel-report\u002Findex",[3162,3164],{"path":3163,"title":3140},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports",{"path":3165,"title":3137},"\u002Fautomating-reporting-workflows",[],[3168,3172,3175,3178,3181,3184],{"path":3169,"title":3170,"kind":3171},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards","Building Multi-Sheet Excel Dashboards","guide",{"path":3173,"title":3174,"kind":3150},"\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":3176,"title":3177,"kind":3150},"\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":3179,"title":3180,"kind":3150},"\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":3182,"title":3183,"kind":3150},"\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":3185,"title":3186,"kind":3150},"\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",1790972121470]