feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration - Checkpoint
This commit is contained in:
@@ -1,103 +1,48 @@
|
||||
/**
|
||||
* @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.)
|
||||
* @description Custom error types for the Reynolds & Reynolds (Rome) integration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Custom Error type for RR API responses
|
||||
* Base RR API Error class — always structured with a message and a code.
|
||||
*/
|
||||
class RrApiError extends Error {
|
||||
constructor(message, { reqId, url, apiName, errorData, status, statusText } = {}) {
|
||||
/**
|
||||
* @param {string} message - Human-readable message
|
||||
* @param {string} [code="RR_ERROR"] - Short machine-readable error code
|
||||
* @param {Object} [details] - Optional structured metadata
|
||||
*/
|
||||
constructor(message, code = "RR_ERROR", details = {}) {
|
||||
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;
|
||||
this.code = code;
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
name: this.name,
|
||||
code: this.code,
|
||||
message: this.message,
|
||||
details: this.details
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Helper to normalize thrown errors into a consistent RrApiError instance.
|
||||
*/
|
||||
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
|
||||
);
|
||||
function toRrError(err, defaultCode = "RR_ERROR") {
|
||||
if (!err) return new RrApiError("Unknown RR error", defaultCode);
|
||||
if (err instanceof RrApiError) return err;
|
||||
if (typeof err === "string") return new RrApiError(err, defaultCode);
|
||||
const msg = err.message || "Unspecified RR error";
|
||||
const code = err.code || defaultCode;
|
||||
const details = err.details || {};
|
||||
return new RrApiError(msg, code, details);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RrApiError,
|
||||
assertRrOk,
|
||||
extractRrResponseData
|
||||
toRrError
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user