9.1 KiB
9.1 KiB
Form 16 – Full Process: Credit & Debit Notes (Incoming & Outgoing)
This document describes the end-to-end flow for Form 16 (Form 16A TDS Credit): 26AS reconciliation, credit/debit note creation, WFM/SAP incoming and outgoing file handling, and how users view SAP responses.
1. High-Level Flow
- 26AS: TDS entries are uploaded (RE) and aggregated by TAN + Financial Year + Quarter (Section 194Q, Booking F/O only).
- Form 16A submission: Dealer submits Form 16A (PDF). OCR extracts TAN, FY, Quarter, TDS amount, certificate number, etc.
- Credit note: When a submission is validated, the system matches it against the latest 26AS aggregate for that TAN/FY/Quarter. On match, a credit note is created, ledger updated, quarter marked SETTLED, and a CSV is pushed to WFM INCOMING for SAP (credit note generation).
- Debit note: When a new 26AS upload changes the quarter total and that quarter was already SETTLED, the system creates a debit note (reversing the earlier credit), updates ledger, sets quarter to DEBIT_ISSUED_PENDING_FORM16, and pushes a CSV to WFM INCOMING for SAP (debit note generation).
- SAP responses: SAP processes the INCOMING files and drops response CSVs in WFM OUTGOING. The backend ingests these (scheduler every 5 min or on-demand Pull), stores them in DB, and users can View (and for credit, Download) the SAP response.
2. Paths (WFM Folder Structure)
All paths are relative to WFM_BASE_PATH (default C:\WFM). Can be overridden via .env (e.g. WFM_BASE_PATH=D:\Form-16 Main). The job also tries <process.cwd()>\WFM-QRE\... if the default path does not exist.
| Direction | Type | Default path (under WFM_BASE_PATH) |
|---|---|---|
| INCOMING | Credit | WFM-QRE\INCOMING\WFM_MAIN\FORM16_CRDT |
| INCOMING | Debit | WFM-QRE\INCOMING\WFM_MAIN\FORM16_DEBT |
| OUTGOING | Credit | WFM-QRE\OUTGOING\WFM_SAP_MAIN\FORM16_CRDT |
| OUTGOING | Debit | WFM-QRE\OUTGOING\WFM_SAP_MAIN\FORM16_DBT |
- INCOMING = files we push to WFM (for SAP to pick up and process).
- OUTGOING = files SAP drops (responses); we read and store them.
3. Credit Note Flow
3.1 When is a credit note created?
- On Form 16A submission validation (after OCR and 26AS check).
run26asMatchAndCreditNote(submission)is called (e.g. from submission validation flow).- Conditions: TAN + FY + Quarter match latest 26AS aggregate (Section 194Q, F/O), amount within tolerance, quarter not already settled with same amount.
- On success: create
Form16CreditNote, ledger entry (CREDIT), set quarter status SETTLED, then push INCOMING CSV.
3.2 Credit note – INCOMING (we push to WFM/SAP)
- Path:
WFM-QRE\INCOMING\WFM_MAIN\FORM16_CRDT - When: Immediately after credit note is created.
- File name:
{creditNoteNumber}.csv(e.g.CN00628226Q20001.csv). - Content (pipe
|separated):
TRNS_UNIQ_NO(e.g.F16-CN-{submissionId}-{creditNoteId}-{timestamp}),
TDS_TRNS_ID(= credit note number),
DEALER_CODE,TDS_TRNS_DOC_TYP,DLR_TAN_NO,FIN_YEAR & QUARTER,DOC_DATE,TDS_AMT. - TDS_TRNS_ID = credit note number (format:
CN+ 6-digit dealer code + 2-digit FY + quarter + 4-digit sequence, e.g.CN00628226Q20001). - A copy is also written to the Form 16 credit archive path (INCOMING archive).
3.3 Credit note – OUTGOING (SAP response)
- Path:
WFM-QRE\OUTGOING\WFM_SAP_MAIN\FORM16_CRDT - Who writes: SAP (response CSVs placed here by SAP/WFM).
- Who reads: Backend Form 16 SAP response job (scheduler every 5 min + on Pull button).
- What we do: Read each CSV, parse first “real” data row, match to credit note by
TRNS_UNIQ_NOorcreditNoteNumber(TDS_TRNS_ID in response), upload file to storage, insert/update row inform16_sap_responseswithtype = 'credit',credit_note_id,storage_url, etc. - User: Credit notes list shows View when a response exists; View opens popup with SAP fields and Download CSV; Pull triggers ingestion and list refresh.
4. Debit Note Flow
4.1 When is a debit note created?
- On 26AS upload that changes the quarter aggregate for a quarter that is already SETTLED (had a credit note).
process26asUploadAggregation(uploadLogId)is called after 26AS file upload (controller calls it when records are imported).- For each (TAN, FY, Quarter) where new 26AS total ≠ previous snapshot and status is SETTLED: create
Form16DebitNote(linked to the last credit note for that quarter), ledger entry (DEBIT), set quarter status DEBIT_ISSUED_PENDING_FORM16, then push INCOMING CSV.
4.2 Debit note – INCOMING (we push to WFM/SAP)
- Path:
WFM-QRE\INCOMING\WFM_MAIN\FORM16_DEBT - When: Immediately after debit note is created in
process26asUploadAggregation. - File name:
{debitNoteNumber}.csv(e.g.DN00628226Q20001.csv). - Content (pipe
|separated):
TRNS_UNIQ_NO(e.g.F16-DN-{creditNoteId}-{debitId}-{timestamp}),
TDS_TRNS_ID= credit note number (not debit note number),
DEALER_CODE,TDS_TRNS_DOC_TYP,Org.Document Number(= debit id),DLR_TAN_NO,FIN_YEAR & QUARTER,DOC_DATE,TDS_AMT. - TDS_TRNS_ID in debit incoming = credit note number (same format as credit, e.g.
CN00628226Q20001). Debit note number = same string withCNreplaced byDN(e.g.DN00628226Q20001). - A copy is also written to the Form 16 debit archive path.
4.3 Debit note – OUTGOING (SAP response)
- Path:
WFM-QRE\OUTGOING\WFM_SAP_MAIN\FORM16_DBT - Who writes: SAP (response CSVs placed here).
- Who reads: Same Form 16 SAP response job (every 5 min + Pull on Debit Notes page).
- What we do: Read each CSV, parse, match to debit note by (in order):
(1)TRNS_UNIQ_NO→form_16_debit_notes.trns_uniq_no,
(2)CLAIM_NUMBER→form_16_debit_notes.debit_note_number,
(3) filename (without .csv) →form_16_debit_notes.debit_note_number.
Upload file to storage, insert/update row inform16_debit_note_sap_responses(separate table from credit) withdebit_note_id,storage_url, etc. - User: Debit notes list shows View when a response exists; View opens popup (no download); Pull triggers ingestion and list refresh.
5. Database Tables for SAP Responses
| Table | Purpose |
|---|---|
| form16_sap_responses | Credit note SAP responses only. Columns: type ('credit'), file_name, credit_note_id, claim_number, sap_document_number, msg_typ, message, raw_row, storage_url, timestamps. |
| form16_debit_note_sap_responses | Debit note SAP responses only. Columns: file_name, debit_note_id, claim_number, sap_document_number, msg_typ, message, raw_row, storage_url, timestamps. No type or credit_note_id. |
Credit and debit SAP responses are not mixed; each has its own table.
6. Scheduler and Pull
- Scheduler:
startForm16SapResponseJob()runs every 5 minutes (cron*/5 * * * *). It callsrunForm16SapResponseIngestionOnce(), which:- Scans OUTGOING credit dir (
FORM16_CRDT) and OUTGOING debit dir (FORM16_DBT) for.csvfiles. - For each file: parse, match to credit or debit note, upload to storage, write to
form16_sap_responses(credit) orform16_debit_note_sap_responses(debit).
- Scans OUTGOING credit dir (
- Pull button (Credit Notes page and Debit Notes page):
POST /api/v1/form16/sap/pulltriggers the samerunForm16SapResponseIngestionOnce(), then the frontend refetches the list. So Pull = one-off run of the same ingestion logic; no separate “pull-only” path. - View appears when the corresponding table has a row for that note with a non-null
storage_url(and for list, we check bycredit_note_id/debit_note_id).
7. End-to-End Summary
| Step | Credit note | Debit note |
|---|---|---|
| Trigger | Form 16A submission validated, 26AS match | 26AS upload changes total for a SETTLED quarter |
| INCOMING (we push) | CSV to INCOMING\WFM_MAIN\FORM16_CRDT |
CSV to INCOMING\WFM_MAIN\FORM16_DEBT |
| TDS_TRNS_ID in CSV | Credit note number | Credit note number |
| File name | {creditNoteNumber}.csv |
{debitNoteNumber}.csv |
| OUTGOING (SAP writes) | SAP drops response in OUTGOING\WFM_SAP_MAIN\FORM16_CRDT |
SAP drops response in OUTGOING\WFM_SAP_MAIN\FORM16_DBT |
| We read & store | Job reads CSV, matches, stores in form16_sap_responses |
Job reads CSV, matches, stores in form16_debit_note_sap_responses |
| User action | View / Download CSV (Pull to refresh) | View only (Pull to refresh) |
8. Env / Config (relevant)
- WFM_BASE_PATH: Base folder that contains
WFM-QRE(e.g.C:\WFMorD:\Form-16 Main). If not set and default path missing, job triesprocess.cwd()\WFM-QRE\.... - WFM_FORM16_CREDIT_INCOMING_PATH, WFM_FORM16_DEBIT_INCOMING_PATH: Override INCOMING paths.
- WFM_FORM16_CREDIT_OUTGOING_PATH, WFM_FORM16_DEBIT_OUTGOING_PATH: Override OUTGOING paths.