CLI · commit 1d41c51

tdsdesk

TDS deduction engine & quarterly return preparation for Indian businesses

Download tdsdesk.zip
Quickstart
unzip tdsdesk.zip && cd tdsdesk
uv venv .venv && uv pip install -p .venv/bin/python -e '.[dev]'
.venv/bin/python -m pytest -q

tdsdesk

tdsdesk is a command-line TDS desk for Indian businesses. It reads a payments register and a deductee master, works out the section, rate and tax for every payment under FY-versioned rules (thresholds with catch-up, 206AA, 206AB, section 197 certificates, GST exclusion), allocates challans, computes section 201(1A) interest and the 234E fee, prepares 26Q return data and 16A certificate data, and reconciles against a 26AS-style statement.

Features

Install

cd tdsdesk
uv venv .venv && uv pip install -p .venv/bin/python -e '.[dev]'
source .venv/bin/activate

Quickstart

cd examples
tdsdesk compute payments.csv --deductees deductees.csv --fy 2025-26 -o tds.csv
tdsdesk thresholds --fy 2025-26 --only-crossed
tdsdesk interest -c challans.csv --as-on 2026-03-31
tdsdesk return 26Q --quarter Q2 --fy 2025-26 -c challans.csv -o out/ --filing-date 2025-11-10
tdsdesk explain P0046 -c challans.csv --as-on 2026-03-31
tdsdesk reconcile 26as.csv -c challans.csv --as-on 2026-03-31

payments.csv, deductees.csv and challans.csv are read from the current directory unless -p, -d, -c say otherwise.

Input files

deductees.csv: deductee_id, name, pan, type (individual|huf|company|firm), resident (Y/N), ldc_cert_no, ldc_section, ldc_limit, ldc_rate, ldc_valid_from, ldc_valid_to, specified_206ab (Y/N), pan_aadhaar_operative (Y/N)

payments.csv: payment_id, credit_date, payment_date, deductee_id, nature, amount, gst_amount, invoice_ref, deduction_date (amount includes GST; gst_amount is the separately stated part; dates YYYY-MM-DD; deduction_date is optional and defaults to the earlier of credit and payment date.) Natures: contract, professional_fees, technical_services, rent_land_building, rent_plant_machinery, commission, interest, purchase_of_goods.

challans.csv: bsr_code, date, challan_serial, amount, section (section as 194C, 94J, 94JB and similar).

26as.csv: pan, section, amount_paid, tax_deducted, tax_deposited.

Usage with real output

The examples/ data set is synthetic: 60 deductees (3 without PAN, 1 with an inoperative PAN, 1 non-resident, a 206AB-flagged vendor, a section 197 certificate that expires on 30 Sep 2025), 900 payments across all sections, GST on most services, a few late deductions, late challans and one short-paid challan. Regenerate it with python examples/generate.py.

compute

$ tdsdesk compute payments.csv --deductees deductees.csv --fy 2025-26 -o tds.csv
warning: non-resident deductee D056 Khan Enterprises & Co: payments skipped (27Q / sec. 195 is out of scope)
                     TDS computation FY 2025-26                     
┏━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┓
┃ Section   ┃ Payments ┃ Base (excl. GST) ┃ Taxable base ┃     TDS ┃
┡━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━┩
│ 194A      │       63 │          253,100 │      253,100 │  28,510 │
│ 194C      │      234 │        9,749,100 │    9,749,100 │ 141,492 │
│ 194H      │      108 │          577,600 │      511,500 │  21,948 │
│ 194I_LB   │      108 │        5,242,500 │    3,280,000 │ 328,000 │
│ 194I_PM   │       27 │          720,000 │            0 │       0 │
│ 194J_PROF │      162 │        4,229,500 │    4,229,500 │ 378,614 │
│ 194J_TECH │       90 │        3,140,100 │    3,140,100 │  62,802 │
│ 194Q      │       90 │       44,153,600 │    8,551,800 │  23,654 │
│ TOTAL     │      882 │       68,065,500 │   29,715,100 │ 985,020 │
└───────────┴──────────┴──────────────────┴──────────────┴─────────┘
882 payments computed (18 skipped) -> /tmp/claude-1000/tds.csv

