#!/usr/bin/env node
const https = require('https');
const { URLSearchParams } = require('url');
// ANSI color codes
const colors = {
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
reset: '\x1b[0m',
bold: '\x1b[1m'
};
async function makeApiRequest(apiKey, params, endpoint = 'api.umbrellacost.io') {
const queryParams = new URLSearchParams();
// Handle parameters properly
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
if (Array.isArray(value)) {
value.forEach(v => queryParams.append(key, v));
} else if (typeof value === 'object' && key === 'excludeFilters') {
// Handle excludeFilters specially
Object.entries(value).forEach(([filterKey, filterValues]) => {
filterValues.forEach((filterValue, index) => {
queryParams.append(`${key}[${filterKey}][]`, filterValue);
});
});
} else {
queryParams.append(key, value);
}
}
});
const url = `https://${endpoint}/api/v1/invoices/caui?${queryParams.toString()}`;
return new Promise((resolve, reject) => {
const startTime = Date.now();
const options = {
hostname: endpoint,
path: `/api/v1/invoices/caui?${queryParams.toString()}`,
method: 'GET',
headers: {
'Accept': 'application/json',
'apikey': apiKey
}
};
console.log(`${colors.cyan}Request URL:${colors.reset} ${url}`);
console.log(`${colors.cyan}API Key:${colors.reset} ${apiKey}`);
console.log(`${colors.cyan}Headers:${colors.reset}`, JSON.stringify(options.headers, null, 2));
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
const responseTime = Date.now() - startTime;
try {
const json = JSON.parse(data);
resolve({
status: res.statusCode,
headers: res.headers,
data: json,
dataLength: json.Data ? json.Data.length : 0,
responseTime,
url
});
} catch (e) {
resolve({
status: res.statusCode,
headers: res.headers,
error: e.message,
raw: data.substring(0, 500),
responseTime,
url
});
}
});
});
req.on('error', reject);
req.end();
});
}
async function compareAccounts() {
console.log(`${colors.bold}${colors.magenta}=== DETAILED ACCOUNT COMPARISON ===${colors.reset}`);
console.log(`${colors.cyan}Testing Date: ${new Date().toISOString()}${colors.reset}\n`);
// Test configurations
const tests = [
{
name: 'AWS Account (932213950603) - WORKING',
apiKey: '8bd39ae4-ebea-4426-bd22-07349dd8b962:9350:0',
params: {
startDate: '2025-01-01',
endDate: '2025-09-30',
groupBy: 'none',
periodGranLevel: 'month',
costType: ['cost', 'discount'],
isUnblended: 'true',
excludeFilters: { chargetype: ['Tax'] }
}
},
{
name: 'MasterBilling (Master-59f88c) - NOT WORKING',
apiKey: '8bd39ae4-ebea-4426-bd22-07349dd8b962:21112:0',
params: {
startDate: '2025-01-01',
endDate: '2025-09-30',
groupBy: 'none',
periodGranLevel: 'month',
costType: ['cost', 'discount'],
isUnblended: 'true',
excludeFilters: { chargetype: ['Tax'] }
}
},
{
name: 'MasterBilling WITH cloud_context=gcp',
apiKey: '8bd39ae4-ebea-4426-bd22-07349dd8b962:21112:0',
params: {
startDate: '2025-01-01',
endDate: '2025-09-30',
groupBy: 'none',
periodGranLevel: 'month',
costType: ['cost', 'discount'],
isUnblended: 'true',
cloud_context: 'gcp',
excludeFilters: { chargetype: ['Tax'] }
}
},
{
name: 'MasterBilling WITHOUT isUnblended',
apiKey: '8bd39ae4-ebea-4426-bd22-07349dd8b962:21112:0',
params: {
startDate: '2025-01-01',
endDate: '2025-09-30',
groupBy: 'none',
periodGranLevel: 'month',
costType: ['cost', 'discount'],
excludeFilters: { chargetype: ['Tax'] }
}
},
{
name: 'MasterBilling with DOUBLE groupBy (like UI)',
apiKey: '8bd39ae4-ebea-4426-bd22-07349dd8b962:21112:0',
params: {
startDate: '2025-01-01',
endDate: '2025-09-30',
groupBy: ['none', 'usagedate'],
periodGranLevel: 'month',
costType: ['cost', 'discount']
}
},
{
name: 'MasterBilling via api-front.umbrellacost.io',
apiKey: '8bd39ae4-ebea-4426-bd22-07349dd8b962:21112:0',
params: {
startDate: '2025-01-01',
endDate: '2025-09-30',
groupBy: ['none', 'usagedate'],
periodGranLevel: 'month',
costType: ['cost', 'discount']
},
endpoint: 'api-front.umbrellacost.io'
},
{
name: 'MasterBilling - Different Date Range (2024)',
apiKey: '8bd39ae4-ebea-4426-bd22-07349dd8b962:21112:0',
params: {
startDate: '2024-01-01',
endDate: '2024-12-31',
groupBy: 'none',
periodGranLevel: 'month',
costType: ['cost', 'discount'],
isUnblended: 'true',
excludeFilters: { chargetype: ['Tax'] }
}
}
];
const results = [];
for (const test of tests) {
console.log(`\n${colors.bold}${colors.yellow}Testing: ${test.name}${colors.reset}`);
console.log('─'.repeat(80));
try {
const result = await makeApiRequest(
test.apiKey,
test.params,
test.endpoint || 'api.umbrellacost.io'
);
results.push({ ...test, result });
console.log(`${colors.bold}Status:${colors.reset} ${result.status === 200 ? colors.green : colors.red}${result.status}${colors.reset}`);
console.log(`${colors.bold}Response Time:${colors.reset} ${result.responseTime}ms`);
console.log(`${colors.bold}Records:${colors.reset} ${result.dataLength > 0 ? colors.green : colors.red}${result.dataLength}${colors.reset}`);
if (result.headers) {
console.log(`${colors.bold}Response Headers:${colors.reset}`);
['content-type', 'x-request-id', 'x-amzn-requestid'].forEach(header => {
if (result.headers[header]) {
console.log(` ${header}: ${result.headers[header]}`);
}
});
}
if (result.dataLength > 0) {
const firstRecord = result.data.Data[0];
console.log(`${colors.bold}${colors.green}✓ DATA FOUND${colors.reset}`);
console.log(`${colors.bold}Sample Record:${colors.reset}`);
console.log(` Date: ${firstRecord.date || firstRecord.Date || 'N/A'}`);
console.log(` Cost: ${firstRecord.cost || firstRecord.Cost || 'N/A'}`);
console.log(` Service: ${firstRecord.service || firstRecord.Service || 'N/A'}`);
// Show unique services if grouped
if (result.data.Data && result.data.Data.length > 1) {
const services = [...new Set(result.data.Data.map(d => d.service || d.Service).filter(Boolean))];
console.log(` Unique Services: ${services.slice(0, 5).join(', ')}${services.length > 5 ? '...' : ''}`);
}
} else {
console.log(`${colors.bold}${colors.red}✗ NO DATA RETURNED${colors.reset}`);
if (result.data && result.data.message) {
console.log(` Message: ${result.data.message}`);
}
if (result.error) {
console.log(` Error: ${result.error}`);
}
}
} catch (error) {
console.log(`${colors.red}✗ Request Failed: ${error.message}${colors.reset}`);
results.push({ ...test, error: error.message });
}
}
// Summary comparison
console.log(`\n${colors.bold}${colors.magenta}=== SUMMARY COMPARISON ===${colors.reset}`);
console.log('─'.repeat(80));
const workingTests = results.filter(r => r.result && r.result.dataLength > 0);
const failedTests = results.filter(r => !r.result || r.result.dataLength === 0);
console.log(`\n${colors.green}${colors.bold}WORKING CONFIGURATIONS (${workingTests.length}):${colors.reset}`);
workingTests.forEach(test => {
console.log(` ✓ ${test.name}`);
console.log(` Records: ${test.result.dataLength}, Response Time: ${test.result.responseTime}ms`);
});
console.log(`\n${colors.red}${colors.bold}FAILING CONFIGURATIONS (${failedTests.length}):${colors.reset}`);
failedTests.forEach(test => {
console.log(` ✗ ${test.name}`);
if (test.result) {
console.log(` Status: ${test.result.status}, Records: 0`);
} else if (test.error) {
console.log(` Error: ${test.error}`);
}
});
// Key differences analysis
console.log(`\n${colors.bold}${colors.cyan}=== KEY DIFFERENCES ANALYSIS ===${colors.reset}`);
console.log('─'.repeat(80));
const awsWorking = results.find(r => r.name.includes('932213950603'));
const masterNotWorking = results.find(r => r.name === 'MasterBilling (Master-59f88c) - NOT WORKING');
if (awsWorking && masterNotWorking) {
console.log(`\n${colors.bold}Account Comparison:${colors.reset}`);
console.log(` AWS (Working): Account Key = 9350, Records = ${awsWorking.result.dataLength}`);
console.log(` MasterBilling (Not): Account Key = 21112, Records = ${masterNotWorking.result.dataLength}`);
console.log(`\n${colors.bold}URL Differences:${colors.reset}`);
console.log(` AWS URL: ${awsWorking.result.url}`);
console.log(` Master URL: ${masterNotWorking.result.url}`);
// Check if any MasterBilling variant worked
const workingMasterVariant = results.find(r =>
r.name.includes('MasterBilling') &&
r.result &&
r.result.dataLength > 0
);
if (workingMasterVariant) {
console.log(`\n${colors.green}${colors.bold}✓ SOLUTION FOUND:${colors.reset}`);
console.log(` Working variant: ${workingMasterVariant.name}`);
console.log(` Key difference: Check the parameters or endpoint used`);
} else {
console.log(`\n${colors.red}${colors.bold}✗ NO WORKING CONFIGURATION FOUND FOR MASTERBILLING${colors.reset}`);
console.log(` This indicates the issue is likely on the backend API side.`);
console.log(` The account key 21112 may not have data or may require special permissions.`);
}
}
console.log(`\n${colors.bold}${colors.yellow}=== RECOMMENDATIONS ===${colors.reset}`);
console.log('─'.repeat(80));
console.log('1. If api-front.umbrellacost.io works, update the server to use it for GCP accounts');
console.log('2. If double groupBy works, implement that pattern for MasterBilling');
console.log('3. If all MasterBilling tests fail, the issue is backend data availability');
console.log('4. Check if account key 21112 has proper permissions or data in the system');
console.log('5. Consider if GCP accounts need special handling or different endpoints');
}
// Run the comparison
compareAccounts().catch(console.error);