[{"data":1,"prerenderedAt":2465},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions":3,"surround:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions":2431,"ancestors:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions":2439,"children:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions":2444,"related:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions":2445},{"id":4,"title":5,"body":6,"dateModified":2397,"datePublished":2397,"description":2398,"extension":2399,"faq":2400,"keyword":2409,"kind":2410,"meta":2411,"navigation":91,"path":2421,"seo":2422,"slug":2425,"stem":2426,"topics":2427,"type":2429,"__hash__":2430},"docs\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions\u002Findex.md","Build a VAT Return Summary from Transactions",{"type":7,"value":8,"toc":2386},"minimark",[9,19,24,53,56,60,63,367,370,550,554,561,1097,1109,1253,1257,1758,1761,1827,1831,1834,2261,2272,2276,2314,2318,2321,2325,2331,2337,2343,2349,2353,2382],[10,11,12,13,18],"p",{},"Every VAT quarter, someone turns the period's transactions into the handful of figures a return asks for: VAT charged on sales, VAT reclaimable on purchases, the net amount due, and the value of sales and purchases. Accounting systems produce the return themselves, but finance teams still build their own summary — to review the figures before filing, to combine several entities or systems, or because part of the data lives outside the ledger. The calculation is simple arithmetic; the difficulty is getting every tax code into the right box, spotting lines where the VAT does not match the rate, and being able to show a reviewer exactly which transactions make up each figure. This page builds that summary with pandas, using the UK's nine-box return as the worked example, with the code-to-box rules held in a table so they can be adapted to other countries' returns. 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 quarter's transactions — one row per invoice line with type (sale or purchase), tax code, net amount and the VAT amount as recorded in the ledger. The tax codes are standard rate (S, 20%), reduced rate (R, 5%), zero-rated (Z), exempt (E), outside the scope of VAT (OS, such as wages or some fees) and reverse charge (RC, services bought from abroad, where the buyer accounts for the VAT). The box rules below follow the UK return; they are an illustration of the technique, not tax advice, so confirm the treatment of your codes with current guidance or your adviser.",[20,57,59],{"id":58},"step-1-load-and-check-every-lines-vat","Step 1 — Load and check every line's VAT",[10,61,62],{},"Before summarising, check that each line's recorded VAT matches its net amount times its rate. Differences of a penny are rounding; anything more is a coding or keying error that should be fixed before the return, not discovered after:",[25,64,68],{"className":65,"code":66,"language":67,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\ntx = pd.read_excel(\"vat_q3_transactions.xlsx\")\nRATES = {\"S\": 0.20, \"R\": 0.05, \"Z\": 0.0, \"E\": 0.0, \"OS\": 0.0, \"RC\": 0.0}\ntx[\"Expected VAT\"] = (tx[\"Net\"] * tx[\"Tax code\"].map(RATES)).round(2)\ntx[\"VAT diff\"] = (tx[\"VAT\"] - tx[\"Expected VAT\"]).round(2)\nexceptions = tx[tx[\"VAT diff\"].abs() > 0.01]\nprint(len(tx), \"lines;\", len(exceptions), \"with VAT not matching the rate\")\nprint(exceptions[[\"Ref\", \"Type\", \"Tax code\", \"Net\", \"VAT\", \"Expected VAT\", \"VAT diff\"]].to_string(index=False))\n","python",[32,69,70,86,93,111,184,228,261,286,316],{"__ignoreMap":30},[35,71,72,76,80,83],{"class":37,"line":38},[35,73,75],{"class":74},"s-kum","import",[35,77,79],{"class":78},"skGVy"," pandas ",[35,81,82],{"class":74},"as",[35,84,85],{"class":78}," pd\n",[35,87,89],{"class":37,"line":88},2,[35,90,92],{"emptyLinePlaceholder":91},true,"\n",[35,94,96,99,102,105,108],{"class":37,"line":95},3,[35,97,98],{"class":78},"tx ",[35,100,101],{"class":74},"=",[35,103,104],{"class":78}," pd.read_excel(",[35,106,107],{"class":45},"\"vat_q3_transactions.xlsx\"",[35,109,110],{"class":78},")\n",[35,112,114,118,121,124,127,130,133,136,139,141,144,146,149,151,154,156,159,161,163,165,168,170,172,174,177,179,181],{"class":37,"line":113},4,[35,115,117],{"class":116},"sP0c6","RATES",[35,119,120],{"class":74}," =",[35,122,123],{"class":78}," {",[35,125,126],{"class":45},"\"S\"",[35,128,129],{"class":78},": ",[35,131,132],{"class":116},"0.20",[35,134,135],{"class":78},", ",[35,137,138],{"class":45},"\"R\"",[35,140,129],{"class":78},[35,142,143],{"class":116},"0.05",[35,145,135],{"class":78},[35,147,148],{"class":45},"\"Z\"",[35,150,129],{"class":78},[35,152,153],{"class":116},"0.0",[35,155,135],{"class":78},[35,157,158],{"class":45},"\"E\"",[35,160,129],{"class":78},[35,162,153],{"class":116},[35,164,135],{"class":78},[35,166,167],{"class":45},"\"OS\"",[35,169,129],{"class":78},[35,171,153],{"class":116},[35,173,135],{"class":78},[35,175,176],{"class":45},"\"RC\"",[35,178,129],{"class":78},[35,180,153],{"class":116},[35,182,183],{"class":78},"}\n",[35,185,187,190,193,196,198,201,204,206,209,212,215,218,220,223,226],{"class":37,"line":186},5,[35,188,189],{"class":78},"tx[",[35,191,192],{"class":45},"\"Expected VAT\"",[35,194,195],{"class":78},"] ",[35,197,101],{"class":74},[35,199,200],{"class":78}," (tx[",[35,202,203],{"class":45},"\"Net\"",[35,205,195],{"class":78},[35,207,208],{"class":74},"*",[35,210,211],{"class":78}," tx[",[35,213,214],{"class":45},"\"Tax code\"",[35,216,217],{"class":78},"].map(",[35,219,117],{"class":116},[35,221,222],{"class":78},")).round(",[35,224,225],{"class":116},"2",[35,227,110],{"class":78},[35,229,231,233,236,238,240,242,245,247,250,252,254,257,259],{"class":37,"line":230},6,[35,232,189],{"class":78},[35,234,235],{"class":45},"\"VAT diff\"",[35,237,195],{"class":78},[35,239,101],{"class":74},[35,241,200],{"class":78},[35,243,244],{"class":45},"\"VAT\"",[35,246,195],{"class":78},[35,248,249],{"class":74},"-",[35,251,211],{"class":78},[35,253,192],{"class":45},[35,255,256],{"class":78},"]).round(",[35,258,225],{"class":116},[35,260,110],{"class":78},[35,262,264,267,269,272,274,277,280,283],{"class":37,"line":263},7,[35,265,266],{"class":78},"exceptions ",[35,268,101],{"class":74},[35,270,271],{"class":78}," tx[tx[",[35,273,235],{"class":45},[35,275,276],{"class":78},"].abs() ",[35,278,279],{"class":74},">",[35,281,282],{"class":116}," 0.01",[35,284,285],{"class":78},"]\n",[35,287,289,292,295,298,301,304,306,308,311,314],{"class":37,"line":288},8,[35,290,291],{"class":116},"print",[35,293,294],{"class":78},"(",[35,296,297],{"class":116},"len",[35,299,300],{"class":78},"(tx), ",[35,302,303],{"class":45},"\"lines;\"",[35,305,135],{"class":78},[35,307,297],{"class":116},[35,309,310],{"class":78},"(exceptions), ",[35,312,313],{"class":45},"\"with VAT not matching the rate\"",[35,315,110],{"class":78},[35,317,319,321,324,327,329,332,334,336,338,340,342,344,346,348,350,352,355,359,361,364],{"class":37,"line":318},9,[35,320,291],{"class":116},[35,322,323],{"class":78},"(exceptions[[",[35,325,326],{"class":45},"\"Ref\"",[35,328,135],{"class":78},[35,330,331],{"class":45},"\"Type\"",[35,333,135],{"class":78},[35,335,214],{"class":45},[35,337,135],{"class":78},[35,339,203],{"class":45},[35,341,135],{"class":78},[35,343,244],{"class":45},[35,345,135],{"class":78},[35,347,192],{"class":45},[35,349,135],{"class":78},[35,351,235],{"class":45},[35,353,354],{"class":78},"]].to_string(",[35,356,358],{"class":357},"sa561","index",[35,360,101],{"class":74},[35,362,363],{"class":116},"False",[35,365,366],{"class":78},"))\n",[10,368,369],{},"Two lines out of 172 fail. One sale carries 12.40 more VAT than its rate gives — perhaps a keying error. One standard-rated purchase has VAT at 5% — either the code or the amount is wrong, and only the invoice will tell which. Reverse-charge lines record no VAT on the invoice, because the supplier does not charge it; the VAT is calculated by the buyer, in the next step. The exceptions go on their own sheet so they are resolved, or consciously accepted, before filing.",[371,372,380,381,380,385,380,389,380,397,380,407,380,418,380,425,380,430,380,434,380,440,380,445,380,450,380,457,380,462,380,465,380,468,380,472,380,475,380,479,380,486,380,491,380,495,380,498,380,502,380,505,380,510,380,517,380,523,380,527,380,531,380,534,380,537,380,543,380,547],"svg",{"viewBox":373,"role":374,"ariaLabelledBy":375,"xmlns":378,"style":379},"4 0 752 142","img",[376,377],"vat-flow-t","vat-flow-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  ",[382,383,384],"title",{"id":376},"From transactions to return boxes",[386,387,388],"desc",{"id":377},"Each transaction's VAT is checked against its rate and exceptions are listed. A mapping table assigns each type and tax code to return boxes, reverse charge lines generate both output and input VAT, the boxes are summed, and the totals are reconciled to the ledger's VAT accounts.",[390,391],"rect",{"x":392,"y":393,"width":394,"height":395,"fill":396},"4","0","752","142","#ffffff",[390,398],{"x":399,"y":400,"width":401,"height":402,"rx":403,"fill":404,"stroke":405,"style":406},"20.0","16.0","115.2","110.5","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[408,409,411],"g",{"transform":410},"translate(65.6,29.0) scale(1.000)",[412,413],"path",{"d":414,"fill":415,"stroke":416,"style":417},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[419,420,424],"text",{"x":421,"y":422,"style":423},"77.6","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Transactions",[419,426,429],{"x":421,"y":427,"style":428},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","type, code, net,",[419,431,433],{"x":421,"y":432,"style":428},"112.5","VAT",[37,435],{"x1":436,"y1":437,"x2":438,"y2":437,"stroke":439,"style":406},"140.2","71.2","162.2","var(--brand,#5b5cf0)",[441,442],"polygon",{"points":443,"fill":444},"166.2,71.2 157.2,76.2 157.2,66.2","#5b5cf0",[390,446],{"x":447,"y":400,"width":401,"height":402,"rx":403,"fill":448,"stroke":449,"style":406},"171.2","#fdefd8","var(--gold,#b4740a)",[408,451,453],{"transform":452},"translate(216.8,29.0) scale(1.000)",[412,454],{"d":455,"fill":415,"stroke":456,"style":417},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--gold-ink,#7a4e06)",[419,458,461],{"x":459,"y":422,"style":460},"228.8","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Check VAT",[419,463,464],{"x":459,"y":427,"style":428},"rate × net,",[419,466,467],{"x":459,"y":432,"style":428},"exceptions",[37,469],{"x1":470,"y1":437,"x2":471,"y2":437,"stroke":439,"style":406},"291.4","313.4",[441,473],{"points":474,"fill":444},"317.4,71.2 308.4,76.2 308.4,66.2",[390,476],{"x":477,"y":400,"width":401,"height":402,"rx":403,"fill":478,"stroke":439,"style":406},"322.4","#f0f4ff",[408,480,482],{"transform":481},"translate(368.0,29.0) scale(1.000)",[412,483],{"d":484,"fill":415,"stroke":485,"style":417},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5","var(--brand-strong,#4338ca)",[419,487,490],{"x":488,"y":422,"style":489},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Map to",[419,492,494],{"x":488,"y":493,"style":489},"93.0","boxes",[419,496,497],{"x":488,"y":432,"style":428},"table, not code",[37,499],{"x1":500,"y1":437,"x2":501,"y2":437,"stroke":439,"style":406},"442.6","464.6",[441,503],{"points":504,"fill":444},"468.6,71.2 459.6,76.2 459.6,66.2",[390,506],{"x":507,"y":400,"width":401,"height":402,"rx":403,"fill":508,"stroke":509,"style":406},"473.6","#d9f4f1","var(--teal,#0f9488)",[408,511,513],{"transform":512},"translate(519.2,37.8) scale(1.000)",[412,514],{"d":515,"fill":415,"stroke":516,"style":417},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","var(--teal-ink,#0b6157)",[419,518,522],{"x":519,"y":520,"style":521},"531.2","84.2","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Sum boxes",[419,524,526],{"x":519,"y":525,"style":428},"103.8","1–9",[37,528],{"x1":529,"y1":437,"x2":530,"y2":437,"stroke":439,"style":406},"593.8","615.8",[441,532],{"points":533,"fill":444},"619.8,71.2 610.8,76.2 610.8,66.2",[390,535],{"x":536,"y":400,"width":401,"height":402,"rx":403,"fill":404,"stroke":405,"style":406},"624.8",[408,538,540],{"transform":539},"translate(670.4,37.8) scale(1.000)",[412,541],{"d":542,"fill":415,"stroke":416,"style":417},"M5 12.5l4.5 4.5L19 7",[419,544,546],{"x":545,"y":520,"style":423},"682.4","Reconcile",[419,548,549],{"x":545,"y":525,"style":428},"to the ledger",[20,551,553],{"id":552},"step-2-map-tax-codes-to-boxes-with-a-table","Step 2 — Map tax codes to boxes with a table",[10,555,556,557,560],{},"Which box a line feeds depends on its type and tax code. Writing that as ",[32,558,559],{},"if"," statements buries the tax rules in code; a mapping table keeps them visible and reviewable, and lets another country's return reuse the same program with a different table:",[25,562,564],{"className":65,"code":563,"language":67,"meta":30,"style":30},"MAP = pd.DataFrame([\n    # type,       code, net box, output VAT box, input VAT box\n    (\"sale\",      \"S\",  6,   1,    None),\n    (\"sale\",      \"R\",  6,   1,    None),\n    (\"sale\",      \"Z\",  6,   None, None),\n    (\"sale\",      \"E\",  6,   None, None),\n    (\"sale\",      \"OS\", None, None, None),\n    (\"purchase\",  \"S\",  7,   None, 4),\n    (\"purchase\",  \"R\",  7,   None, 4),\n    (\"purchase\",  \"Z\",  7,   None, None),\n    (\"purchase\",  \"E\",  7,   None, None),\n    (\"purchase\",  \"OS\", None, None, None),\n    (\"purchase\",  \"RC\", \"6+7\", 1,  4),\n], columns=[\"Type\", \"Tax code\", \"Net box\", \"Output box\", \"Input box\"])\n\nlines = tx.merge(MAP, on=[\"Type\", \"Tax code\"], how=\"left\", validate=\"many_to_one\", indicator=True)\nunmapped = lines[lines[\"_merge\"] == \"left_only\"]\nassert unmapped.empty, f\"unmapped tax codes: {unmapped[['Type', 'Tax code']].drop_duplicates().values.tolist()}\"\nlines[\"RC VAT\"] = (lines[\"Net\"] * 0.20).where(lines[\"Tax code\"] == \"RC\", 0.0).round(2)\nprint(MAP.to_string(index=False))\n",[32,565,566,576,582,616,640,664,688,712,738,762,787,812,837,863,901,906,966,990,1029,1077],{"__ignoreMap":30},[35,567,568,571,573],{"class":37,"line":38},[35,569,570],{"class":116},"MAP",[35,572,120],{"class":74},[35,574,575],{"class":78}," pd.DataFrame([\n",[35,577,578],{"class":37,"line":88},[35,579,581],{"class":580},"s-wDw","    # type,       code, net box, output VAT box, input VAT box\n",[35,583,584,587,590,593,595,598,601,604,607,610,613],{"class":37,"line":95},[35,585,586],{"class":78},"    (",[35,588,589],{"class":45},"\"sale\"",[35,591,592],{"class":78},",      ",[35,594,126],{"class":45},[35,596,597],{"class":78},",  ",[35,599,600],{"class":116},"6",[35,602,603],{"class":78},",   ",[35,605,606],{"class":116},"1",[35,608,609],{"class":78},",    ",[35,611,612],{"class":116},"None",[35,614,615],{"class":78},"),\n",[35,617,618,620,622,624,626,628,630,632,634,636,638],{"class":37,"line":113},[35,619,586],{"class":78},[35,621,589],{"class":45},[35,623,592],{"class":78},[35,625,138],{"class":45},[35,627,597],{"class":78},[35,629,600],{"class":116},[35,631,603],{"class":78},[35,633,606],{"class":116},[35,635,609],{"class":78},[35,637,612],{"class":116},[35,639,615],{"class":78},[35,641,642,644,646,648,650,652,654,656,658,660,662],{"class":37,"line":186},[35,643,586],{"class":78},[35,645,589],{"class":45},[35,647,592],{"class":78},[35,649,148],{"class":45},[35,651,597],{"class":78},[35,653,600],{"class":116},[35,655,603],{"class":78},[35,657,612],{"class":116},[35,659,135],{"class":78},[35,661,612],{"class":116},[35,663,615],{"class":78},[35,665,666,668,670,672,674,676,678,680,682,684,686],{"class":37,"line":230},[35,667,586],{"class":78},[35,669,589],{"class":45},[35,671,592],{"class":78},[35,673,158],{"class":45},[35,675,597],{"class":78},[35,677,600],{"class":116},[35,679,603],{"class":78},[35,681,612],{"class":116},[35,683,135],{"class":78},[35,685,612],{"class":116},[35,687,615],{"class":78},[35,689,690,692,694,696,698,700,702,704,706,708,710],{"class":37,"line":263},[35,691,586],{"class":78},[35,693,589],{"class":45},[35,695,592],{"class":78},[35,697,167],{"class":45},[35,699,135],{"class":78},[35,701,612],{"class":116},[35,703,135],{"class":78},[35,705,612],{"class":116},[35,707,135],{"class":78},[35,709,612],{"class":116},[35,711,615],{"class":78},[35,713,714,716,719,721,723,725,728,730,732,734,736],{"class":37,"line":288},[35,715,586],{"class":78},[35,717,718],{"class":45},"\"purchase\"",[35,720,597],{"class":78},[35,722,126],{"class":45},[35,724,597],{"class":78},[35,726,727],{"class":116},"7",[35,729,603],{"class":78},[35,731,612],{"class":116},[35,733,135],{"class":78},[35,735,392],{"class":116},[35,737,615],{"class":78},[35,739,740,742,744,746,748,750,752,754,756,758,760],{"class":37,"line":318},[35,741,586],{"class":78},[35,743,718],{"class":45},[35,745,597],{"class":78},[35,747,138],{"class":45},[35,749,597],{"class":78},[35,751,727],{"class":116},[35,753,603],{"class":78},[35,755,612],{"class":116},[35,757,135],{"class":78},[35,759,392],{"class":116},[35,761,615],{"class":78},[35,763,765,767,769,771,773,775,777,779,781,783,785],{"class":37,"line":764},10,[35,766,586],{"class":78},[35,768,718],{"class":45},[35,770,597],{"class":78},[35,772,148],{"class":45},[35,774,597],{"class":78},[35,776,727],{"class":116},[35,778,603],{"class":78},[35,780,612],{"class":116},[35,782,135],{"class":78},[35,784,612],{"class":116},[35,786,615],{"class":78},[35,788,790,792,794,796,798,800,802,804,806,808,810],{"class":37,"line":789},11,[35,791,586],{"class":78},[35,793,718],{"class":45},[35,795,597],{"class":78},[35,797,158],{"class":45},[35,799,597],{"class":78},[35,801,727],{"class":116},[35,803,603],{"class":78},[35,805,612],{"class":116},[35,807,135],{"class":78},[35,809,612],{"class":116},[35,811,615],{"class":78},[35,813,815,817,819,821,823,825,827,829,831,833,835],{"class":37,"line":814},12,[35,816,586],{"class":78},[35,818,718],{"class":45},[35,820,597],{"class":78},[35,822,167],{"class":45},[35,824,135],{"class":78},[35,826,612],{"class":116},[35,828,135],{"class":78},[35,830,612],{"class":116},[35,832,135],{"class":78},[35,834,612],{"class":116},[35,836,615],{"class":78},[35,838,840,842,844,846,848,850,853,855,857,859,861],{"class":37,"line":839},13,[35,841,586],{"class":78},[35,843,718],{"class":45},[35,845,597],{"class":78},[35,847,176],{"class":45},[35,849,135],{"class":78},[35,851,852],{"class":45},"\"6+7\"",[35,854,135],{"class":78},[35,856,606],{"class":116},[35,858,597],{"class":78},[35,860,392],{"class":116},[35,862,615],{"class":78},[35,864,866,869,872,874,877,879,881,883,885,888,890,893,895,898],{"class":37,"line":865},14,[35,867,868],{"class":78},"], ",[35,870,871],{"class":357},"columns",[35,873,101],{"class":74},[35,875,876],{"class":78},"[",[35,878,331],{"class":45},[35,880,135],{"class":78},[35,882,214],{"class":45},[35,884,135],{"class":78},[35,886,887],{"class":45},"\"Net box\"",[35,889,135],{"class":78},[35,891,892],{"class":45},"\"Output box\"",[35,894,135],{"class":78},[35,896,897],{"class":45},"\"Input box\"",[35,899,900],{"class":78},"])\n",[35,902,904],{"class":37,"line":903},15,[35,905,92],{"emptyLinePlaceholder":91},[35,907,909,912,914,917,919,921,924,926,928,930,932,934,936,939,941,944,946,949,951,954,956,959,961,964],{"class":37,"line":908},16,[35,910,911],{"class":78},"lines ",[35,913,101],{"class":74},[35,915,916],{"class":78}," tx.merge(",[35,918,570],{"class":116},[35,920,135],{"class":78},[35,922,923],{"class":357},"on",[35,925,101],{"class":74},[35,927,876],{"class":78},[35,929,331],{"class":45},[35,931,135],{"class":78},[35,933,214],{"class":45},[35,935,868],{"class":78},[35,937,938],{"class":357},"how",[35,940,101],{"class":74},[35,942,943],{"class":45},"\"left\"",[35,945,135],{"class":78},[35,947,948],{"class":357},"validate",[35,950,101],{"class":74},[35,952,953],{"class":45},"\"many_to_one\"",[35,955,135],{"class":78},[35,957,958],{"class":357},"indicator",[35,960,101],{"class":74},[35,962,963],{"class":116},"True",[35,965,110],{"class":78},[35,967,969,972,974,977,980,982,985,988],{"class":37,"line":968},17,[35,970,971],{"class":78},"unmapped ",[35,973,101],{"class":74},[35,975,976],{"class":78}," lines[lines[",[35,978,979],{"class":45},"\"_merge\"",[35,981,195],{"class":78},[35,983,984],{"class":74},"==",[35,986,987],{"class":45}," \"left_only\"",[35,989,285],{"class":78},[35,991,993,996,999,1002,1005,1009,1012,1015,1017,1020,1023,1026],{"class":37,"line":992},18,[35,994,995],{"class":74},"assert",[35,997,998],{"class":78}," unmapped.empty, ",[35,1000,1001],{"class":74},"f",[35,1003,1004],{"class":45},"\"unmapped tax codes: ",[35,1006,1008],{"class":1007},"sSjpA","{",[35,1010,1011],{"class":78},"unmapped[[",[35,1013,1014],{"class":45},"'Type'",[35,1016,135],{"class":78},[35,1018,1019],{"class":45},"'Tax code'",[35,1021,1022],{"class":78},"]].drop_duplicates().values.tolist()",[35,1024,1025],{"class":1007},"}",[35,1027,1028],{"class":45},"\"\n",[35,1030,1032,1035,1038,1040,1042,1045,1047,1049,1051,1054,1057,1059,1061,1063,1066,1068,1070,1073,1075],{"class":37,"line":1031},19,[35,1033,1034],{"class":78},"lines[",[35,1036,1037],{"class":45},"\"RC VAT\"",[35,1039,195],{"class":78},[35,1041,101],{"class":74},[35,1043,1044],{"class":78}," (lines[",[35,1046,203],{"class":45},[35,1048,195],{"class":78},[35,1050,208],{"class":74},[35,1052,1053],{"class":116}," 0.20",[35,1055,1056],{"class":78},").where(lines[",[35,1058,214],{"class":45},[35,1060,195],{"class":78},[35,1062,984],{"class":74},[35,1064,1065],{"class":45}," \"RC\"",[35,1067,135],{"class":78},[35,1069,153],{"class":116},[35,1071,1072],{"class":78},").round(",[35,1074,225],{"class":116},[35,1076,110],{"class":78},[35,1078,1080,1082,1084,1086,1089,1091,1093,1095],{"class":37,"line":1079},20,[35,1081,291],{"class":116},[35,1083,294],{"class":78},[35,1085,570],{"class":116},[35,1087,1088],{"class":78},".to_string(",[35,1090,358],{"class":357},[35,1092,101],{"class":74},[35,1094,363],{"class":116},[35,1096,366],{"class":78},[10,1098,1099,1100,1104,1105,1108],{},"Zero-rated and exempt sales carry no VAT but still count in the value of sales (box 6); out-of-scope items appear nowhere. Reverse charge is the interesting row: the buyer accounts for VAT as if it had made the sale ",[1101,1102,1103],"em",{},"and"," reclaims it as input VAT, so the same amount goes into box 1 and box 4 — it usually nets to zero — and the net value appears in both box 6 and box 7. The ",[32,1106,1107],{},"validate=\"many_to_one\""," guard makes the merge fail if the table accidentally has two rows for one code, and the assertion fails the run if a transaction uses a code the table does not know — the safe behaviour, since a new code silently ignored means a wrong return.",[371,1110,380,1115,380,1118,380,1121,380,1124,380,1129,380,1134,380,1140,380,1143,380,1147,380,1151,380,1157,380,1159,380,1163,380,1165,380,1168,380,1171,380,1175,380,1177,380,1181,380,1183,380,1185,380,1188,380,1192,380,1194,380,1198,380,1200,380,1203,380,1206,380,1210,380,1212,380,1215,380,1217,380,1219,380,1222,380,1226,380,1228,380,1232,380,1234,380,1237,380,1240,380,1244,380,1246,380,1249,380,1251],{"viewBox":1111,"role":374,"ariaLabelledBy":1112,"xmlns":378,"style":379},"4 0 752 276",[1113,1114],"vat-map-t","vat-map-d",[382,1116,1117],{"id":1113},"Where each kind of line goes on the return",[386,1119,1120],{"id":1114},"Standard and reduced-rate sales put VAT in box 1 and the net value in box 6. Zero-rated and exempt sales go only to box 6. Purchases with VAT put it in box 4 and the net in box 7. Reverse charge purchases put the self-assessed VAT in both box 1 and box 4 and the net in boxes 6 and 7. Out-of-scope items appear nowhere.",[390,1122],{"x":392,"y":393,"width":394,"height":1123,"fill":396},"276",[390,1125],{"x":399,"y":400,"width":1126,"height":1127,"rx":393,"fill":396,"stroke":405,"style":1128},"120.1","40.0","stroke-width:1px",[390,1130],{"x":1131,"y":400,"width":1132,"height":1127,"rx":393,"fill":478,"stroke":439,"style":1133},"140.1","299.9","stroke-width:1.2px",[419,1135,1139],{"x":1136,"y":1137,"style":1138},"290.1","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","VAT box",[390,1141],{"x":1142,"y":400,"width":1132,"height":1127,"rx":393,"fill":478,"stroke":439,"style":1133},"440.1",[419,1144,1146],{"x":1145,"y":1137,"style":1138},"590.0","value box",[390,1148],{"x":399,"y":1149,"width":1126,"height":1150,"rx":393,"fill":404,"stroke":405,"style":1128},"56.0","34.0",[419,1152,1156],{"x":1153,"y":1154,"style":1155},"32.0","78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","sale S \u002F R",[390,1158],{"x":1131,"y":1149,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1160,1162],{"x":1136,"y":1161,"style":428},"77.0","box 1",[390,1164],{"x":1142,"y":1149,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1166,1167],{"x":1145,"y":1161,"style":428},"box 6",[390,1169],{"x":399,"y":1170,"width":1126,"height":1150,"rx":393,"fill":404,"stroke":405,"style":1128},"90.0",[419,1172,1174],{"x":1153,"y":1173,"style":1155},"112.0","sale Z \u002F E",[390,1176],{"x":1131,"y":1170,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1178,1180],{"x":1136,"y":1179,"style":428},"111.0","—",[390,1182],{"x":1142,"y":1170,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1184,1167],{"x":1145,"y":1179,"style":428},[390,1186],{"x":399,"y":1187,"width":1126,"height":1150,"rx":393,"fill":404,"stroke":405,"style":1128},"124.0",[419,1189,1191],{"x":1153,"y":1190,"style":1155},"146.0","purchase S \u002F R",[390,1193],{"x":1131,"y":1187,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1195,1197],{"x":1136,"y":1196,"style":428},"145.0","box 4",[390,1199],{"x":1142,"y":1187,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1201,1202],{"x":1145,"y":1196,"style":428},"box 7",[390,1204],{"x":399,"y":1205,"width":1126,"height":1150,"rx":393,"fill":404,"stroke":405,"style":1128},"158.0",[419,1207,1209],{"x":1153,"y":1208,"style":1155},"180.0","purchase Z \u002F E",[390,1211],{"x":1131,"y":1205,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1213,1180],{"x":1136,"y":1214,"style":428},"179.0",[390,1216],{"x":1142,"y":1205,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1218,1202],{"x":1145,"y":1214,"style":428},[390,1220],{"x":399,"y":1221,"width":1126,"height":1150,"rx":393,"fill":404,"stroke":405,"style":1128},"192.0",[419,1223,1225],{"x":1153,"y":1224,"style":1155},"214.0","purchase RC",[390,1227],{"x":1131,"y":1221,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1229,1231],{"x":1136,"y":1230,"style":428},"213.0","boxes 1 and 4",[390,1233],{"x":1142,"y":1221,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1235,1236],{"x":1145,"y":1230,"style":428},"boxes 6 and 7",[390,1238],{"x":399,"y":1239,"width":1126,"height":1150,"rx":393,"fill":404,"stroke":405,"style":1128},"226.0",[419,1241,1243],{"x":1153,"y":1242,"style":1155},"248.0","OS",[390,1245],{"x":1131,"y":1239,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1247,1180],{"x":1136,"y":1248,"style":428},"247.0",[390,1250],{"x":1142,"y":1239,"width":1132,"height":1150,"rx":393,"fill":396,"stroke":405,"style":1128},[419,1252,1180],{"x":1145,"y":1248,"style":428},[20,1254,1256],{"id":1255},"step-3-sum-the-boxes","Step 3 — Sum the boxes",[25,1258,1260],{"className":65,"code":1259,"language":67,"meta":30,"style":30},"def box_sum(mask, column):\n    return round(float(lines.loc[mask, column].sum()), 2)\n\nnet6 = lines[\"Net box\"].astype(str).str.contains(\"6\")\nnet7 = lines[\"Net box\"].astype(str).str.contains(\"7\")\nboxes = {\n    1: box_sum(lines[\"Output box\"] == 1, \"VAT\") + box_sum(lines[\"Tax code\"] == \"RC\", \"RC VAT\"),\n    2: 0.0,\n    4: box_sum(lines[\"Input box\"] == 4, \"VAT\") + box_sum(lines[\"Tax code\"] == \"RC\", \"RC VAT\"),\n    6: round(float(lines.loc[net6, \"Net\"].sum())),\n    7: round(float(lines.loc[net7, \"Net\"].sum())),\n    8: 0, 9: 0,\n}\nboxes[3] = round(boxes[1] + boxes[2], 2)\nboxes[5] = round(boxes[3] - boxes[4], 2)\nLABELS = {1: \"VAT due on sales and other outputs\", 2: \"VAT due on acquisitions (NI only)\", 3: \"Total VAT due\",\n          4: \"VAT reclaimed on purchases and other inputs\", 5: \"Net VAT to pay (or reclaim)\",\n          6: \"Total value of sales, excluding VAT\", 7: \"Total value of purchases, excluding VAT\",\n          8: \"Supplies of goods to the EU (NI only)\", 9: \"Acquisitions of goods from the EU (NI only)\"}\nsummary = pd.DataFrame({\"Box\": list(LABELS), \"Description\": list(LABELS.values()), \"Amount\": [boxes[b] for b in LABELS]})\nprint(summary.to_string(index=False))\n",[32,1261,1262,1274,1294,1298,1324,1346,1356,1400,1412,1452,1474,1494,1514,1518,1552,1583,1619,1640,1661,1682,1742],{"__ignoreMap":30},[35,1263,1264,1267,1271],{"class":37,"line":38},[35,1265,1266],{"class":74},"def",[35,1268,1270],{"class":1269},"s_Opv"," box_sum",[35,1272,1273],{"class":78},"(mask, column):\n",[35,1275,1276,1279,1282,1284,1287,1290,1292],{"class":37,"line":88},[35,1277,1278],{"class":74},"    return",[35,1280,1281],{"class":116}," round",[35,1283,294],{"class":78},[35,1285,1286],{"class":116},"float",[35,1288,1289],{"class":78},"(lines.loc[mask, column].sum()), ",[35,1291,225],{"class":116},[35,1293,110],{"class":78},[35,1295,1296],{"class":37,"line":95},[35,1297,92],{"emptyLinePlaceholder":91},[35,1299,1300,1303,1305,1308,1310,1313,1316,1319,1322],{"class":37,"line":113},[35,1301,1302],{"class":78},"net6 ",[35,1304,101],{"class":74},[35,1306,1307],{"class":78}," lines[",[35,1309,887],{"class":45},[35,1311,1312],{"class":78},"].astype(",[35,1314,1315],{"class":116},"str",[35,1317,1318],{"class":78},").str.contains(",[35,1320,1321],{"class":45},"\"6\"",[35,1323,110],{"class":78},[35,1325,1326,1329,1331,1333,1335,1337,1339,1341,1344],{"class":37,"line":186},[35,1327,1328],{"class":78},"net7 ",[35,1330,101],{"class":74},[35,1332,1307],{"class":78},[35,1334,887],{"class":45},[35,1336,1312],{"class":78},[35,1338,1315],{"class":116},[35,1340,1318],{"class":78},[35,1342,1343],{"class":45},"\"7\"",[35,1345,110],{"class":78},[35,1347,1348,1351,1353],{"class":37,"line":230},[35,1349,1350],{"class":78},"boxes ",[35,1352,101],{"class":74},[35,1354,1355],{"class":78}," {\n",[35,1357,1358,1361,1364,1366,1368,1370,1373,1375,1377,1380,1383,1386,1388,1390,1392,1394,1396,1398],{"class":37,"line":263},[35,1359,1360],{"class":116},"    1",[35,1362,1363],{"class":78},": box_sum(lines[",[35,1365,892],{"class":45},[35,1367,195],{"class":78},[35,1369,984],{"class":74},[35,1371,1372],{"class":116}," 1",[35,1374,135],{"class":78},[35,1376,244],{"class":45},[35,1378,1379],{"class":78},") ",[35,1381,1382],{"class":74},"+",[35,1384,1385],{"class":78}," box_sum(lines[",[35,1387,214],{"class":45},[35,1389,195],{"class":78},[35,1391,984],{"class":74},[35,1393,1065],{"class":45},[35,1395,135],{"class":78},[35,1397,1037],{"class":45},[35,1399,615],{"class":78},[35,1401,1402,1405,1407,1409],{"class":37,"line":288},[35,1403,1404],{"class":116},"    2",[35,1406,129],{"class":78},[35,1408,153],{"class":116},[35,1410,1411],{"class":78},",\n",[35,1413,1414,1417,1419,1421,1423,1425,1428,1430,1432,1434,1436,1438,1440,1442,1444,1446,1448,1450],{"class":37,"line":318},[35,1415,1416],{"class":116},"    4",[35,1418,1363],{"class":78},[35,1420,897],{"class":45},[35,1422,195],{"class":78},[35,1424,984],{"class":74},[35,1426,1427],{"class":116}," 4",[35,1429,135],{"class":78},[35,1431,244],{"class":45},[35,1433,1379],{"class":78},[35,1435,1382],{"class":74},[35,1437,1385],{"class":78},[35,1439,214],{"class":45},[35,1441,195],{"class":78},[35,1443,984],{"class":74},[35,1445,1065],{"class":45},[35,1447,135],{"class":78},[35,1449,1037],{"class":45},[35,1451,615],{"class":78},[35,1453,1454,1457,1459,1462,1464,1466,1469,1471],{"class":37,"line":764},[35,1455,1456],{"class":116},"    6",[35,1458,129],{"class":78},[35,1460,1461],{"class":116},"round",[35,1463,294],{"class":78},[35,1465,1286],{"class":116},[35,1467,1468],{"class":78},"(lines.loc[net6, ",[35,1470,203],{"class":45},[35,1472,1473],{"class":78},"].sum())),\n",[35,1475,1476,1479,1481,1483,1485,1487,1490,1492],{"class":37,"line":789},[35,1477,1478],{"class":116},"    7",[35,1480,129],{"class":78},[35,1482,1461],{"class":116},[35,1484,294],{"class":78},[35,1486,1286],{"class":116},[35,1488,1489],{"class":78},"(lines.loc[net7, ",[35,1491,203],{"class":45},[35,1493,1473],{"class":78},[35,1495,1496,1499,1501,1503,1505,1508,1510,1512],{"class":37,"line":814},[35,1497,1498],{"class":116},"    8",[35,1500,129],{"class":78},[35,1502,393],{"class":116},[35,1504,135],{"class":78},[35,1506,1507],{"class":116},"9",[35,1509,129],{"class":78},[35,1511,393],{"class":116},[35,1513,1411],{"class":78},[35,1515,1516],{"class":37,"line":839},[35,1517,183],{"class":78},[35,1519,1520,1523,1526,1528,1530,1532,1535,1537,1539,1541,1544,1546,1548,1550],{"class":37,"line":865},[35,1521,1522],{"class":78},"boxes[",[35,1524,1525],{"class":116},"3",[35,1527,195],{"class":78},[35,1529,101],{"class":74},[35,1531,1281],{"class":116},[35,1533,1534],{"class":78},"(boxes[",[35,1536,606],{"class":116},[35,1538,195],{"class":78},[35,1540,1382],{"class":74},[35,1542,1543],{"class":78}," boxes[",[35,1545,225],{"class":116},[35,1547,868],{"class":78},[35,1549,225],{"class":116},[35,1551,110],{"class":78},[35,1553,1554,1556,1559,1561,1563,1565,1567,1569,1571,1573,1575,1577,1579,1581],{"class":37,"line":903},[35,1555,1522],{"class":78},[35,1557,1558],{"class":116},"5",[35,1560,195],{"class":78},[35,1562,101],{"class":74},[35,1564,1281],{"class":116},[35,1566,1534],{"class":78},[35,1568,1525],{"class":116},[35,1570,195],{"class":78},[35,1572,249],{"class":74},[35,1574,1543],{"class":78},[35,1576,392],{"class":116},[35,1578,868],{"class":78},[35,1580,225],{"class":116},[35,1582,110],{"class":78},[35,1584,1585,1588,1590,1592,1594,1596,1599,1601,1603,1605,1608,1610,1612,1614,1617],{"class":37,"line":908},[35,1586,1587],{"class":116},"LABELS",[35,1589,120],{"class":74},[35,1591,123],{"class":78},[35,1593,606],{"class":116},[35,1595,129],{"class":78},[35,1597,1598],{"class":45},"\"VAT due on sales and other outputs\"",[35,1600,135],{"class":78},[35,1602,225],{"class":116},[35,1604,129],{"class":78},[35,1606,1607],{"class":45},"\"VAT due on acquisitions (NI only)\"",[35,1609,135],{"class":78},[35,1611,1525],{"class":116},[35,1613,129],{"class":78},[35,1615,1616],{"class":45},"\"Total VAT due\"",[35,1618,1411],{"class":78},[35,1620,1621,1624,1626,1629,1631,1633,1635,1638],{"class":37,"line":968},[35,1622,1623],{"class":116},"          4",[35,1625,129],{"class":78},[35,1627,1628],{"class":45},"\"VAT reclaimed on purchases and other inputs\"",[35,1630,135],{"class":78},[35,1632,1558],{"class":116},[35,1634,129],{"class":78},[35,1636,1637],{"class":45},"\"Net VAT to pay (or reclaim)\"",[35,1639,1411],{"class":78},[35,1641,1642,1645,1647,1650,1652,1654,1656,1659],{"class":37,"line":992},[35,1643,1644],{"class":116},"          6",[35,1646,129],{"class":78},[35,1648,1649],{"class":45},"\"Total value of sales, excluding VAT\"",[35,1651,135],{"class":78},[35,1653,727],{"class":116},[35,1655,129],{"class":78},[35,1657,1658],{"class":45},"\"Total value of purchases, excluding VAT\"",[35,1660,1411],{"class":78},[35,1662,1663,1666,1668,1671,1673,1675,1677,1680],{"class":37,"line":1031},[35,1664,1665],{"class":116},"          8",[35,1667,129],{"class":78},[35,1669,1670],{"class":45},"\"Supplies of goods to the EU (NI only)\"",[35,1672,135],{"class":78},[35,1674,1507],{"class":116},[35,1676,129],{"class":78},[35,1678,1679],{"class":45},"\"Acquisitions of goods from the EU (NI only)\"",[35,1681,183],{"class":78},[35,1683,1684,1687,1689,1692,1695,1697,1700,1702,1704,1707,1710,1712,1714,1716,1718,1721,1724,1727,1730,1733,1736,1739],{"class":37,"line":1079},[35,1685,1686],{"class":78},"summary ",[35,1688,101],{"class":74},[35,1690,1691],{"class":78}," pd.DataFrame({",[35,1693,1694],{"class":45},"\"Box\"",[35,1696,129],{"class":78},[35,1698,1699],{"class":116},"list",[35,1701,294],{"class":78},[35,1703,1587],{"class":116},[35,1705,1706],{"class":78},"), ",[35,1708,1709],{"class":45},"\"Description\"",[35,1711,129],{"class":78},[35,1713,1699],{"class":116},[35,1715,294],{"class":78},[35,1717,1587],{"class":116},[35,1719,1720],{"class":78},".values()), ",[35,1722,1723],{"class":45},"\"Amount\"",[35,1725,1726],{"class":78},": [boxes[b] ",[35,1728,1729],{"class":74},"for",[35,1731,1732],{"class":78}," b ",[35,1734,1735],{"class":74},"in",[35,1737,1738],{"class":116}," LABELS",[35,1740,1741],{"class":78},"]})\n",[35,1743,1745,1747,1750,1752,1754,1756],{"class":37,"line":1744},21,[35,1746,291],{"class":116},[35,1748,1749],{"class":78},"(summary.to_string(",[35,1751,358],{"class":357},[35,1753,101],{"class":74},[35,1755,363],{"class":116},[35,1757,366],{"class":78},[10,1759,1760],{},"Boxes 6 and 7 are reported in whole pounds, the VAT boxes in pounds and pence, which is why they are rounded differently. Boxes 2, 8 and 9 apply only to goods moving between Northern Ireland and the EU and are zero here. Box 5 is box 3 minus box 4: positive means VAT to pay, negative a repayment. This quarter the VAT reclaimed on purchases, 43,187.34, slightly exceeds the 43,124.09 due on sales, so the return shows a repayment of 63.25 — a result worth a second look, because a single miscoded purchase can turn a payment into a repayment. The 274.71 purchase from Step 1 is a case in point: if its correct VAT is the 1,098.85 the rate implies, box 4 rises by 824.14.",[371,1762,380,1768,380,1771,380,1774,380,1778,380,1782,380,1788,380,1793,380,1798,380,1800,380,1804,380,1807,380,1812,380,1815,380,1819,380,1822],{"viewBox":1763,"role":374,"ariaLabelledBy":1764,"xmlns":378,"style":1767},"4 0 684 140",[1765,1766],"vat-boxes-t","vat-boxes-d","width:100%;max-width:684px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[382,1769,1770],{"id":1765},"The quarter's VAT boxes",[386,1772,1773],{"id":1766},"Box 1, VAT due on sales including reverse charge, is 43,124.09. Box 4, VAT reclaimed on purchases including reverse charge, is 43,187.34. Box 5, the difference, is a repayment of 63.25.",[390,1775],{"x":392,"y":393,"width":1776,"height":1777,"fill":396},"684","140",[390,1779],{"x":399,"y":400,"width":1780,"height":1781,"rx":727,"fill":404,"stroke":405,"style":1128},"195.8","28.0",[419,1783,1787],{"x":1784,"y":1785,"style":1786},"117.9","34.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Box 1 – VAT on sales",[390,1789],{"x":1790,"y":400,"width":1791,"height":1781,"rx":727,"fill":478,"stroke":439,"style":1792},"225.8","374.4","stroke-width:1.5px",[419,1794,1797],{"x":1795,"y":1785,"style":1796},"608.2","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","43,124.09",[390,1799],{"x":399,"y":1149,"width":1780,"height":1781,"rx":727,"fill":404,"stroke":405,"style":1128},[419,1801,1803],{"x":1784,"y":1802,"style":1786},"74.5","Box 4 – VAT on purchases",[390,1805],{"x":1790,"y":1149,"width":1806,"height":1781,"rx":727,"fill":508,"stroke":509,"style":1792},"375.0",[419,1808,1811],{"x":1809,"y":1802,"style":1810},"608.7","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","43,187.34",[390,1813],{"x":399,"y":1814,"width":1780,"height":1781,"rx":727,"fill":404,"stroke":405,"style":1128},"96.0",[419,1816,1818],{"x":1784,"y":1817,"style":1786},"114.5","Box 5 – net",[390,1820],{"x":1790,"y":1814,"width":1821,"height":1781,"rx":727,"fill":448,"stroke":449,"style":1792},"6.0",[419,1823,1826],{"x":1824,"y":1817,"style":1825},"239.8","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","−63.25 (repayment)",[20,1828,1830],{"id":1829},"step-4-reconcile-and-write-a-traceable-workbook","Step 4 — Reconcile and write a traceable workbook",[10,1832,1833],{},"The VAT boxes should agree with the movement on the ledger's VAT accounts for the quarter; any difference is investigated before filing. Here the ledger totals are the recorded VAT columns by type:",[25,1835,1837],{"className":65,"code":1836,"language":67,"meta":30,"style":30},"ledger_output = round(float(tx.loc[tx[\"Type\"] == \"sale\", \"VAT\"].sum()), 2)\nledger_input = round(float(tx.loc[tx[\"Type\"] == \"purchase\", \"VAT\"].sum()), 2)\nrc_total = box_sum(lines[\"Tax code\"] == \"RC\", \"RC VAT\")\nrecon = pd.DataFrame({\n    \"Check\": [\"Box 1 less reverse charge = ledger output VAT\", \"Box 4 less reverse charge = ledger input VAT\"],\n    \"Return\": [boxes[1] - rc_total, boxes[4] - rc_total], \"Ledger\": [ledger_output, ledger_input]})\nrecon[\"Difference\"] = (recon[\"Return\"] - recon[\"Ledger\"]).round(2)\nprint(recon.to_string(index=False))\n\nwith pd.ExcelWriter(\"vat_return_2026_q3.xlsx\", engine=\"openpyxl\") as xw:\n    summary.to_excel(xw, sheet_name=\"Return\", index=False)\n    recon.to_excel(xw, sheet_name=\"Reconciliation\", index=False)\n    exceptions.to_excel(xw, sheet_name=\"Exceptions\", index=False)\n    (lines.pivot_table(index=[\"Type\", \"Tax code\"], values=[\"Net\", \"VAT\", \"RC VAT\"], aggfunc=\"sum\").round(2)\n          .to_excel(xw, sheet_name=\"By tax code\"))\n    lines.drop(columns=\"_merge\").to_excel(xw, sheet_name=\"Transactions\", index=False)\n    MAP.to_excel(xw, sheet_name=\"Box mapping\", index=False)\n",[32,1838,1839,1875,1909,1932,1942,1961,1993,2026,2041,2045,2073,2095,2117,2139,2191,2205,2236],{"__ignoreMap":30},[35,1840,1841,1844,1846,1848,1850,1852,1855,1857,1859,1861,1864,1866,1868,1871,1873],{"class":37,"line":38},[35,1842,1843],{"class":78},"ledger_output ",[35,1845,101],{"class":74},[35,1847,1281],{"class":116},[35,1849,294],{"class":78},[35,1851,1286],{"class":116},[35,1853,1854],{"class":78},"(tx.loc[tx[",[35,1856,331],{"class":45},[35,1858,195],{"class":78},[35,1860,984],{"class":74},[35,1862,1863],{"class":45}," \"sale\"",[35,1865,135],{"class":78},[35,1867,244],{"class":45},[35,1869,1870],{"class":78},"].sum()), ",[35,1872,225],{"class":116},[35,1874,110],{"class":78},[35,1876,1877,1880,1882,1884,1886,1888,1890,1892,1894,1896,1899,1901,1903,1905,1907],{"class":37,"line":88},[35,1878,1879],{"class":78},"ledger_input ",[35,1881,101],{"class":74},[35,1883,1281],{"class":116},[35,1885,294],{"class":78},[35,1887,1286],{"class":116},[35,1889,1854],{"class":78},[35,1891,331],{"class":45},[35,1893,195],{"class":78},[35,1895,984],{"class":74},[35,1897,1898],{"class":45}," \"purchase\"",[35,1900,135],{"class":78},[35,1902,244],{"class":45},[35,1904,1870],{"class":78},[35,1906,225],{"class":116},[35,1908,110],{"class":78},[35,1910,1911,1914,1916,1918,1920,1922,1924,1926,1928,1930],{"class":37,"line":95},[35,1912,1913],{"class":78},"rc_total ",[35,1915,101],{"class":74},[35,1917,1385],{"class":78},[35,1919,214],{"class":45},[35,1921,195],{"class":78},[35,1923,984],{"class":74},[35,1925,1065],{"class":45},[35,1927,135],{"class":78},[35,1929,1037],{"class":45},[35,1931,110],{"class":78},[35,1933,1934,1937,1939],{"class":37,"line":113},[35,1935,1936],{"class":78},"recon ",[35,1938,101],{"class":74},[35,1940,1941],{"class":78}," pd.DataFrame({\n",[35,1943,1944,1947,1950,1953,1955,1958],{"class":37,"line":186},[35,1945,1946],{"class":45},"    \"Check\"",[35,1948,1949],{"class":78},": [",[35,1951,1952],{"class":45},"\"Box 1 less reverse charge = ledger output VAT\"",[35,1954,135],{"class":78},[35,1956,1957],{"class":45},"\"Box 4 less reverse charge = ledger input VAT\"",[35,1959,1960],{"class":78},"],\n",[35,1962,1963,1966,1969,1971,1973,1975,1978,1980,1982,1984,1987,1990],{"class":37,"line":230},[35,1964,1965],{"class":45},"    \"Return\"",[35,1967,1968],{"class":78},": [boxes[",[35,1970,606],{"class":116},[35,1972,195],{"class":78},[35,1974,249],{"class":74},[35,1976,1977],{"class":78}," rc_total, boxes[",[35,1979,392],{"class":116},[35,1981,195],{"class":78},[35,1983,249],{"class":74},[35,1985,1986],{"class":78}," rc_total], ",[35,1988,1989],{"class":45},"\"Ledger\"",[35,1991,1992],{"class":78},": [ledger_output, ledger_input]})\n",[35,1994,1995,1998,2001,2003,2005,2008,2011,2013,2015,2018,2020,2022,2024],{"class":37,"line":263},[35,1996,1997],{"class":78},"recon[",[35,1999,2000],{"class":45},"\"Difference\"",[35,2002,195],{"class":78},[35,2004,101],{"class":74},[35,2006,2007],{"class":78}," (recon[",[35,2009,2010],{"class":45},"\"Return\"",[35,2012,195],{"class":78},[35,2014,249],{"class":74},[35,2016,2017],{"class":78}," recon[",[35,2019,1989],{"class":45},[35,2021,256],{"class":78},[35,2023,225],{"class":116},[35,2025,110],{"class":78},[35,2027,2028,2030,2033,2035,2037,2039],{"class":37,"line":288},[35,2029,291],{"class":116},[35,2031,2032],{"class":78},"(recon.to_string(",[35,2034,358],{"class":357},[35,2036,101],{"class":74},[35,2038,363],{"class":116},[35,2040,366],{"class":78},[35,2042,2043],{"class":37,"line":318},[35,2044,92],{"emptyLinePlaceholder":91},[35,2046,2047,2050,2053,2056,2058,2061,2063,2066,2068,2070],{"class":37,"line":764},[35,2048,2049],{"class":74},"with",[35,2051,2052],{"class":78}," pd.ExcelWriter(",[35,2054,2055],{"class":45},"\"vat_return_2026_q3.xlsx\"",[35,2057,135],{"class":78},[35,2059,2060],{"class":357},"engine",[35,2062,101],{"class":74},[35,2064,2065],{"class":45},"\"openpyxl\"",[35,2067,1379],{"class":78},[35,2069,82],{"class":74},[35,2071,2072],{"class":78}," xw:\n",[35,2074,2075,2078,2081,2083,2085,2087,2089,2091,2093],{"class":37,"line":789},[35,2076,2077],{"class":78},"    summary.to_excel(xw, ",[35,2079,2080],{"class":357},"sheet_name",[35,2082,101],{"class":74},[35,2084,2010],{"class":45},[35,2086,135],{"class":78},[35,2088,358],{"class":357},[35,2090,101],{"class":74},[35,2092,363],{"class":116},[35,2094,110],{"class":78},[35,2096,2097,2100,2102,2104,2107,2109,2111,2113,2115],{"class":37,"line":814},[35,2098,2099],{"class":78},"    recon.to_excel(xw, ",[35,2101,2080],{"class":357},[35,2103,101],{"class":74},[35,2105,2106],{"class":45},"\"Reconciliation\"",[35,2108,135],{"class":78},[35,2110,358],{"class":357},[35,2112,101],{"class":74},[35,2114,363],{"class":116},[35,2116,110],{"class":78},[35,2118,2119,2122,2124,2126,2129,2131,2133,2135,2137],{"class":37,"line":839},[35,2120,2121],{"class":78},"    exceptions.to_excel(xw, ",[35,2123,2080],{"class":357},[35,2125,101],{"class":74},[35,2127,2128],{"class":45},"\"Exceptions\"",[35,2130,135],{"class":78},[35,2132,358],{"class":357},[35,2134,101],{"class":74},[35,2136,363],{"class":116},[35,2138,110],{"class":78},[35,2140,2141,2144,2146,2148,2150,2152,2154,2156,2158,2161,2163,2165,2167,2169,2171,2173,2175,2177,2180,2182,2185,2187,2189],{"class":37,"line":865},[35,2142,2143],{"class":78},"    (lines.pivot_table(",[35,2145,358],{"class":357},[35,2147,101],{"class":74},[35,2149,876],{"class":78},[35,2151,331],{"class":45},[35,2153,135],{"class":78},[35,2155,214],{"class":45},[35,2157,868],{"class":78},[35,2159,2160],{"class":357},"values",[35,2162,101],{"class":74},[35,2164,876],{"class":78},[35,2166,203],{"class":45},[35,2168,135],{"class":78},[35,2170,244],{"class":45},[35,2172,135],{"class":78},[35,2174,1037],{"class":45},[35,2176,868],{"class":78},[35,2178,2179],{"class":357},"aggfunc",[35,2181,101],{"class":74},[35,2183,2184],{"class":45},"\"sum\"",[35,2186,1072],{"class":78},[35,2188,225],{"class":116},[35,2190,110],{"class":78},[35,2192,2193,2196,2198,2200,2203],{"class":37,"line":903},[35,2194,2195],{"class":78},"          .to_excel(xw, ",[35,2197,2080],{"class":357},[35,2199,101],{"class":74},[35,2201,2202],{"class":45},"\"By tax code\"",[35,2204,366],{"class":78},[35,2206,2207,2210,2212,2214,2216,2219,2221,2223,2226,2228,2230,2232,2234],{"class":37,"line":908},[35,2208,2209],{"class":78},"    lines.drop(",[35,2211,871],{"class":357},[35,2213,101],{"class":74},[35,2215,979],{"class":45},[35,2217,2218],{"class":78},").to_excel(xw, ",[35,2220,2080],{"class":357},[35,2222,101],{"class":74},[35,2224,2225],{"class":45},"\"Transactions\"",[35,2227,135],{"class":78},[35,2229,358],{"class":357},[35,2231,101],{"class":74},[35,2233,363],{"class":116},[35,2235,110],{"class":78},[35,2237,2238,2241,2244,2246,2248,2251,2253,2255,2257,2259],{"class":37,"line":968},[35,2239,2240],{"class":116},"    MAP",[35,2242,2243],{"class":78},".to_excel(xw, ",[35,2245,2080],{"class":357},[35,2247,101],{"class":74},[35,2249,2250],{"class":45},"\"Box mapping\"",[35,2252,135],{"class":78},[35,2254,358],{"class":357},[35,2256,101],{"class":74},[35,2258,363],{"class":116},[35,2260,110],{"class":78},[10,2262,2263,2264,2267,2268,18],{},"Both reconciliation lines agree to the penny, because the boxes were built from the same recorded VAT amounts — the exceptions from Step 1 are ",[1101,2265,2266],{},"included"," at their recorded values until corrected, which is right: the return must match the books, and the books are what gets fixed. The workbook gives a reviewer the return, the reconciliation, the exceptions, totals by type and tax code, every transaction with the boxes it feeds, and the mapping table itself. Any figure on the return can be traced to its lines with a filter, which is what a reviewer — or a tax inspector — will want to do. Combining entities that report in different currencies first needs the conversion in ",[14,2269,2271],{"href":2270},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fconvert-multi-currency-transactions-with-an-fx-rate-table\u002F","Convert Multi-Currency Transactions with an FX Rate Table",[20,2273,2275],{"id":2274},"common-pitfalls","Common pitfalls",[2277,2278,2279,2290,2296,2302,2308],"ul",{},[2280,2281,2282,2289],"li",{},[2283,2284,2285,2286,2288],"strong",{},"Tax rules hard-coded in ",[32,2287,559],{}," statements."," Keep the code-to-box mapping in a table.",[2280,2291,2292,2295],{},[2283,2293,2294],{},"Unknown tax codes ignored."," Fail the run when a code is not mapped.",[2280,2297,2298,2301],{},[2283,2299,2300],{},"Forgetting reverse charge."," It adds to both output and input VAT and to boxes 6 and 7.",[2280,2303,2304,2307],{},[2283,2305,2306],{},"Leaving out zero-rated and exempt values."," They belong in boxes 6 and 7.",[2280,2309,2310,2313],{},[2283,2311,2312],{},"No reconciliation."," The boxes must agree with the ledger's VAT accounts.",[20,2315,2317],{"id":2316},"conclusion","Conclusion",[10,2319,2320],{},"To build a VAT return summary from transactions, first check every line's VAT against its rate and list the exceptions, then map each type and tax code to return boxes through an explicit table that fails on unknown codes, apply reverse charge to both sides, sum the boxes with the right rounding, and reconcile the VAT boxes to the ledger. Write the return together with its reconciliation, exceptions, breakdown and transactions so every figure can be traced.",[20,2322,2324],{"id":2323},"frequently-asked-questions","Frequently asked questions",[10,2326,2327,2330],{},[2283,2328,2329],{},"How do I calculate VAT return boxes from a transaction list in pandas?","\nMap each transaction's type and tax code to the boxes it feeds with a mapping table, merge it onto the transactions, and sum the net and VAT columns per box.",[10,2332,2333,2336],{},[2283,2334,2335],{},"How is reverse charge handled on a VAT return?","\nThe buyer calculates the VAT on the net value and includes it as output VAT and as input VAT, and includes the net value in both the sales and purchases value boxes.",[10,2338,2339,2342],{},[2283,2340,2341],{},"Do zero-rated and exempt sales go on the VAT return?","\nYes. They carry no VAT but their net value is included in the total value of sales, while out-of-scope items are left out.",[10,2344,2345,2348],{},[2283,2346,2347],{},"How do I check that VAT amounts are correct?","\nRecompute each line's VAT as net times the rate for its tax code and list lines where the recorded VAT differs by more than rounding.",[20,2350,2352],{"id":2351},"related","Related",[2277,2354,2355,2361,2368,2375],{},[2280,2356,2357,2358,2360],{},"Up one level: ",[14,2359,17],{"href":16}," — finance reports from Python.",[2280,2362,2363,2367],{},[14,2364,2366],{"href":2365},"\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"," — the ledger the return reconciles to.",[2280,2369,2370,2374],{},[14,2371,2373],{"href":2372},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-supplier-payment-run-proposal\u002F","Build a Supplier Payment Run Proposal"," — another accounts payable task.",[2280,2376,2377,2381],{},[14,2378,2380],{"href":2379},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fvalidate-a-merge-to-avoid-duplicate-rows\u002F","Validate a Merge to Avoid Duplicate Rows"," — the merge guard used here.",[2383,2384,2385],"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 .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}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":30,"searchDepth":88,"depth":88,"links":2387},[2388,2389,2390,2391,2392,2393,2394,2395,2396],{"id":22,"depth":88,"text":23},{"id":58,"depth":88,"text":59},{"id":552,"depth":88,"text":553},{"id":1255,"depth":88,"text":1256},{"id":1829,"depth":88,"text":1830},{"id":2274,"depth":88,"text":2275},{"id":2316,"depth":88,"text":2317},{"id":2323,"depth":88,"text":2324},{"id":2351,"depth":88,"text":2352},"2026-10-02","Summarise a quarter's sales and purchase transactions into VAT return boxes with pandas: map tax codes to boxes through a table rather than code, handle standard, reduced, zero-rated, exempt, out-of-scope and reverse-charge lines, check every line's VAT against its rate, reconcile the boxes to the ledger, and write a summary workbook a reviewer can trace back to the transactions.","md",[2401,2403,2405,2407],{"q":2329,"a":2402},"Map each transaction's type and tax code to the boxes it feeds with a mapping table, merge it onto the transactions, and sum the net and VAT columns per box.",{"q":2335,"a":2404},"The buyer calculates the VAT on the net value and includes it as output VAT and as input VAT, and includes the net value in both the sales and purchases value boxes.",{"q":2341,"a":2406},"Yes. They carry no VAT but their net value is included in the total value of sales, while out-of-scope items are left out.",{"q":2347,"a":2408},"Recompute each line's VAT as net times the rate for its tax code and list lines where the recorded VAT differs by more than rounding.","vat return summary from transactions",null,{"breadcrumb":2412},[2413,2416,2419],{"name":2414,"item":2415},"Home","\u002F",{"name":2417,"item":2418},"Automating Reporting Workflows with Python and Excel","\u002Fautomating-reporting-workflows\u002F",{"name":2420,"item":16},"Building Finance and Operations Reports in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions",{"title":2423,"description":2424},"Build a VAT Return Summary from Transactions with Python","VAT return boxes from transaction data with pandas: a tax-code-to-box mapping table, reverse charge, zero-rated and exempt lines, per-line VAT checks, reconciliation to the ledger and a traceable Excel summary.","build-a-vat-return-summary-from-transactions","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-vat-return-summary-from-transactions\u002Findex",[2428],"report-layouts","how-to","B-rYOFK0miCyczluFFeq1_XgW1E963uIxr5s41RpDzM",[2432,2435],{"title":2366,"path":2433,"stem":2434,"children":-1},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-trial-balance-from-a-general-ledger","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-trial-balance-from-a-general-ledger\u002Findex",{"title":2436,"path":2437,"stem":2438,"children":-1},"Build a Warehouse Pick List from Orders","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-warehouse-pick-list-from-orders\u002Findex",[2440,2442],{"path":2441,"title":2420},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports",{"path":2443,"title":2417},"\u002Fautomating-reporting-workflows",[],[2446,2450,2453,2456,2459,2462],{"path":2447,"title":2448,"kind":2449},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards","Building Multi-Sheet Excel Dashboards","guide",{"path":2451,"title":2452,"kind":2429},"\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":2454,"title":2455,"kind":2429},"\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":2457,"title":2458,"kind":2429},"\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":2460,"title":2461,"kind":2429},"\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":2463,"title":2464,"kind":2429},"\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",1790972127435]