tds.csv holds one row per payment: status, catch-up base, taxable base, effective rate, rate basis and TDS.

thresholds

                                                Thresholds FY 2025-26                                                
┏━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓
┃ ID   ┃ Deductee                  ┃ Section   ┃ Aggregate ┃ Threshold ┃ Headroom ┃ Pending ┃ State                 ┃
┡━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩
│ D001 │ Neha Gupta                │ 194C      │   807,300 │   100,000 │        - │       - │ crossed on 2025-05-09 │
│ D002 │ Sanjay Gupta              │ 194J_PROF │   288,700 │    50,000 │        - │       - │ crossed on 2025-05-06 │
│ D003 │ Tara Khan                 │ 194I_LB   │   895,000 │   600,000 │        - │       - │ crossed on 2025-09-18 │
│ D004 │ Meera Patil               │ 194C      │   319,000 │   100,000 │        - │       - │ crossed on 2025-07-14 │
│ D004 │ Meera Patil               │ 194H      │    31,700 │    20,000 │        - │       - │ crossed on 2026-02-21 │

interest and challan allocation

                                                 Interest u/s 201(1A), FY 2025-26                                                 
┏━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━┓
┃ Payment ┃ Section   ┃   TDS ┃ Deducted   ┃ Due        ┃ Late deduction ┃ Late deposit ┃ Undeposited ┃ Undeposited int. ┃ Total ┃
┡━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━┩
│ P0006   │ 194C      │   798 │ 2025-05-09 │ 2025-06-07 │             16 │           24 │           0 │                0 │    40 │
│ P0059   │ 194C      │   790 │ 2025-06-03 │ 2025-07-07 │             16 │            0 │           0 │                0 │    16 │
│ P0081   │ 194C      │   653 │ 2025-05-03 │ 2025-06-07 │              0 │           29 │           0 │                0 │    29 │
│ P0083   │ 194C      │   408 │ 2025-05-04 │ 2025-06-07 │              0 │           18 │           0 │                0 │    18 │
│ P0087   │ 194C      │   365 │ 2025-05-06 │ 2025-06-07 │              0 │           11 │           0 │                0 │    11 │
└─────────┴───────────┴───────┴────────────┴────────────┴────────────────┴──────────────┴─────────────┴──────────────────┴───────┘
TDS deducted 985,020; deposited via challans 983,520; interest payable 811
flag: SHORTFALL P0894 (194C, deducted 2026-03-29): 404 not covered by any challan
flag: SHORTFALL P0895 (194C, deducted 2026-03-30): 1096 not covered by any challan

return 26Q

                             Form 26Q Q2 FY 2025-26                             
┏━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Section ┃ Deductees ┃ Amount paid ┃ TDS deducted ┃ TDS deposited ┃ Shortfall ┃
┡━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ 94A     │         6 │      79,000 │        9,070 │         9,070 │         0 │
│ 94C     │        13 │   2,587,800 │       41,517 │        41,517 │         0 │
│ 94H     │         7 │     147,400 │        9,536 │         9,536 │         0 │
│ 94IB    │         1 │     635,000 │       63,500 │        63,500 │         0 │
│ 94JA    │         4 │     788,500 │       15,770 │        15,770 │         0 │
│ 94JB    │        10 │   1,182,600 │       92,108 │        92,108 │         0 │
│ TOTAL   │        36 │   5,420,300 │      231,501 │       231,501 │         0 │
└─────────┴───────────┴─────────────┴──────────────┴───────────────┴───────────┘
annexure      out/26Q_2025-26_Q2_deductee_annexure.csv
summary       out/26Q_2025-26_Q2_summary.csv
challans      out/26Q_2025-26_Q2_challans.csv
certificates  out/16A_2025-26_Q2.csv
Due date 2025-10-31; filed 2025-11-10: 10 day(s) late, sec. 234E fee 2,000

Files written to out/: the deductee annexure, section summary, challan details and 16A_...csv.

