Files
bodyshop/server/rr/rr-error.js

104 lines
2.7 KiB
JavaScript

/**
* @file rr-error.js
* @description Centralized error class and assertion logic for Reynolds & Reynolds API calls.
* Provides consistent handling across all RR modules (customer, repair order, lookups, etc.)
*/
/**
* Custom Error type for RR API responses
*/
class RrApiError extends Error {
constructor(message, { reqId, url, apiName, errorData, status, statusText } = {}) {
super(message);
this.name = "RrApiError";
this.reqId = reqId || null;
this.url = url || null;
this.apiName = apiName || null;
this.errorData = errorData || null;
this.status = status || null;
this.statusText = statusText || null;
}
}
/**
* Assert that a Reynolds & Reynolds response is successful.
*
* Expected success structure (based on Rome RR specs):
* {
* "SuccessFlag": true,
* "ErrorCode": "0",
* "ErrorMessage": "",
* "Data": { ... }
* }
*
* Or if SOAP/XML-based:
* {
* "Envelope": {
* "Body": {
* "Response": {
* "SuccessFlag": true,
* ...
* }
* }
* }
* }
*
* This helper unwraps and normalizes the response to detect any error cases.
*/
function assertRrOk(data, { apiName = "RR API Call", allowEmpty = false } = {}) {
if (!data && !allowEmpty) {
throw new RrApiError(`${apiName} returned no data`, { apiName });
}
// Normalize envelope
const response =
data?.Envelope?.Body?.Response ||
data?.Envelope?.Body?.[Object.keys(data.Envelope?.Body || {})[0]] ||
data?.Response ||
data;
// Handle array of errors or error objects
const errorBlock = response?.Errors || response?.Error || response?.Fault || null;
// Basic success conditions per RR documentation
const success =
response?.SuccessFlag === true ||
response?.ErrorCode === "0" ||
response?.ResultCode === "0" ||
(Array.isArray(errorBlock) && errorBlock.length === 0);
// If success, return normalized response
if (success || allowEmpty) {
return response?.Data || response;
}
// Construct contextual error info
const errorMessage = response?.ErrorMessage || response?.FaultString || response?.Message || "Unknown RR API error";
throw new RrApiError(`${apiName} failed: ${errorMessage}`, {
apiName,
errorData: response,
status: response?.ErrorCode || response?.ResultCode
});
}
/**
* Safely unwrap nested RR API responses for consistency across handlers.
*/
function extractRrResponseData(data) {
if (!data) return null;
return (
data?.Envelope?.Body?.Response?.Data ||
data?.Envelope?.Body?.[Object.keys(data.Envelope?.Body || {})[0]]?.Data ||
data?.Data ||
data
);
}
module.exports = {
RrApiError,
assertRrOk,
extractRrResponseData
};