AP Payment-Run Optimizer Copy link
Plugin: Blitz Report Excel Add-in Skills (
br-ap-payment-optimizer)Works with: Claude in Excel, Microsoft 365 Copilot in Excel
Optimize an Oracle EBS Accounts Payable payment run in Excel: have the br-run-reports skill extract the AP cash requirement (due invoices, available early-pay discounts, due dates, payment priority), classify each invoice as capture-discount / pay-to-avoid-late / defer-to-due / priority-must-pay, select the best pay run within a cash constraint by discount ROI, quantify the discount $ captured and DPO impact, and build a payment-run dashboard.
When to use it
- Use when the user asks which invoices to pay and when, capture early-pay discounts, optimize a payment batch, plan a cash disbursement, or improve DPO.
- Download the skill zip. br-ap-payment-optimizer.zip
- In Claude in Excel open Customize > Skills > Create skill and upload the zip.
- Connect the Blitz Report Excel add-in to your Oracle EBS instance, then ask Claude for the task in your own words.
- Download the skill folder from GitHub. br-ap-payment-optimizer
- Copy the folder into Documents/Copilot/Microsoft Excel/Skills in your OneDrive.
- Open Excel with the Blitz Report add-in connected and ask Copilot for the task.
- Add the Enginatics marketplace in Claude Code.
/plugin marketplace add enginatics/ai-skills - Install the Excel add-in skills plugin.
/plugin install blitz-report-excel-addin-ai-skills@enginatics - Run the setup skill; it installs or updates the skills in Claude in Excel or Microsoft 365 Copilot in Excel.
/blitz-report-excel-addin-ai-skills:excel-skills-setup
Requirements: Blitz Report and the Blitz Report Excel add-in, connected to your Oracle EBS instance, plus Claude in Excel or Microsoft 365 Copilot in Excel.
π¨ Blitz data = Excel worksheet UDFs, not MCP tools/connectors. Extract data only by writing
=br_...()into a cell (viaexecute_office_js) and reading the spill β nevertool_searchforbr_*, neverrefresh_mcp_connectors, and never conclude "no Oracle EBS / Blitz connector is set up" (the Blitz Report add-in is an Excel add-in, not an MCP connector, so it never appears in the connector list β its absence there is expected). Load the extraction mechanism first:read_skill("br-run-reports").Performance: Read
br-analytics-standardsat the start of every run (read_skill("br-analytics-standards")). All pipeline steps must follow those rules. Target runtime: Standard run under 5 minutes β one extract, one classify pass, one optimize pass, dashboard. Step 6 (cash-outflow projection) is the only deep-dive add-on and is opt-in; do not run it unasked. There is no Step-0 depth prompt here because that single add-on is the only optional work β just don't volunteer it.
Produce an optimized AP payment-run recommendation in one Excel workbook. You own the orchestration, the per-invoice classification, the cash-constrained selection, and the written recommendation; the specialist skills do the extraction and the dashboard build. Run steps in order, on separate turns, keeping every intermediate sheet so the user can audit each decision.
Requires: br-run-reports (extraction). Optional: br-data-dashboard (dashboard build β if it doesn't fire, build inline per Step 5); br-forecasting (forward cash-outflow projection β Step 6).
Division of responsibility β READ FIRST
You do NOT run Blitz reports yourself. All extraction is performed by the br-run-reports skill, which owns add-in connection, authentication, asynchronous execution, completion polling, and deterministic cell population.
- Never call
br_*add-in functions directly. - Never rename the result sheet, read its values, sum a column, or start any analysis until extraction is confirmed complete β touching the workbook while the add-in's run is still in flight can stall it and the run will never finish.
- Your job is only: (1) ask br-run-reports to fetch the data, then (2) once it has fully landed, classify, optimize, and present it.
This skill is read-and-recommend only. It does NOT create or submit a Payment Process Request, select invoices for payment in EBS, or place/release any hold. It produces a recommended pay run and a deferred list; building the actual payment batch is a separate, human-approved step.
When to use
"Which invoices should we pay this week and when", "capture early-pay discounts", "optimize our payment run", "plan the cash disbursement", "improve DPO without missing discounts", "what can we safely defer". For a plain due-invoices list with no optimization, use br-run-reports directly.
Inputs (collect up front)
- Operating Unit (required) β ask if not supplied.
- Pay Through Date (required) β the horizon: which invoices are in scope for this run (the report shows everything due on/before it).
- Optional: Cash available β the constraint for this run. If omitted, there is no cap and the optimizer recommends the economically-ideal run (capture every beneficial discount, pay everything due, defer the rest); if supplied, it selects the best subset within the cap.
- Optional: Supplier / Payment Method / Payment Priority filter; "include unvalidated/unapproved" (default No β only payable invoices); a cost-of-cash / annual borrowing rate (default 10%) used to judge whether paying early to capture a discount is genuinely beneficial.
Reports used (authoritative names β do NOT broad-search for them)
These exact report names are known. When you ask br-run-reports to run one, pass the documented
name directly β do NOT run a br_report_list_external discovery search first. Inspect parameters
only if you need an exact LOV spelling. Fallback: only if a run returns #BLITZ_REPORT_NOT_FOUND do a name search. If a run returns a bare ERROR: ERROR, the param names didn't match β have
br-run-reports inspect params (br_report_params_external) and adapt, then retry; don't abandon it.
| Report (exact name) | Run with | Role |
|---|---|---|
AP Cash Requirement | Operating Unit (required, multi-value) + Pay Through Date (the run horizon β the report's own param is optional, but set it to scope which invoices are in play). Optional: Due Date From/To, Payment Method, Payment Priority From/To, and Economically Beneficial = Yes (a filter param β see note). Leave Include Unvalidated Invoices / Include Unapproved Invoices = No unless asked. | The optimization base β one row per due invoice with the discount columns, due date, priority, and in-report hold flags. Payables (always present) |
AP Invoice on Hold (optional, rarely needed) | Operating Unit | A separate held-invoice list β usually unnecessary: AP Cash Requirement already carries HOLD_FLAG / HOLDS_COUNT per row, so exclude held invoices in-sheet. |
AP Invoices and Lines (optional) | Operating Unit + Open only = Yes + Display Level = Headers | Richer terms / context if AP Cash Requirement lacks a column you need. |
Verified output columns (r12, parsed):
TRADING_PARTNER(the supplier),INVOICE_NUM,INVOICE_DATE,DUE_DATE,DAYS_TO_DUE,GROSS_AMOUNT/AMOUNT(payment ccy) /FUNCTIONAL_CURRENCY_AMOUNT,INVOICE_CURRENCY_CODE,PAYMENT_PRIORITY,PAYMENT_METHOD,PAY_GROUP,DISCOUNT_DATE,DISCOUNT_AMOUNT_AVAILABLE,DISCOUNT_AMOUNT_REMAINING,PAYMENT_STATUS,INVOICE_STATUS,APPROVED,HOLD_FLAG,HOLDS_COUNT,OPERATING_UNIT,INVOICE_ID. π¨ There is NO "Economically Beneficial" output column β it exists only as a Yes-only filter parameter (set it = Yes to have EBS pre-filter to invoices where the discount beats the cost of cash). This skill computes its own discount ROI fromDISCOUNT_AMOUNT_AVAILABLE+DISCOUNT_DATE
DUE_DATE/DAYS_TO_DUE, so it does not depend on that flag β but you MAY setEconomically Beneficial = Yesto shrink the working set on a very large OU.
CONFIG β edit to match the customer; logic below reads from here
π¨ Amount column β MANDATORY functional consolidation when currencies mix
First check how many INVOICE_CURRENCY_CODE values are present. If more than one, you MUST sum FUNCTIONAL_CURRENCY_AMOUNT β never GROSS_AMOUNT (payment currency). Summing payment-currency
magnitudes across currencies is meaningless: a foreign line in its own units doesn't compare to a USD
line (real Vision rows: FRF 2,060,630 gross = $345,134 functional; EGP 4,400 = $151,400; JPY 26,991 = $212). Do NOT write grossAmount || functionalAmount (the || prefers gross and
reintroduces the bug). Pick one column up front by currency count:
// COPY VERBATIM (port of skill_logic.py::consolidated_amount)
const multiCcy = new Set(rows.map(r => r.invoiceCurrencyCode)).size > 1;
const amountOf = inv => Number(multiCcy ? inv.functionalAmount : inv.grossAmount) || 0;Single currency β GROSS_AMOUNT is fine and reads natively. Label every total as functional when multiCcy.
Per-invoice decision class (columns are the verified r12 headers)
Classify each in-scope invoice (today = run date), reading DISCOUNT_AMOUNT_AVAILABLE, DISCOUNT_DATE, DUE_DATE, DAYS_TO_DUE, PAYMENT_PRIORITY, HOLD_FLAG/HOLDS_COUNT, INVOICE_STATUS, APPROVED, and the amount (amountOf above β functional when the OU mixes
currencies, gross otherwise). π¨ Test the classes in EXACTLY this order β each if/else if falls through to the next:
- Excluded (test 1st) β
HOLD_FLAG='Y' /HOLDS_COUNT>0, or not approved/validated (APPROVED/INVOICE_STATUSnot in a payable state). Not payable β show but never select. - Capture-Discount (test 2nd β BEFORE Priority and Late) β
DISCOUNT_AMOUNT_AVAILABLE> 0 andDISCOUNT_DATEβ₯ today and the discount is beneficial (ROI > cost of cash, below). Pay byDISCOUNT_DATEto captureDISCOUNT_AMOUNT_AVAILABLE. π¨ This MUST be tested before Priority-Must-Pay / Pay-To-Avoid-Late β a beneficial discount whose date hasn't passed is captured even on a high-priority or overdue invoice (you still pay it, AND you save the discount). A live run tested Priority first and under-reported capturable discount by ~$119K ($690K instead of $809K) because high-priority discount-eligible invoices were mis-labelled Priority-Must-Pay. - Pay-To-Avoid-Late (test 3rd) β
DAYS_TO_DUEβ€ 0 (already due / past due) with no remaining discount. Pay now to avoid late penalties / supplier-relationship damage. - Priority-Must-Pay (test 4th) β
PAYMENT_PRIORITYat/above the critical threshold (default β€ 10, i.e. highest), or a flagged critical supplier β pay regardless of economics. - Defer-To-Due (the fall-through default) β no beneficial discount and
DAYS_TO_DUE> 0 β hold the cash, pay onDUE_DATEto maximize DPO. (Deferring is the correct default; never pay early with no discount.)
Discount ROI (ranks the discount-capture opportunities)
discount_% β DISCOUNT_AMOUNT_AVAILABLE Γ· amount; days_accelerated β DUE_DATE β DISCOUNT_DATE (how much earlier you pay to earn it). The implied annualized return is ROI β discount_% Γ· days_accelerated Γ 365. A 2%/10-net-30 discount β 36% annualized β far above any
cost of cash. The discount is beneficial when this ROI exceeds the user's cost-of-cash
(default 10%). Rank capture opportunities by DISCOUNT_AMOUNT_AVAILABLE for headline impact, and
by ROI when cash is constrained (highest-return discounts first per dollar of accelerated cash). (EBS tiers later discounts too β SECOND_DISC_AMT_AVAILABLE/THIRD_DISC_AMT_AVAILABLE with SECOND_DISCOUNT_DATE/THIRD_DISCOUNT_DATE; default to the first discount, surface the later tiers
only if asked.)
Cash-constrained selection (only when "Cash available" is supplied)
Select invoices to maximize (discount $ captured + late penalties avoided) subject to Ξ£ paid β€ cash cap, in this precedence:
- Priority-Must-Pay and Pay-To-Avoid-Late first (non-negotiable β these get paid).
- Then Capture-Discount by descending ROI (greedy) until the cash runs out β each captured discount is free money per day of accelerated cash.
- Defer-To-Due is not funded by this run (it isn't due yet). If steps 1β2 exceed the cap, report the shortfall and which beneficial discounts had to be dropped (the cost of the cash constraint = the discount $ left on the table). With no cap, the recommended run = all Priority/Late + all beneficial Capture-Discount, by their pay-by dates.
DPO / cash framing
pay_by_date= discount date (Capture-Discount), run date (Pay-To-Avoid-Late / Priority), or due date (Defer-To-Due). The run schedule is grouped bypay_by_date.- DPO impact β paying only what's due/beneficial and deferring the rest lengthens DPO; flag any invoice being paid early with no discount as a DPO leak (should be Defer-To-Due).
Output sheet names & tab order (left to right)
AP_Pay_Run (dashboard, first), Pay_Schedule (selected invoices by pay-by date), Deferred (not-funded / defer-to-due, with deferral note), AP_Cash_Req (the extracted base β its report name).
Pipeline
Step 1 β Extract (DELEGATE to br-run-reports β do not run it yourself)
Ask br-run-reports to run "AP Cash Requirement" with Operating Unit = {OU} and Pay Through
Date = {horizon} (Include Unvalidated/Unapproved = No). The report already carries HOLD_FLAG per
row, so no separate holds run is needed (only add "AP Invoice on Hold" if the user wants hold
detail). Pass the exact name directly; wait for completion; do nothing mid-run.
#BLITZ_NOT_CONNECTEDβ relay it, ask the user to connect via the Blitz Report ribbon, retry.- Fallback: if the hand-off doesn't fire or the data never lands, tell the user to run "AP Cash Requirement" themselves for the OU + pay-through date, then ask you to optimize it; resume at 1b.
Step 1b β Anchor (single execute_office_js call)
In one call: locate the columns (TRADING_PARTNER, INVOICE_NUM, GROSS_AMOUNT, DUE_DATE, DAYS_TO_DUE, DISCOUNT_AMOUNT_AVAILABLE, DISCOUNT_DATE, PAYMENT_PRIORITY, HOLD_FLAG, INVOICE_CURRENCY_CODE), record the invoice count, total amount due in horizon (SUM GROSS_AMOUNT), and total discount available (SUM DISCOUNT_AMOUNT_AVAILABLE) as the
reconciliation anchors, and return them. If zero invoices: report "no AP invoices due on/before
{pay-through date} for {OU}" and stop.
Step 2 β Classify + economics (single execute_office_js call)
In one call: derive days_accelerated (DUE_DATE β DISCOUNT_DATE), ROI, pay_by_date, and the decision class per CONFIG β excluding held/unapproved rows in-sheet via HOLD_FLAG/APPROVED (no separate report needed) β writing all headers + seed row + autoFill to the last row in the same
block (Rule 4). Compute "beneficial" yourself (ROI > cost of cash); do not look for an
Economically Beneficial column (there isn't one). Consolidate amounts via FUNCTIONAL_CURRENCY_AMOUNT when the OU mixes currencies (otherwise compare same-currency only).
Text-format only literal label cells, never formula cells (Excel-correctness #1). Return counts + $
by decision class and total discount $ capturable.
Step 3 β Optimize the run (single execute_office_js call)
In one call: if Cash available was supplied, run the cash-constrained greedy selection per CONFIG
(Priority + Late first, then Capture-Discount by ROI until the cap) and mark each invoice Selected or Deferred with the reason; if no cap, mark all Priority/Late/beneficial-Capture as
Selected and all not-yet-due as Deferred. Build Pay_Schedule (Selected, grouped by pay_by_date)
and Deferred (not funded / defer-to-due, each with a one-line reason and the deferral cost if a
discount was dropped). Return: total to pay, discount $ captured, late exposure avoided, and (if
capped) the discount $ left on the table.
Step 4 β (reserved) (no-op placeholder to keep Step 3 and the dashboard as separate single calls)
Step 5 β Dashboard (two execute_office_js calls: data then charts) (delegate to br-data-dashboard if it fires; else inline)
Call 1 β all data sections on a NEW AP_Pay_Run sheet at position 0: KPI band (Total due
in horizon, Recommended pay-run $, Discount $ captured, Late exposure avoided, $
deferred, and β if capped β discount $ left on the table); a decision-class breakdown
(count + $ for Capture-Discount / Pay-To-Avoid-Late / Priority-Must-Pay / Defer-To-Due / Excluded); a pay-by-date schedule (cash needed per date); and the top-N discount-capture opportunities by
$ (supplier, invoice, discount $, discount date, ROI). Every KPI is a formula referencing Pay_Schedule / AP_Cash_Req (COUNTIFS/SUMIFS) so it refreshes on re-run. Call 2 β charts only: a cash-needed-by-date column chart and a decision-class bar chart.
- Build mechanics (house standard): build only on the new sheet; do not rename the report
sheet (KPIs link to it). Do NOT use a multi-row
copyToRangeto fill schedule rows β write each formula explicitly. After building, scan beyond the dashboard range, clear stray cells, widen amount columns so values don't render as######.
Step 6 β Cash-outflow projection (OPTIONAL add-on β only if the user asks)
Delegate to br-forecasting (or compute inline) a weekly cash-outflow profile from the pay_by_date schedule across the horizon β a Cash_Outflow panel/sheet. This is a schedule roll-up, not a
statistical forecast β label it so.
It derives purely from Pay_Schedule, so adding it later costs no re-extract: verify Pay_Schedule is unchanged, build Cash_Outflow, and re-run Step 8 to place the tab. Never point a
dashboard KPI at Cash_Outflow unless this step ran.
Step 7 β Narrative (single set_cell_range call)
Write all β€6 bullets on AP_Pay_Run in one call: "pay these N by <discount date> to capture $X in
discounts"; the total recommended pay-run $ and the cash needed by date; how much can be safely
deferred to lengthen DPO (and confirm nothing is being paid early for no discount); the single
biggest discount opportunity (supplier + $ + ROI); if capped, the discount $ left on the table and
what extra cash would unlock it; and any excluded held/unvalidated invoices to clear first.
Then, in your reply (not on the sheet), if Step 6 was skipped, offer it in one line and say it needs no re-extract β e.g. "Want the weekly cash-outflow profile off this schedule? I can add it without re-running the report."
Step 8 β Arrange tabs + final validation (single execute_office_js call + one read)
Reorder tabs to AP_Pay_Run, Pay_Schedule, Deferred, AP_Cash_Req (+ Cash_Outflow if built);
delete the blitz_ helper sheet; activate AP_Pay_Run. Then the one permitted verification read: confirm Selected $ + Deferred $ + Excluded $ = total
due (Step-1b anchor), that Selected $ β€ cash cap when a cap was given, and that captured
discount $ ties to the schedule. This is the only explicit re-read outside Step 1b.
Validation (before declaring done)
- Reconcile: Selected + Deferred + Excluded $ = the Step-1b total-due anchor; the pay-by-date schedule sums to the recommended pay-run $.
- Constraint: when a cash cap was supplied, recommended pay-run $ β€ cap; the shortfall and dropped discounts are reported.
- Economics sanity: every Capture-Discount invoice has
DISCOUNT_DATEβ₯ run date and a computed ROI > cost of cash; no invoice is paid early without a discount (those must be Defer-To-Due). - No
######and no stray cells outside the dashboard range.
Re-run / refresh
Never re-extract when you don't have to:
- "Different cash budget" (same data) β re-run only Steps 3 and 5β8; the extract and the Step-2 classification are unchanged.
- "Add the cash-outflow projection" (same data) β run only Step 6, then Step 8 for the tab.
- "Next week's run" / a new Pay Through Date / "rebuild" (new data) β re-drive from Step 1, rebuilding the same set of sheets the previous run produced.
Closed-loop (roadmap, not executed here)
Building the payment batch is a Payment Process Request (a concurrent submit / Payments-form action); placing or releasing an invoice hold is a Blitz Upload. This skill recommends the run; a human executes it.