explain

A catch-up crossing with GST excluded:

Payment P0046  (INV/2504/0046)
Deductee      D026 Kestrel Software Pvt Ltd  PAN TEGCC1123B  type company
Nature        technical_services -> section 194J_TECH (Fees for technical services / royalty on sale of films), NSDL code 94JA
Authority     Sec. 194J(1)(ba): 2% on technical services, call centre and royalty for sale/distribution/exhibition of cinematographic films; same threshold proviso
Event date    2025-04-16 (earlier of credit 2025-04-16 / payment None)
Amount        42716 less GST 6516 = TDS base 36200
Threshold     aggregate threshold 50000; aggregate 39600 -> 75800
Status        aggregate_threshold_crossed
Catch-up      39600 of earlier payments deducted now, taxable base 75800 = 39600 + 36200
Rate          2% (before any section 197 certificate)
  75800 x 2% = 1516  [normal]
TDS           1516 (rounded to the nearest rupee, sec. 288B)
Deducted on   2025-04-16 (quarter Q1); deposit due 2025-05-07
Challan       0510308/30002 dated 2025-05-06: 1516
Interest      201(1A)(i) late deduction 0; 201(1A)(ii) late deposit 0; undeposited 0; total 0
Note          GST of 6516 excluded as separately stated

A deductee without PAN (206AA, 20%):

Payment P0298  (INV/2507/0298)
Deductee      D034 Harbor Freight Pvt Ltd  PAN not available  type company
Nature        commission -> section 194H (Commission or brokerage), NSDL code 94H
Authority     Sec. 194H: rate 5% reduced to 2% w.e.f. 1-Oct-2024 (Finance (No.2) Act 2024); threshold per FY
Event date    2025-07-20 (earlier of credit 2025-07-20 / payment None)
Amount        8614 less GST 1314 = TDS base 7300
Threshold     aggregate threshold 20000; aggregate 18000 -> 25300
Status        aggregate_threshold_crossed
Catch-up      18000 of earlier payments deducted now, taxable base 25300 = 18000 + 7300
Rate          20% (before any section 197 certificate)
  25300 x 20% = 5060  [206AA (no/inoperative PAN)]
TDS           5060 (rounded to the nearest rupee, sec. 288B)
Deducted on   2025-07-20 (quarter Q2); deposit due 2025-08-07
Challan       0510308/30013 dated 2025-08-04: 5060
Interest      201(1A)(i) late deduction 0; 201(1A)(ii) late deposit 0; undeposited 0; total 0
Note          GST of 1314 excluded as separately stated

A catch-up under a section 197 certificate at 2%:

Payment P0058  (INV/2504/0058)
Deductee      D031 Prism Consulting Pvt Ltd  PAN NWSCW8150J  type company
Nature        professional_fees -> section 194J_PROF (Fees for professional services), NSDL code 94JB
Authority     Sec. 194J(1)(b): 10% on professional services; proviso: no deduction if aggregate in FY does not exceed threshold
Event date    2025-04-21 (earlier of credit 2025-04-21 / payment 2025-05-30)
Amount        30916 less GST 4716 = TDS base 26200
Threshold     aggregate threshold 50000; aggregate 36700 -> 62900
Status        aggregate_threshold_crossed
Catch-up      36700 of earlier payments deducted now, taxable base 62900 = 36700 + 26200
Rate          10% (before any section 197 certificate)
  62900 x 2% = 1258  [197 certificate LDC/2025/0042]
TDS           1258 (rounded to the nearest rupee, sec. 288B)
Deducted on   2025-04-21 (quarter Q1); deposit due 2025-05-07
Challan       0510308/30002 dated 2025-05-06: 1258
Interest      201(1A)(i) late deduction 0; 201(1A)(ii) late deposit 0; undeposited 0; total 0
Note          GST of 4716 excluded as separately stated

206AB on FY 2024-25 (small hand-written data set in examples/fy2024-25/; the section was omitted from FY 2025-26):

