query_yeepay_payment_status
Check the status of Yeepay payments by querying with the merchant order ID to verify transaction details and ensure accurate payment processing.
Instructions
查询支付状态工具
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| orderId | Yes | 商户订单号 |
Implementation Reference
- src/index.ts:67-94 (registration)MCP server registration of the 'query_yeepay_payment_status' tool, defining input schema and thin wrapper handler that calls the core queryYeepayPaymentStatus function.server.tool( "query_yeepay_payment_status", "查询支付状态工具", QueryPaymentStatusInputSchema.shape, // Pass the shape async (input: QueryPaymentStatusInput) => { // Zod schema handles validation try { // Dynamically import the module to avoid circular dependencies const { queryYeepayPaymentStatus } = await import( "./tools/queryPayment.js" ); const queryResult = await queryYeepayPaymentStatus(input); return { content: [ { type: "text" as const, text: JSON.stringify(queryResult, null, 2) }, ], }; } catch (error) { console.error( "Error caught in query_yeepay_payment_status tool handler:", error, ); throw error; // Let SDK handle the error } }, );
- src/tools/queryPayment.ts:31-92 (handler)The core handler logic for querying Yeepay payment status, called by the MCP tool registration. Uses YopClient to make GET request to Yeepay API.export async function queryYeepayPaymentStatus(input: QueryRequest): Promise<YeepayQueryResult> { try { const { parentMerchantNo, merchantNo, appKey, appPrivateKey } = appConfig; const yopConfig: YopConfig = { appKey, appPrivateKey, }; const yopClient = new YopClient(yopConfig); const queryParams = { parentMerchantNo, merchantNo, orderId: input.orderId }; console.info("[QueryPayment] Request Params:", JSON.stringify(queryParams, null, 2)); const apiUrl = '/rest/v1.0/trade/order/query'; // Add double assertion for consistency, similar to the post method usage const responseData = await yopClient.get(apiUrl, queryParams as unknown as Record<string, unknown>) as YeepayQueryResponse; // 使用 SDK 的 get 方法 console.info("[QueryPayment] Raw Response Data:", JSON.stringify(responseData, null, 2)); // 打印原始响应 if (responseData && responseData.state === 'SUCCESS') { if (responseData.result && responseData.result.code === 'OPR00000') { // 成功状态且业务码为 OPR00000 console.info("[QueryPayment] Success:", JSON.stringify(responseData.result)); return responseData.result; } else { // 成功状态但业务码非 OPR00000,表示业务失败 const errorCode = responseData.result?.code || 'UNKNOWN_CODE'; const errorMessage = responseData.result?.message || 'Unknown Yeepay business error message'; const errorLog = `[QueryPayment] Yeepay API Business Error (state: SUCCESS): Code=${errorCode}, Message=${errorMessage}`; console.error(errorLog); throw new Error(`Yeepay Business Error: ${errorCode} - ${errorMessage}`); } } else if (responseData && responseData.state === 'FAILURE') { // Failure state const errorCode = responseData.error?.code || 'UNKNOWN_FAILURE_CODE'; const errorMessage = responseData.error?.message || 'Unknown Yeepay failure message'; const errorLog = `[QueryPayment] Yeepay API Failure (state: FAILURE): Code=${errorCode}, Message=${errorMessage}`; console.error(errorLog); throw new Error(`Yeepay API Failure: ${errorCode} - ${errorMessage}`); } else { // Unknown state or other unexpected response structure const errorLog = `[QueryPayment] Unknown or Unexpected Yeepay API Response State: ${responseData?.state || 'State Undefined'}. Response: ${JSON.stringify(responseData)}`; console.error(errorLog); throw new Error(`Unknown Yeepay API response state: ${responseData?.state}`); } } catch (error: unknown) { // Catch standardized errors from YopClient or other errors within this function console.error("[QueryPayment] Overall Error:", error); // Re-throw the error directly if (error instanceof Error) { throw error; } else { throw new Error(`Unknown error in queryYeepayPaymentStatus: ${String(error)}`); } } }
- src/index.ts:61-65 (schema)Zod schema defining the input parameters for the query_yeepay_payment_status tool (orderId: string).// Define Zod schema for query payment status input const QueryPaymentStatusInputSchema = z.object({ orderId: z.string().describe("商户订单号"), }); type QueryPaymentStatusInput = z.infer<typeof QueryPaymentStatusInputSchema>;
- src/tools/queryPayment.ts:4-92 (schema)TypeScript interfaces defining input (QueryRequest), output (YeepayQueryResult), and internal response structures for type safety.// Expected structure for a successful query result export interface YeepayQueryResult { // Add export code: string; message: string; orderId: string; uniqueOrderNo: string; status: string; // e.g., 'PROCESSING', 'SUCCESS', 'FAILED' } // Expected structure for a query error interface YeepayQueryError { code: string; message: string; } // Complete SDK response structure interface YeepayQueryResponse { state: 'SUCCESS' | 'FAILURE' | string; result?: YeepayQueryResult; error?: YeepayQueryError; } export interface QueryRequest { // Add export orderId: string; } export async function queryYeepayPaymentStatus(input: QueryRequest): Promise<YeepayQueryResult> { try { const { parentMerchantNo, merchantNo, appKey, appPrivateKey } = appConfig; const yopConfig: YopConfig = { appKey, appPrivateKey, }; const yopClient = new YopClient(yopConfig); const queryParams = { parentMerchantNo, merchantNo, orderId: input.orderId }; console.info("[QueryPayment] Request Params:", JSON.stringify(queryParams, null, 2)); const apiUrl = '/rest/v1.0/trade/order/query'; // Add double assertion for consistency, similar to the post method usage const responseData = await yopClient.get(apiUrl, queryParams as unknown as Record<string, unknown>) as YeepayQueryResponse; // 使用 SDK 的 get 方法 console.info("[QueryPayment] Raw Response Data:", JSON.stringify(responseData, null, 2)); // 打印原始响应 if (responseData && responseData.state === 'SUCCESS') { if (responseData.result && responseData.result.code === 'OPR00000') { // 成功状态且业务码为 OPR00000 console.info("[QueryPayment] Success:", JSON.stringify(responseData.result)); return responseData.result; } else { // 成功状态但业务码非 OPR00000,表示业务失败 const errorCode = responseData.result?.code || 'UNKNOWN_CODE'; const errorMessage = responseData.result?.message || 'Unknown Yeepay business error message'; const errorLog = `[QueryPayment] Yeepay API Business Error (state: SUCCESS): Code=${errorCode}, Message=${errorMessage}`; console.error(errorLog); throw new Error(`Yeepay Business Error: ${errorCode} - ${errorMessage}`); } } else if (responseData && responseData.state === 'FAILURE') { // Failure state const errorCode = responseData.error?.code || 'UNKNOWN_FAILURE_CODE'; const errorMessage = responseData.error?.message || 'Unknown Yeepay failure message'; const errorLog = `[QueryPayment] Yeepay API Failure (state: FAILURE): Code=${errorCode}, Message=${errorMessage}`; console.error(errorLog); throw new Error(`Yeepay API Failure: ${errorCode} - ${errorMessage}`); } else { // Unknown state or other unexpected response structure const errorLog = `[QueryPayment] Unknown or Unexpected Yeepay API Response State: ${responseData?.state || 'State Undefined'}. Response: ${JSON.stringify(responseData)}`; console.error(errorLog); throw new Error(`Unknown Yeepay API response state: ${responseData?.state}`); } } catch (error: unknown) { // Catch standardized errors from YopClient or other errors within this function console.error("[QueryPayment] Overall Error:", error); // Re-throw the error directly if (error instanceof Error) { throw error; } else { throw new Error(`Unknown error in queryYeepayPaymentStatus: ${String(error)}`); } } }
- Alternative standalone handler export for a tool runtime, implementing full logic including validation, SDK init with hardcoded creds, API call, and error handling for query_yeepay_payment_status.export async function handler({ input, logger }: Args<Input>): Promise<Output> { // 0. Input Validation try { if (!input || typeof input !== 'object') { throw new Error('Missing or invalid event object.'); } // Required parameters const requiredFields = ['orderId']; const missingFields = requiredFields.filter(key => !input[key]); if (missingFields.length > 0) { throw new Error(`Missing required fields in event object: ${missingFields.join(', ')}`); } } catch (error) { logger.error('Input validation failed:', error.message); return { error: 'INVALID_PARAMETERS', message: error.message, }; } try { // 2. Prepare Request Data const queryParams = { parentMerchantNo: '10086032562', merchantNo: '10086039518', orderId: input.orderId }; logger.debug('Prepared query parameters:', JSON.stringify(queryParams)); // Use dynamic import() for ES modules const sdk = await import('@yeepay/yop-typescript-sdk'); const YopClient = sdk.YopClient; if (!YopClient) { throw new Error('Could not find YopClient in the dynamically imported module'); } logger.info('YopClient loaded from dynamic import'); // Initialize YopClient with config const yopClientInstance = new YopClient({ appKey: 'app_10086032562', appPrivateKey: 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDdnBKx03zrrPzJ/Z8rJMEaYvmes19qIPGcgncUQNOYauaXy99iT2P3O1H3qZceKZ8ngeha5ckuV4ke3tLlMRHn3GvTzd1l6EEntwL6SRUopmhj/635bkGUlQvEZrWAtwfO0wcoI0XnRB3JLc+r8nTf64vIi2UovqcZ6LKJj96btie7rYZZqqtr2+e7S0HDqH6nHcqvBYVGYGrYnDNKyjSvKdjGIq+JMQu1tJOtqT4JoeFAOBSTw3Jqkpvnudc1GgWVOepuGVyaXHXVNQTjnap7LMbJ+IJXBLSgGi1uC4u8Ypc2u0kDLXKkff0X/DG9cJXMaLcf/3yBH2/UoebTTJudAgMBAAECggEACptTfrzlW/9b2wwfT+iSsIFfurORo8n/XnMVIXxH1GH7dvT8VF+B5J2reuvcToaF9lVeqmkYo7XvW3GlTPB4D62qYIkYKW5AHhdBlnqkf11VnkGo0UkwbNzkYwpachZwknrhuw9TI3JMbapaZ/uzEdubhWX8mcJkS5ZqYzCmYjPzKfYMuowZ4ygOETOER9pl8J7dt4CYYI+GLwVT39D6ptf74fzlKohT506ulLUu3AWsavvW3QTPSxzS2ARO7QaLco8Dly8AJiGmSUdwSzzwVgYD1kVHtUUukbtnjFBTN8PqGt+TM+gcv8s5LlaZSYp4Zlwt9LTdW2sFCSoRj8HLaQKBgQD3u6c2PyRckNpwGuOjTJHy+uF7OGoiFyuGAxmyC8UzNG+nLBghZjCJmzkfzKrjNINrNT4zxepXhKurW0vxd9ZSkjpyEteRDSfdyvsDEbfR3p6w9ObA8iZkCvesYchrwrdWO7V4sjynvEhWkLSctLWaASbj7zuyYu0OYiSo28MN+QKBgQDlAUB3mLEpBvWIlMnXhfz/RrmEqlg6yygu37Xjjs7wjyPSz3RqUIB2YYT9d5wGob2nBLD4IvoSWvysNegt0TiklAHYW7LNW1DB1Oo0M5xOgToOOA545aR8DG9XJGOlKRiGJQS0q9T4X4z1TOx93W8bzNeUZgL5Kk5WQE8cuUxzxQKBgQC4nhgWzSeD9E9VjDRo1f9OXLj84yX1Ed9Vl6nmje8AIeuzYaD6AvXZFtyTXitb9x6ZHqykWLIzVqO4p+kIoo4OKvtzV6deabd0CnjV6LZcqNMKfPgaglsp4yKATL7Xz9xhX032DJ43QpGGMYDn56QOiR06cGbEogSX23wGev/5wQKBgQCMQc8FMNzYnu2FAHP675J7mwqG6XnuUH1E8DlLrSyrg0/SjsLjVnjHiITWZQqHuUoZ4DKvV2TIFzgIFWAlp63Ehu32YHtLcTEt9kSXQkDqiBVRnh2nCCdM3qTWv2/UOS5PAp82NMPUd1ky6DE0CYpCgZxLxIrvpmyiQPLzSb48bQKBgAF0EpSRsPQhPjUYsPc3FA71R0GSRyxr9ktM5hqsG/qrh0ep4jIFKibGA+VJo/ed2QC4MNAjPR285v6ytBcFyoEAacf7noSavVvYU5/KaQ5wJYSue0+M5IBJrrwLv0k1ppe86Xp8890NT2XHbaALY3hcSBTGs2aHPUNEma7H+2T9', yopApiBaseUrl: 'https://openapi-a.yeepay.com', yopPublicKey: 'MIIE2TCCA8GgAwIBAgIFQ5cTlZgwDQYJKoZIhvcNAQELBQAwWDELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEXMBUGA1UEAwwOQ0ZDQSBBQ1MgT0NBMzEwHhcNMjEwNDI1MDIwOTAwWhcNMjMwNDI1MDIwOTAwWjCBhzELMAkGA1UEBhMCQ04xFzAVBgNVBAoMDkNGQ0EgQUNTIE9DQTMxMRAwDgYDVQQLDAdURVNUIFJBMRkwFwYDVQQLDBBPcmdhbmlzYXRpb25hbC0xMTIwMAYDVQQDDCkwNTFA5piT5a6d5byA5pS+5bmz5Y+wQDMxMTAwMDAwMDU4MDQyMjlANTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOqdF1o7HGPoLMqikYcPTHi7BJoRXQUYU9npjnJPxdTpsN/GVoScYfZA37OR8xSTK1aM4FPkiRQzjcbPFAdMDCCykZqny3HwpRvTMgjbiZJH5tBxUL9YURnTr2T149wXJLsGuxaxFwUWFISu7yeNGn7prKbYZrHum7OpmcTZ/5gC2dl9O7s5zq63Nq5ONWNh37XbsWcOk+BJrVrjdseAmfIMEsjwFuWc2SS0OrWQ6IwSuBmUwBoZ5924OWwbAZcNvhS5AkAbg7CVbBT4hof2+iv/sxk71slHLvi1I9jHo2EBCwzt4tr0F1Q5O5VYtv03FGHn7yHLLJ87Hwn42qK8bLsCAwEAAaOCAXgwggF0MGwGCCsGAQUFBwEBBGAwXjAoBggrBgEFBQcwAYYcaHR0cDovL29jc3AuY2ZjYS5jb20uY24vb2NzcDAyBggrBgEFBQcwAoYmaHR0cDovL2NybC5jZmNhLmNvbS5jbi9vY2EzMS9vY2EzMS5jZXIwHwYDVR0jBBgwFoAU4rQJy81hoXNKeX/xioML3bR+jB0wDAYDVR0TAQH/BAIwADBIBgNVHSAEQTA/MD0GCGCBHIbvKgEEMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTQuaHRtMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwuY2ZjYS5jb20uY24vb2NhMzEvUlNBL2NybDMwMjAuY3JsMA4GA1UdDwEB/wQEAwIGwDAdBgNVHQ4EFgQU4swobhCzosrPL4Gv8clxRwbHy0EwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQBpZpClbx+FJo5WpuJW+TJKYRayKeAx3/+VvlMyWvdcbABPlvwBY1m3xl1k+tsqqtBGvjathGmw1w7YESdRFTT/ty04MDLmz62USS4DJlZ2EWMxPm0bKpuAPsWb3+EtvizyZ0l1gX/D0YHDcH+VljYlGAv+yQEUzD+0c9NZSWr4V19yRVDQEicll5hJko7RFQUrwW+wNSrexzlyQFbUlbljwAnHO0TF3zgTXKRu2YNiKZGlxr28FjOeMQdvpiNqHCW9ACjQqL0vz1l9IImn0lm+0vh0YhAN0oFzJZvs5lFG9Bg+kNkyhgf9eVcUUxXKnA6UwXq2amoTa4Iq3NW6YuPI' }); logger.info('YopClient initialized successfully'); // 4. Define API URI const apiUri = '/rest/v1.0/trade/order/query'; // 5. API Call const response = await yopClientInstance.get(apiUri, queryParams); logger.debug('API Response:', JSON.stringify(response)); // 6. Result Handling const isProduction = process.env.NODE_ENV === 'production'; // Check env for logging control if (response && response.result) { const resultData = response.result; logger.info('YeePay API query successful.'); const queryResponse = { code: resultData.code, message: resultData.message, orderId: resultData.orderId, uniqueOrderNo: resultData.uniqueOrderNo, status: resultData.status, orderAmount: resultData.orderAmount, payAmount: resultData.payAmount }; logger.debug('Processed successful response:', JSON.stringify(queryResponse)); return queryResponse; } else { logger.error('YeePay API call failed or returned an error state.'); const errorDetails = response ? (response.error || response.result || response) : 'No response object'; logger.error('Error details:', JSON.stringify(errorDetails)); /** @type {YeePayError} */ const errorResponse = { error: response?.error?.code || response?.result?.code || 'YOP_API_ERROR', message: response?.error?.message || response?.result?.message || 'Unknown YeePay API error', subCode: response?.error?.subCode, subMessage: response?.error?.subMessage, rawResponse: !isProduction ? response : undefined, }; return errorResponse; } } catch (error) { logger.error('An unexpected error occurred during YeePay payment status query:', error); if (error.stack) { logger.error('Stack trace:', error.stack); } return { error: 'INTERNAL_SERVER_ERROR', message: error.message || 'An unexpected error occurred.', }; } };