| Case Number | 00077357 |
| Oracle Module | Accounts Payable (AP) / Purchasing (PO) |
| EBS Version | 11i (11.5.10.2) |
| Functional Area | PO Accrual Reconciliation / Accrual Write-Offs / Receipt Variance |
| Related Patches | None |
| Related Case | 00059272 (earlier write-off implementation — see also) |
PO_ACCRUAL_RECONCILE_TEMP_ALL where abs(net_po_line_amount) equals a specified threshold (typically a small rounding amount such as 1 cent) and net_po_line_quantity = 0, indicating fully received but unresolved monetary variances that cannot be cleared through re-matching.po_distribution_id, requiring write-off records to be created for each PO transaction within the distribution group rather than for a single row.The same root cause as case 00059272 applies: rounding or conversion differences between PO receipt amounts and AP invoice amounts accumulate in net_po_line_amount and cannot be resolved through re-matching. This case adds a more sophisticated grouping approach — processing by po_distribution_id rather than by individual transaction row — to correctly handle distributions with multiple PO receipt transaction rows. The write-off logic evolved through five iterative phases (G through M), each refining the AP matching criteria, amount comparison function, and idempotency guards.
The five fix scripts represent a progressive refinement:
po_distribution_id; amount comparison uses round().floor().SELECT UNIQUE added to inner cursors to deduplicate rows.po_transaction_id from the outer driver key (cleaner distribution-level deduplication only).write_off_flag <> 'Y' guard to prevent reprocessing of already written-off distributions. Most defensive and preferred version for subsequent runs.Run 01_setup_driver_tables.sql first. Creates:
RSI_PO_ACCR_77357 — mirrors PO_ACCRUAL_RECONCILE_TEMP_ALL structure with unique index on (PO_HEADER_ID, PO_LINE_ID, LINE_LOCATION_ID, INVENTORY_ITEM_ID, TRANSACTION_SOURCE_CODE). Used as backup for affected accrual reconciliation rows before write-off creation.RSI_AP_PO_ERRORS_77357 — error tracking table with columns: transaction_id, distribution_id (added vs. case 59272), trans_type, error_message, error_block. The distribution_id column enables error attribution at the distribution level, not just the transaction level.Accepts three runtime parameters: &p_variable1 (org_id), &p_variable2 (variance amount), &p_variable3 (override Y/N, default N).
Outer cursor getPOReceipts: selects all columns from PO_ACCRUAL_RECONCILE_TEMP_ALL where abs(net_po_line_amount) = &p_variable2, org_id = &p_variable1, transaction_source_code = 'PO', net_po_line_quantity = 0, write_off_id IS NULL.
For each PO row:
PO_ACCRUAL_RECONCILE_TEMP_ALL into RSI_PO_ACCR_77357 (DUP_VAL_ON_INDEX protected).PO_ACCRUAL_WRITE_OFFS_ALL using PO_ACCRUAL_WRITE_OFFS_S.NEXTVAL; updates the PO row (write_off_id, write_off_flag='Y', net_po_line_amount=0).v_po_distribution_id, v_transaction_amount = round(abs(rec1.transaction_amount)), v_transaction_quantity = abs(rec1.transaction_quantity).getAPRecs cursor (matches on po_distribution_id, transaction_source_code='AP'): for each AP row, creates an AP write-off record and updates the AP row.override = 'N': if round(abs(sum_AP_amounts)) <> round(abs(PO_amount)) — rolls back all changes for this distribution; logs error.override = 'Y': proceeds regardless of amount mismatch; logs warning only.RSI_AP_PO_ERRORS_77357.Key changes from Phase G:
getPOReceipts selects UNIQUE (po_header_id, po_line_id, line_location_id, po_distribution_id, po_transaction_id) — groups at the distribution level rather than fetching all columns per row.getPOTransactions: fetches all PO transaction rows for PO_DISTRIBUTION_ID = v_po_distribution_id, transaction_source_code='PO'. Creates one write-off record per PO transaction in the inner loop; accumulates v_transaction_amount and v_transaction_quantity across all PO transactions in the distribution.floor(abs(...)) instead of round(abs(...)), providing a more conservative match threshold.getAPRecs matches on po_distribution_id = v_po_distribution_id, transaction_source_code='AP'.Per-distribution processing: back up → inner PO loop (write-off per transaction) → inner AP loop (write-off per AP row) → amount validation with override → commit or rollback.
Identical to Phase H with one change: both getPOTransactions and getAPRecs cursors use SELECT UNIQUE ROWNUM, ... to deduplicate rows within each distribution group before creating write-off records. This prevents duplicate write-off insertions when the underlying data contains duplicate rows in PO_ACCRUAL_RECONCILE_TEMP_ALL.
Identical to Phase K with one change: outer cursor getPOReceipts selects UNIQUE (po_header_id, po_line_id, line_location_id, po_distribution_id) — po_transaction_id is removed from the outer driver key. This ensures the outer loop deduplicates strictly at the distribution level, eliminating any risk of the same distribution being processed multiple times due to different po_transaction_id values within the same distribution group.
Identical to Phase L with one additional filter added to both the preview query and the outer cursor getPOReceipts: AND write_off_flag <> 'Y'. This ensures the script is fully idempotent — distributions that were already written off in a previous run (where write_off_flag was set to 'Y') are excluded from reprocessing even if write_off_id IS NULL due to a partial prior update. Phase M is the preferred version for new runs.
&p_variable1), variance amount (&p_variable2), and override flag (&p_variable3, default N). The override parameter controls whether amount mismatches between PO and AP transaction totals cause rollback (N) or proceed with a warning (Y). Amount comparison in Phase G uses round(); Phases H through M use floor(). All scripts use REASON_ID = 232, WRITE_OFF_CODE = 'WRITE OFF', and LAST_UPDATED_BY = -9999. Script 01 must be run before any fix script. Run phases in order (G → H → K → L → M) only if earlier phases fail to resolve all records; for a clean engagement, run Phase M directly. The error table RSI_AP_PO_ERRORS_77357 includes a distribution_id column (absent in case 59272) enabling per-distribution error attribution. This case is closely related to case 00059272; the write-off logic and table structures are consistent between both cases except for the distribution-level grouping and override parameter added here.
| File | Description |
|---|---|
| 01_setup_driver_tables.sql | Creates backup table RSI_PO_ACCR_77357 (mirrors PO_ACCRUAL_RECONCILE_TEMP_ALL with unique index on 5 key columns) and error table RSI_AP_PO_ERRORS_77357 (includes distribution_id column). Must be run before any fix script. |
| 02_data_fix_phase_g.sql | Phase G: Per-PO-row write-off with 3 parameters (org_id, variance, override Y/N). AP matched via po_distribution_id. Amount validation uses round(). Creates one PO write-off and one-or-more AP write-offs per outer PO row. Rolls back (or proceeds with warning if override=Y) when AP amount sum mismatches. |
| 03_data_fix_phase_h.sql | Phase H: Distribution-level grouping. Outer key is UNIQUE (po_header_id, po_line_id, line_location_id, po_distribution_id, po_transaction_id). Inner getPOTransactions loop creates write-offs for all PO transactions in the distribution; amount comparison uses floor(). AP matched via po_distribution_id. |
| 04_data_fix_phase_k.sql | Phase K: Identical to Phase H with SELECT UNIQUE added to getPOTransactions and getAPRecs cursors to deduplicate inner result sets. |
| 05_data_fix_phase_l.sql | Phase L: Identical to Phase K with po_transaction_id removed from outer getPOReceipts key (strictly distribution-level outer deduplication on 4 fields). |
| 06_data_fix_phase_m.sql | Phase M (preferred): Identical to Phase L with write_off_flag <> 'Y' added to outer cursor and preview query, preventing re-processing of already written-off distributions. Most idempotent and defensive version. |
| Table | Action |
|---|---|
| PO_ACCRUAL_WRITE_OFFS_ALL | Insert write-off records for all PO transaction rows within each qualifying distribution (via PO_ACCRUAL_WRITE_OFFS_S.NEXTVAL), and for each matching AP accrual row (all phases) |
| PO_ACCRUAL_RECONCILE_TEMP_ALL | Update write_off_id, write_off_flag='Y', net_po_line_amount=0 for each written-off PO transaction and AP accrual row (all phases) |
| RSI_PO_ACCR_77357 | Backup of PO_ACCRUAL_RECONCILE_TEMP_ALL rows for the qualifying distribution before write-off (all phases) |
| RSI_AP_PO_ERRORS_77357 | Error log for per-transaction and per-distribution processing failures; includes distribution_id for precise error attribution (all phases) |