Payment A2  (INV/002)
Deductee      V1 Redwood Services Pvt Ltd  PAN AABCR1234K  type company
Nature        professional_fees -> section 194J_PROF (Fees for professional services), NSDL code 94JB
Authority     Sec. 194J(1)(b): 10% on professional services; proviso: no deduction if aggregate in FY does not exceed threshold
Event date    2024-07-12 (earlier of credit 2024-07-12 / payment None)
Amount        118000 less GST 18000 = TDS base 100000
Threshold     aggregate threshold 30000; aggregate 0 -> 100000
Status        aggregate_threshold_crossed
Rate          20% (before any section 197 certificate)
  100000 x 20% = 20000  [206AB (specified person)]
TDS           20000 (rounded to the nearest rupee, sec. 288B)
Deducted on   2024-07-12 (quarter Q2); deposit due 2024-08-07
Challan       20000 not covered by any challan
Interest      201(1A)(i) late deduction 0; 201(1A)(ii) late deposit 0; undeposited 2700; total 2700
              - 20000 not deposited as on 2025-03-31: 9 month(s) at 1.5%
Note          GST of 18000 excluded as separately stated

reconcile

examples/26as.csv has a changed tax figure, a changed amount, a missing row and an extra row planted in it.

                                                     Reconciliation                                                      
┏━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ PAN        ┃ Section ┃ Status           ┃ Detail                                                                      ┃
┡━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ CLPCX5938P │ 94H     │ MISMATCH         │ tds_deducted: books 1124 vs 26AS 624; tds_deposited: books 1124 vs 26AS 624 │
│ HFGCX7136P │ 94JB    │ MISMATCH         │ amount: books 104000 vs 26AS 129000                                         │
│ HYTPK7791G │ 94H     │ MISSING_IN_26AS  │                                                                             │
│ PANNOTAVBL │ 94A     │ MISSING_IN_26AS  │                                                                             │
│ PANNOTAVBL │ 94H     │ MISSING_IN_26AS  │                                                                             │
│ PANNOTAVBL │ 94Q     │ MISSING_IN_26AS  │                                                                             │
│ ZZZPZ9999Z │ 94C     │ MISSING_IN_BOOKS │                                                                             │
└────────────┴─────────┴──────────────────┴─────────────────────────────────────────────────────────────────────────────┘
63 PAN/section pairs: 56 match, 7 need attention

Deductees without a PAN always appear as missing in 26AS, which is the expected result.

Configuration

No config file. Options common to all commands: --fy (default 2025-26), -d/--deductees, -p/--payments, -c/--challans, --as-on (date for undeposited-tax interest, default today) and --no-194q (buyer turnover did not exceed 10 crore). Exit status is 2 with a one-line message for bad input (unknown FY, bad CSV value with file and line, unknown nature). Rules are the JSON files in src/tdsdesk/data/.

Architecture

Module Role
rules.py, data/fy_*.json Load FY rules into typed objects
loaders.py CSV parsing and validation with line numbers
engine.py Thresholds, catch-up, rate selection, rounding
challans.py FIFO challan allocation
interest.py 201(1A) interest and 234E fee
dates.py Month-or-part counting, due dates, quarters, FY
returns.py 26Q, summary, challan and 16A CSVs
recon.py 26AS reconciliation
explain.py Narrative derivation
pipeline.py, cli.py Wiring and the Click commands

Deeper documents: docs/rules.md (sections, rates, citations), docs/algorithms.md (catch-up, precedence, interest and FIFO with worked examples), docs/limitations.md.

Tests

.venv/bin/pytest

75 tests: every section's rate and threshold in both FYs including exact-boundary and catch-up cases, 206AA / 206AB / 197 precedence, GST exclusion, rounding, month-or-part table, due dates including March, hand-computed interest and fee, challan FIFO, return CSV shape and totals, explain, reconcile, loaders and the CLI against the example data.

Limitations

Resident deductees and Form 26Q only; the 26Q output is an intermediate CSV, not an FVU file; some precedence rules and thresholds are marked illustrative. Rules data should be verified against current law before use. See docs/limitations.md. This tool is not tax advice.