mirror of
https://github.com/Sea-Haven-Industries/payments-dashboard.git
synced 2026-09-30 07:43:12 +00:00
- Fix transaction code mapping (475=Cleared, 255=Returned) in fetchBoaTransactions - Match on customerReference instead of bankReference for check number matching - Add bank-confirmed protection: CSV cannot override status once bank confirms Cleared - Add status progression guard: CSV cannot regress status backward in lifecycle - Cleared status is permanent — cannot be voided, cancelled, or changed - Enable daily fetchBoaTransactions schedule (9am ET weekdays) - Add production test script and dry run simulation script
130 lines
3.9 KiB
JavaScript
130 lines
3.9 KiB
JavaScript
/**
|
|
* Dry-run test for BoA CashPro production API connectivity.
|
|
* 1. Authenticates with both Check Management and Reporting credentials
|
|
* 2. Calls Previous Day Transaction Inquiry (read-only)
|
|
* 3. Does NOT issue or cancel any checks
|
|
*
|
|
* Usage:
|
|
* node scripts/test-boa-prod.js
|
|
*/
|
|
|
|
import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm";
|
|
|
|
const ssm = new SSMClient();
|
|
const BASE_URL = "https://api.bofa.com";
|
|
|
|
async function getSSMParam(name) {
|
|
const { Parameter } = await ssm.send(
|
|
new GetParameterCommand({ Name: name, WithDecryption: true })
|
|
);
|
|
return Parameter.Value;
|
|
}
|
|
|
|
async function getAccessToken(applicationID, clientId, clientSecret) {
|
|
console.log(` Requesting token for ${applicationID}...`);
|
|
|
|
const res = await fetch(`${BASE_URL}/authn/v1/client-authentication`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
applicationID,
|
|
authn: { client_id: clientId, client_secret: clientSecret },
|
|
}),
|
|
});
|
|
|
|
const text = await res.text();
|
|
console.log(` Auth response (${res.status}):`, text, "\n");
|
|
|
|
if (!res.ok) {
|
|
throw new Error(`Auth failed for ${applicationID}: ${res.status} - ${text}`);
|
|
}
|
|
|
|
const data = JSON.parse(text);
|
|
return data.access_token;
|
|
}
|
|
|
|
async function main() {
|
|
console.log("Loading credentials from SSM...\n");
|
|
|
|
const [
|
|
checkMgmtAppId,
|
|
checkMgmtClientId,
|
|
checkMgmtSecret,
|
|
reportingAppId,
|
|
reportingClientId,
|
|
reportingSecret,
|
|
accountNumber,
|
|
bankId,
|
|
] = await Promise.all([
|
|
getSSMParam("/payments-dashboard/boa-check-mgmt-app-id"),
|
|
getSSMParam("/payments-dashboard/boa-check-mgmt-client-id"),
|
|
getSSMParam("/payments-dashboard/boa-check-mgmt-token"),
|
|
getSSMParam("/payments-dashboard/boa-reporting-app-id"),
|
|
getSSMParam("/payments-dashboard/boa-account-info-client-id"),
|
|
getSSMParam("/payments-dashboard/boa-account-info-token"),
|
|
getSSMParam("/payments-dashboard/boa-account-number"),
|
|
getSSMParam("/payments-dashboard/boa-bank-id"),
|
|
]);
|
|
|
|
console.log("Credentials loaded.\n");
|
|
|
|
// --- Step 1: OAuth for Check Management ---
|
|
console.log("=".repeat(60));
|
|
console.log("STEP 1: OAuth — Check Management");
|
|
console.log("=".repeat(60));
|
|
console.log();
|
|
|
|
const checkMgmtToken = await getAccessToken(checkMgmtAppId, checkMgmtClientId, checkMgmtSecret);
|
|
console.log(" ✓ Check Management token acquired\n");
|
|
|
|
// --- Step 2: OAuth for Reporting ---
|
|
console.log("=".repeat(60));
|
|
console.log("STEP 2: OAuth — Reporting");
|
|
console.log("=".repeat(60));
|
|
console.log();
|
|
|
|
const reportingToken = await getAccessToken(reportingAppId, reportingClientId, reportingSecret);
|
|
console.log(" ✓ Reporting token acquired\n");
|
|
|
|
// --- Step 3: Previous Day Transaction Inquiry (read-only) ---
|
|
console.log("=".repeat(60));
|
|
console.log("STEP 3: Previous Day Transaction Inquiry (read-only)");
|
|
console.log("=".repeat(60));
|
|
|
|
const yesterday = new Date();
|
|
yesterday.setDate(yesterday.getDate() - 1);
|
|
const dateStr = yesterday.toISOString().split("T")[0];
|
|
|
|
const inquiryPayload = {
|
|
fromDate: dateStr,
|
|
toDate: dateStr,
|
|
accounts: [{ accountNumber, bankId }],
|
|
};
|
|
|
|
console.log("Request:", JSON.stringify(inquiryPayload, null, 2), "\n");
|
|
|
|
const inquiryRes = await fetch(
|
|
`${BASE_URL}/cashpro/reporting/v1/transaction-inquiries/previous-day`,
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${reportingToken}`,
|
|
},
|
|
body: JSON.stringify(inquiryPayload),
|
|
}
|
|
);
|
|
|
|
const inquiryText = await inquiryRes.text();
|
|
console.log("Status:", inquiryRes.status);
|
|
console.log("Response:", inquiryText);
|
|
|
|
console.log("\n" + "=".repeat(60));
|
|
console.log("Dry run complete. No checks were issued or cancelled.");
|
|
console.log("=".repeat(60));
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error("Fatal error:", err);
|
|
process.exit(1);
|
|
});
|