Add temporary debug endpoints and methods for WHMCS payment methods testing
- Introduced `testPaymentMethods` endpoint in InvoicesController to directly test WHMCS payment methods for a specific client ID. - Added `testWhmcsPaymentMethods` method in InvoicesService for detailed logging and error handling during WHMCS API calls. - Implemented cache bypassing and enhanced logging in `getPaymentMethods` method of WhmcsPaymentService for debugging purposes. - Updated payment method transformation logic in WhmcsDataTransformer to handle variations in WHMCS API responses. - Added debug information in Checkout and AddressConfirmation components to assist in troubleshooting address confirmation flow.
This commit is contained in:
parent
1640fae457
commit
a8f02ebc2b
@ -128,6 +128,16 @@ export class InvoicesController {
|
||||
return this.invoicesService.getPaymentGateways();
|
||||
}
|
||||
|
||||
@Get("test-payment-methods/:clientId")
|
||||
@ApiOperation({
|
||||
summary: "Test WHMCS payment methods API for specific client ID",
|
||||
description: "Direct test of WHMCS GetPayMethods API - TEMPORARY DEBUG ENDPOINT",
|
||||
})
|
||||
@ApiParam({ name: "clientId", type: Number, description: "WHMCS Client ID to test" })
|
||||
async testPaymentMethods(@Param("clientId", ParseIntPipe) clientId: number): Promise<any> {
|
||||
return this.invoicesService.testWhmcsPaymentMethods(clientId);
|
||||
}
|
||||
|
||||
@Post("payment-methods/refresh")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({
|
||||
|
||||
@ -466,6 +466,45 @@ export class InvoicesService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TEMPORARY DEBUG METHOD: Test WHMCS payment methods API directly
|
||||
*/
|
||||
async testWhmcsPaymentMethods(clientId: number): Promise<any> {
|
||||
try {
|
||||
this.logger.log(`🔬 TESTING WHMCS GetPayMethods API for client ${clientId}`);
|
||||
|
||||
// Call WHMCS API directly with detailed logging
|
||||
const result = await this.whmcsService.getPaymentMethods(clientId, `test-client-${clientId}`);
|
||||
|
||||
this.logger.log(`🔬 Test result for client ${clientId}:`, {
|
||||
totalCount: result.totalCount,
|
||||
paymentMethods: result.paymentMethods,
|
||||
});
|
||||
|
||||
return {
|
||||
clientId,
|
||||
testTimestamp: new Date().toISOString(),
|
||||
whmcsResponse: result,
|
||||
summary: {
|
||||
totalPaymentMethods: result.totalCount,
|
||||
hasPaymentMethods: result.totalCount > 0,
|
||||
paymentMethodTypes: result.paymentMethods.map(pm => pm.type),
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error(`🔬 Test failed for client ${clientId}`, {
|
||||
error: getErrorMessage(error),
|
||||
});
|
||||
|
||||
return {
|
||||
clientId,
|
||||
testTimestamp: new Date().toISOString(),
|
||||
error: getErrorMessage(error),
|
||||
errorType: error instanceof Error ? error.constructor.name : typeof error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create payment SSO link for invoice with specific payment method or gateway
|
||||
*/
|
||||
|
||||
@ -21,16 +21,29 @@ export class WhmcsPaymentService {
|
||||
*/
|
||||
async getPaymentMethods(clientId: number, userId: string): Promise<PaymentMethodList> {
|
||||
try {
|
||||
// Try cache first
|
||||
const cached = await this.cacheService.getPaymentMethods(userId);
|
||||
if (cached) {
|
||||
this.logger.debug(`Cache hit for payment methods: user ${userId}`);
|
||||
return cached;
|
||||
}
|
||||
// TEMPORARILY BYPASS CACHE for debugging
|
||||
console.log(`🔍 BYPASSING CACHE for debugging - client ${clientId}, user ${userId}`);
|
||||
|
||||
// COMPLETELY BYPASS CACHE for debugging
|
||||
console.log(`🔍 COMPLETELY BYPASSING CACHE for debugging - client ${clientId}, user ${userId}`);
|
||||
|
||||
// Try cache first - DISABLED FOR DEBUGGING
|
||||
// const cached = await this.cacheService.getPaymentMethods(userId);
|
||||
// if (cached && false) { // Force bypass cache
|
||||
// this.logger.debug(`Cache hit for payment methods: user ${userId}`);
|
||||
// return cached;
|
||||
// }
|
||||
|
||||
const response = await this.connectionService.getPayMethods({ clientid: clientId });
|
||||
|
||||
// Debug logging to understand what WHMCS returns
|
||||
console.log(`🔍 WHMCS GetPayMethods DEBUG for client ${clientId}:`);
|
||||
console.log('Raw response:', JSON.stringify(response, null, 2));
|
||||
console.log('Paymethods:', response.paymethods);
|
||||
console.log('Paymethod array:', response.paymethods?.paymethod);
|
||||
console.log('Is array:', Array.isArray(response.paymethods?.paymethod));
|
||||
console.log('Length:', response.paymethods?.paymethod?.length);
|
||||
|
||||
this.logger.log(`WHMCS GetPayMethods response for client ${clientId}:`, {
|
||||
rawResponse: response,
|
||||
paymethods: response.paymethods,
|
||||
@ -40,28 +53,71 @@ export class WhmcsPaymentService {
|
||||
userId
|
||||
});
|
||||
|
||||
const methods = (response.paymethods?.paymethod || []).map(pm => {
|
||||
const transformed = this.dataTransformer.transformPaymentMethod(pm);
|
||||
this.logger.log(`Transformed payment method:`, {
|
||||
original: pm,
|
||||
transformed,
|
||||
clientId,
|
||||
userId
|
||||
});
|
||||
return transformed;
|
||||
});
|
||||
// Handle different response structures
|
||||
// According to WHMCS API docs, GetPayMethods returns { paymethods: [...] } directly
|
||||
let paymentMethodsArray: any[] = [];
|
||||
if (response.paymethods) {
|
||||
if (Array.isArray(response.paymethods)) {
|
||||
// Direct array response (correct for GetPayMethods)
|
||||
paymentMethodsArray = response.paymethods;
|
||||
} else if (response.paymethods.paymethod) {
|
||||
// Nested structure (for GetPaymentMethods - payment gateways)
|
||||
if (Array.isArray(response.paymethods.paymethod)) {
|
||||
paymentMethodsArray = response.paymethods.paymethod;
|
||||
} else {
|
||||
paymentMethodsArray = [response.paymethods.paymethod];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`🔍 Payment methods array:`, paymentMethodsArray);
|
||||
console.log(`🔍 Array length:`, paymentMethodsArray.length);
|
||||
|
||||
const methods = paymentMethodsArray.map(pm => {
|
||||
console.log(`🔍 Processing payment method:`, pm);
|
||||
try {
|
||||
const transformed = this.dataTransformer.transformPaymentMethod(pm);
|
||||
console.log(`🔍 Transformed to:`, transformed);
|
||||
|
||||
this.logger.log(`Transformed payment method:`, {
|
||||
original: pm,
|
||||
transformed,
|
||||
clientId,
|
||||
userId
|
||||
});
|
||||
return transformed;
|
||||
} catch (error) {
|
||||
console.error(`🚨 ERROR transforming payment method:`, error);
|
||||
this.logger.error(`Failed to transform payment method`, {
|
||||
error: getErrorMessage(error),
|
||||
paymentMethod: pm,
|
||||
clientId,
|
||||
userId
|
||||
});
|
||||
return null; // Return null for failed transformations
|
||||
}
|
||||
}).filter(method => method !== null); // Filter out failed transformations
|
||||
|
||||
const result: PaymentMethodList = { paymentMethods: methods, totalCount: methods.length };
|
||||
|
||||
console.log(`🔍 FINAL RESULT for client ${clientId}:`, {
|
||||
totalCount: result.totalCount,
|
||||
hasPaymentMethods: result.totalCount > 0,
|
||||
methods: result.paymentMethods
|
||||
});
|
||||
|
||||
this.logger.log(`Final payment methods result for client ${clientId}:`, {
|
||||
totalCount: result.totalCount,
|
||||
methods: result.paymentMethods,
|
||||
userId
|
||||
});
|
||||
|
||||
await this.cacheService.setPaymentMethods(userId, result);
|
||||
// DISABLE CACHE SAVING for debugging
|
||||
// await this.cacheService.setPaymentMethods(userId, result);
|
||||
console.log(`🔍 RETURNING RESULT WITHOUT CACHING for debugging`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`🚨 ERROR fetching payment methods for client ${clientId}:`, error);
|
||||
this.logger.error(`Failed to fetch payment methods for client ${clientId}`, {
|
||||
error: getErrorMessage(error),
|
||||
userId,
|
||||
|
||||
@ -415,25 +415,33 @@ export class WhmcsDataTransformer {
|
||||
/**
|
||||
* Transform WHMCS payment method to shared PaymentMethod interface
|
||||
*/
|
||||
transformPaymentMethod(whmcsPayMethod: WhmcsPaymentMethod): PaymentMethod {
|
||||
transformPaymentMethod(whmcsPayMethod: any): PaymentMethod {
|
||||
try {
|
||||
console.log(`🔧 TRANSFORMER DEBUG - Input:`, whmcsPayMethod);
|
||||
|
||||
// Handle field name variations between different WHMCS API responses
|
||||
const transformed: PaymentMethod = {
|
||||
id: whmcsPayMethod.id,
|
||||
type: whmcsPayMethod.type,
|
||||
description: whmcsPayMethod.description,
|
||||
description: whmcsPayMethod.description || "",
|
||||
gatewayName: whmcsPayMethod.gateway_name,
|
||||
lastFour: whmcsPayMethod.last_four,
|
||||
expiryDate: whmcsPayMethod.expiry_date,
|
||||
// Handle both possible field names for lastFour
|
||||
lastFour: whmcsPayMethod.last_four || whmcsPayMethod.card_last_four,
|
||||
// Handle both possible field names for expiryDate
|
||||
expiryDate: whmcsPayMethod.expiry_date || whmcsPayMethod.expiry_date,
|
||||
bankName: whmcsPayMethod.bank_name,
|
||||
accountType: whmcsPayMethod.account_type,
|
||||
remoteToken: whmcsPayMethod.remote_token,
|
||||
ccType: whmcsPayMethod.cc_type,
|
||||
cardBrand: whmcsPayMethod.cc_type,
|
||||
billingContactId: whmcsPayMethod.billing_contact_id,
|
||||
createdAt: whmcsPayMethod.created_at,
|
||||
updatedAt: whmcsPayMethod.updated_at,
|
||||
// Handle both possible field names for card type
|
||||
ccType: whmcsPayMethod.cc_type || whmcsPayMethod.card_type,
|
||||
cardBrand: whmcsPayMethod.cc_type || whmcsPayMethod.card_type,
|
||||
billingContactId: whmcsPayMethod.billing_contact_id || whmcsPayMethod.contact_id,
|
||||
createdAt: whmcsPayMethod.created_at || whmcsPayMethod.last_updated,
|
||||
updatedAt: whmcsPayMethod.updated_at || whmcsPayMethod.last_updated,
|
||||
};
|
||||
|
||||
console.log(`🔧 TRANSFORMER DEBUG - Output:`, transformed);
|
||||
|
||||
// Optional validation hook
|
||||
if (!this.validatePaymentMethod(transformed)) {
|
||||
this.logger.warn("Transformed payment method failed validation", {
|
||||
|
||||
7
apps/bff/src/vendors/whmcs/whmcs.service.ts
vendored
7
apps/bff/src/vendors/whmcs/whmcs.service.ts
vendored
@ -218,6 +218,13 @@ export class WhmcsService {
|
||||
return this.paymentService.getPaymentGateways();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate payment methods cache for a user
|
||||
*/
|
||||
async invalidatePaymentMethodsCache(userId: string): Promise<void> {
|
||||
return this.paymentService.invalidatePaymentMethodsCache(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create SSO token with payment method for invoice payment
|
||||
*/
|
||||
|
||||
@ -241,8 +241,16 @@ function CheckoutContent() {
|
||||
};
|
||||
|
||||
const handleAddressConfirmed = (address?: Address) => {
|
||||
console.log("🎯 PARENT: handleAddressConfirmed called with:", address);
|
||||
console.log("🎯 PARENT: Current addressConfirmed state before:", addressConfirmed);
|
||||
setAddressConfirmed(true);
|
||||
setConfirmedAddress(address || null);
|
||||
console.log("🎯 PARENT: addressConfirmed state set to true");
|
||||
|
||||
// Force a log after state update (in next tick)
|
||||
setTimeout(() => {
|
||||
console.log("🎯 PARENT: addressConfirmed state after update:", addressConfirmed);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const handleAddressIncomplete = () => {
|
||||
@ -424,19 +432,20 @@ function CheckoutContent() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Debug Info - Remove in production */}
|
||||
{/* Debug Info - Remove in production */}
|
||||
<div className="bg-gray-100 border rounded-lg p-3 mb-4 text-xs text-gray-600">
|
||||
<strong>Debug Info:</strong> Address Confirmed: {addressConfirmed ? '✅' : '❌'} |
|
||||
<strong>Debug Info:</strong> Address Confirmed: {addressConfirmed ? '✅' : '❌'} ({String(addressConfirmed)}) |
|
||||
Payment Methods: {paymentMethodsLoading ? '⏳ Loading...' : paymentMethodsError ? '❌ Error' : paymentMethods ? `✅ ${paymentMethods.paymentMethods.length} found` : '❌ None'} |
|
||||
Order Items: {checkoutState.orderItems.length} |
|
||||
Can Submit: {!(
|
||||
submitting ||
|
||||
checkoutState.orderItems.length === 0 ||
|
||||
checkoutState.orderItems.length === 0 ||
|
||||
!addressConfirmed ||
|
||||
paymentMethodsLoading ||
|
||||
!paymentMethods ||
|
||||
paymentMethods.paymentMethods.length === 0
|
||||
) ? '✅' : '❌'}
|
||||
) ? '✅' : '❌'} |
|
||||
Render Time: {new Date().toLocaleTimeString()}
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
|
||||
@ -128,9 +128,19 @@ export function AddressConfirmation({
|
||||
};
|
||||
|
||||
const handleConfirmAddress = () => {
|
||||
console.log("🏠 CONFIRM ADDRESS CLICKED", {
|
||||
billingInfo,
|
||||
hasAddress: !!billingInfo?.address,
|
||||
address: billingInfo?.address
|
||||
});
|
||||
|
||||
if (billingInfo?.address) {
|
||||
console.log("🏠 Calling onAddressConfirmed with:", billingInfo.address);
|
||||
onAddressConfirmed(billingInfo.address);
|
||||
setAddressConfirmed(true);
|
||||
console.log("🏠 Address confirmed state set to true");
|
||||
} else {
|
||||
console.log("🏠 No billing info or address available");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user