Re_Backend/docs/FORM16_CREDIT_DEBIT_PROCESS.md
2026-03-18 12:59:20 +05:30

138 lines
9.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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_NO` or `creditNoteNumber` (TDS_TRNS_ID in response), upload file to storage, insert/update row in **`form16_sap_responses`** with `type = '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 with `CN` replaced by `DN` (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 in **`form16_debit_note_sap_responses`** (separate table from credit) with `debit_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 calls `runForm16SapResponseIngestionOnce()`, which:
- Scans **OUTGOING** credit dir (`FORM16_CRDT`) and **OUTGOING** debit dir (`FORM16_DBT`) for `.csv` files.
- For each file: parse, match to credit or debit note, upload to storage, write to `form16_sap_responses` (credit) or `form16_debit_note_sap_responses` (debit).
- **Pull button** (Credit Notes page and Debit Notes page): `POST /api/v1/form16/sap/pull` triggers the **same** `runForm16SapResponseIngestionOnce()`, 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 by `credit_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:\WFM` or `D:\Form-16 Main`). If not set and default path missing, job tries `process.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.