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();
|
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")
|
@Post("payment-methods/refresh")
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@ApiOperation({
|
@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
|
* 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> {
|
async getPaymentMethods(clientId: number, userId: string): Promise<PaymentMethodList> {
|
||||||
try {
|
try {
|
||||||
// Try cache first
|
// TEMPORARILY BYPASS CACHE for debugging
|
||||||
const cached = await this.cacheService.getPaymentMethods(userId);
|
console.log(`🔍 BYPASSING CACHE for debugging - client ${clientId}, user ${userId}`);
|
||||||
if (cached) {
|
|
||||||
this.logger.debug(`Cache hit for payment methods: user ${userId}`);
|
// COMPLETELY BYPASS CACHE for debugging
|
||||||
return cached;
|
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 });
|
const response = await this.connectionService.getPayMethods({ clientid: clientId });
|
||||||
|
|
||||||
// Debug logging to understand what WHMCS returns
|
// 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}:`, {
|
this.logger.log(`WHMCS GetPayMethods response for client ${clientId}:`, {
|
||||||
rawResponse: response,
|
rawResponse: response,
|
||||||
paymethods: response.paymethods,
|
paymethods: response.paymethods,
|
||||||
@ -40,28 +53,71 @@ export class WhmcsPaymentService {
|
|||||||
userId
|
userId
|
||||||
});
|
});
|
||||||
|
|
||||||
const methods = (response.paymethods?.paymethod || []).map(pm => {
|
// Handle different response structures
|
||||||
const transformed = this.dataTransformer.transformPaymentMethod(pm);
|
// According to WHMCS API docs, GetPayMethods returns { paymethods: [...] } directly
|
||||||
this.logger.log(`Transformed payment method:`, {
|
let paymentMethodsArray: any[] = [];
|
||||||
original: pm,
|
if (response.paymethods) {
|
||||||
transformed,
|
if (Array.isArray(response.paymethods)) {
|
||||||
clientId,
|
// Direct array response (correct for GetPayMethods)
|
||||||
userId
|
paymentMethodsArray = response.paymethods;
|
||||||
});
|
} else if (response.paymethods.paymethod) {
|
||||||
return transformed;
|
// 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 };
|
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}:`, {
|
this.logger.log(`Final payment methods result for client ${clientId}:`, {
|
||||||
totalCount: result.totalCount,
|
totalCount: result.totalCount,
|
||||||
methods: result.paymentMethods,
|
methods: result.paymentMethods,
|
||||||
userId
|
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;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(`🚨 ERROR fetching payment methods for client ${clientId}:`, error);
|
||||||
this.logger.error(`Failed to fetch payment methods for client ${clientId}`, {
|
this.logger.error(`Failed to fetch payment methods for client ${clientId}`, {
|
||||||
error: getErrorMessage(error),
|
error: getErrorMessage(error),
|
||||||
userId,
|
userId,
|
||||||
|
|||||||
@ -415,25 +415,33 @@ export class WhmcsDataTransformer {
|
|||||||
/**
|
/**
|
||||||
* Transform WHMCS payment method to shared PaymentMethod interface
|
* Transform WHMCS payment method to shared PaymentMethod interface
|
||||||
*/
|
*/
|
||||||
transformPaymentMethod(whmcsPayMethod: WhmcsPaymentMethod): PaymentMethod {
|
transformPaymentMethod(whmcsPayMethod: any): PaymentMethod {
|
||||||
try {
|
try {
|
||||||
|
console.log(`🔧 TRANSFORMER DEBUG - Input:`, whmcsPayMethod);
|
||||||
|
|
||||||
|
// Handle field name variations between different WHMCS API responses
|
||||||
const transformed: PaymentMethod = {
|
const transformed: PaymentMethod = {
|
||||||
id: whmcsPayMethod.id,
|
id: whmcsPayMethod.id,
|
||||||
type: whmcsPayMethod.type,
|
type: whmcsPayMethod.type,
|
||||||
description: whmcsPayMethod.description,
|
description: whmcsPayMethod.description || "",
|
||||||
gatewayName: whmcsPayMethod.gateway_name,
|
gatewayName: whmcsPayMethod.gateway_name,
|
||||||
lastFour: whmcsPayMethod.last_four,
|
// Handle both possible field names for lastFour
|
||||||
expiryDate: whmcsPayMethod.expiry_date,
|
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,
|
bankName: whmcsPayMethod.bank_name,
|
||||||
accountType: whmcsPayMethod.account_type,
|
accountType: whmcsPayMethod.account_type,
|
||||||
remoteToken: whmcsPayMethod.remote_token,
|
remoteToken: whmcsPayMethod.remote_token,
|
||||||
ccType: whmcsPayMethod.cc_type,
|
// Handle both possible field names for card type
|
||||||
cardBrand: whmcsPayMethod.cc_type,
|
ccType: whmcsPayMethod.cc_type || whmcsPayMethod.card_type,
|
||||||
billingContactId: whmcsPayMethod.billing_contact_id,
|
cardBrand: whmcsPayMethod.cc_type || whmcsPayMethod.card_type,
|
||||||
createdAt: whmcsPayMethod.created_at,
|
billingContactId: whmcsPayMethod.billing_contact_id || whmcsPayMethod.contact_id,
|
||||||
updatedAt: whmcsPayMethod.updated_at,
|
createdAt: whmcsPayMethod.created_at || whmcsPayMethod.last_updated,
|
||||||
|
updatedAt: whmcsPayMethod.updated_at || whmcsPayMethod.last_updated,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(`🔧 TRANSFORMER DEBUG - Output:`, transformed);
|
||||||
|
|
||||||
// Optional validation hook
|
// Optional validation hook
|
||||||
if (!this.validatePaymentMethod(transformed)) {
|
if (!this.validatePaymentMethod(transformed)) {
|
||||||
this.logger.warn("Transformed payment method failed validation", {
|
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();
|
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
|
* Create SSO token with payment method for invoice payment
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -241,8 +241,16 @@ function CheckoutContent() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleAddressConfirmed = (address?: Address) => {
|
const handleAddressConfirmed = (address?: Address) => {
|
||||||
|
console.log("🎯 PARENT: handleAddressConfirmed called with:", address);
|
||||||
|
console.log("🎯 PARENT: Current addressConfirmed state before:", addressConfirmed);
|
||||||
setAddressConfirmed(true);
|
setAddressConfirmed(true);
|
||||||
setConfirmedAddress(address || null);
|
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 = () => {
|
const handleAddressIncomplete = () => {
|
||||||
@ -424,19 +432,20 @@ function CheckoutContent() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</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">
|
<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'} |
|
Payment Methods: {paymentMethodsLoading ? '⏳ Loading...' : paymentMethodsError ? '❌ Error' : paymentMethods ? `✅ ${paymentMethods.paymentMethods.length} found` : '❌ None'} |
|
||||||
Order Items: {checkoutState.orderItems.length} |
|
Order Items: {checkoutState.orderItems.length} |
|
||||||
Can Submit: {!(
|
Can Submit: {!(
|
||||||
submitting ||
|
submitting ||
|
||||||
checkoutState.orderItems.length === 0 ||
|
checkoutState.orderItems.length === 0 ||
|
||||||
!addressConfirmed ||
|
!addressConfirmed ||
|
||||||
paymentMethodsLoading ||
|
paymentMethodsLoading ||
|
||||||
!paymentMethods ||
|
!paymentMethods ||
|
||||||
paymentMethods.paymentMethods.length === 0
|
paymentMethods.paymentMethods.length === 0
|
||||||
) ? '✅' : '❌'}
|
) ? '✅' : '❌'} |
|
||||||
|
Render Time: {new Date().toLocaleTimeString()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
|
|||||||
@ -128,9 +128,19 @@ export function AddressConfirmation({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleConfirmAddress = () => {
|
const handleConfirmAddress = () => {
|
||||||
|
console.log("🏠 CONFIRM ADDRESS CLICKED", {
|
||||||
|
billingInfo,
|
||||||
|
hasAddress: !!billingInfo?.address,
|
||||||
|
address: billingInfo?.address
|
||||||
|
});
|
||||||
|
|
||||||
if (billingInfo?.address) {
|
if (billingInfo?.address) {
|
||||||
|
console.log("🏠 Calling onAddressConfirmed with:", billingInfo.address);
|
||||||
onAddressConfirmed(billingInfo.address);
|
onAddressConfirmed(billingInfo.address);
|
||||||
setAddressConfirmed(true);
|
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