diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..ab1f416 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..bf016ac --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/sub2apipay.iml b/.idea/sub2apipay.iml new file mode 100644 index 0000000..c956989 --- /dev/null +++ b/.idea/sub2apipay.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..8b3390e --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/__tests__/lib/zpay/client.test.ts b/src/__tests__/lib/zpay/client.test.ts deleted file mode 100644 index 57ecba5..0000000 --- a/src/__tests__/lib/zpay/client.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; - -// Mock config -vi.mock('@/lib/config', () => ({ - getEnv: () => ({ - ZPAY_PID: 'test_pid', - ZPAY_PKEY: 'test_pkey', - ZPAY_API_BASE: 'https://test.zpay.com', - ZPAY_NOTIFY_URL: 'https://test.com/api/zpay/notify', - ZPAY_RETURN_URL: 'https://test.com/pay/result', - }), -})); - -import { createPayment, queryOrder, refund } from '@/lib/zpay/client'; - -describe('ZPAY Client', () => { - beforeEach(() => { - vi.restoreAllMocks(); - }); - - it('createPayment should post to mapi.php and return result', async () => { - const mockResponse = { - code: 1, - trade_no: 'zpay_123', - payurl: 'https://pay.example.com', - qrcode: 'https://qr.example.com', - img: 'https://img.example.com/qr.jpg', - }; - - global.fetch = vi.fn().mockResolvedValue({ - json: () => Promise.resolve(mockResponse), - }); - - const result = await createPayment({ - outTradeNo: 'test_order_1', - amount: '10.00', - paymentType: 'alipay', - clientIp: '127.0.0.1', - productName: 'Test Product', - }); - - expect(result.trade_no).toBe('zpay_123'); - expect(result.payurl).toBe('https://pay.example.com'); - expect(fetch).toHaveBeenCalledWith( - 'https://test.zpay.com/mapi.php', - expect.objectContaining({ method: 'POST' }), - ); - }); - - it('createPayment should throw on error response', async () => { - global.fetch = vi.fn().mockResolvedValue({ - json: () => Promise.resolve({ code: 0, msg: 'insufficient balance' }), - }); - - await expect( - createPayment({ - outTradeNo: 'test_order_2', - amount: '10.00', - paymentType: 'alipay', - clientIp: '127.0.0.1', - productName: 'Test Product', - }), - ).rejects.toThrow('ZPAY create payment failed'); - }); - - it('queryOrder should fetch order status', async () => { - global.fetch = vi.fn().mockResolvedValue({ - json: () => Promise.resolve({ - code: 1, - trade_no: 'zpay_123', - out_trade_no: 'test_order_1', - status: 1, - money: '10.00', - }), - }); - - const result = await queryOrder('test_order_1'); - expect(result.status).toBe(1); - expect(result.money).toBe('10.00'); - }); - - it('refund should post refund request', async () => { - global.fetch = vi.fn().mockResolvedValue({ - json: () => Promise.resolve({ code: 1, msg: '退款成功' }), - }); - - const result = await refund('zpay_123', 'test_order_1', '10.00'); - expect(result.code).toBe(1); - }); -}); diff --git a/src/app/api/zpay/notify/route.ts b/src/app/api/zpay/notify/route.ts index 64168ae..7dc6529 100644 --- a/src/app/api/zpay/notify/route.ts +++ b/src/app/api/zpay/notify/route.ts @@ -1,12 +1,12 @@ import { NextRequest } from 'next/server'; import { handlePaymentNotify } from '@/lib/order/service'; -import type { ZPayNotifyParams } from '@/lib/zpay/types'; +import type { EasyPayNotifyParams } from '@/lib/easy-pay/types'; export async function GET(request: NextRequest) { try { const searchParams = request.nextUrl.searchParams; - const params: ZPayNotifyParams = { + const params: EasyPayNotifyParams = { pid: searchParams.get('pid') || '', name: searchParams.get('name') || '', money: searchParams.get('money') || '', diff --git a/src/lib/zpay/client.ts b/src/lib/zpay/client.ts deleted file mode 100644 index bbf157c..0000000 --- a/src/lib/zpay/client.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { getEnv } from '@/lib/config'; -import { generateSign } from './sign'; -import type { ZPayCreateResponse, ZPayQueryResponse, ZPayRefundResponse } from './types'; - -export interface CreatePaymentOptions { - outTradeNo: string; - amount: string; // 金额字符串,如 "10.00" - paymentType: 'alipay' | 'wxpay'; - clientIp: string; - productName: string; -} - -export async function createPayment(opts: CreatePaymentOptions): Promise { - const env = getEnv(); - const params: Record = { - pid: env.ZPAY_PID, - type: opts.paymentType, - out_trade_no: opts.outTradeNo, - notify_url: env.ZPAY_NOTIFY_URL, - return_url: env.ZPAY_RETURN_URL, - name: opts.productName, - money: opts.amount, - clientip: opts.clientIp, - }; - - const sign = generateSign(params, env.ZPAY_PKEY); - params.sign = sign; - params.sign_type = 'MD5'; - - const formData = new URLSearchParams(params); - const response = await fetch(`${env.ZPAY_API_BASE}/mapi.php`, { - method: 'POST', - body: formData, - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - }); - - const data = await response.json() as ZPayCreateResponse; - if (data.code !== 1) { - throw new Error(`ZPAY create payment failed: ${data.msg || 'unknown error'}`); - } - return data; -} - -export async function queryOrder(outTradeNo: string): Promise { - const env = getEnv(); - const url = `${env.ZPAY_API_BASE}/api.php?act=order&pid=${env.ZPAY_PID}&key=${env.ZPAY_PKEY}&out_trade_no=${outTradeNo}`; - const response = await fetch(url); - const data = await response.json() as ZPayQueryResponse; - if (data.code !== 1) { - throw new Error(`ZPAY query order failed: ${data.msg || 'unknown error'}`); - } - return data; -} - -export async function refund(tradeNo: string, outTradeNo: string, money: string): Promise { - const env = getEnv(); - const params = new URLSearchParams({ - pid: env.ZPAY_PID, - key: env.ZPAY_PKEY, - trade_no: tradeNo, - out_trade_no: outTradeNo, - money, - }); - const response = await fetch(`${env.ZPAY_API_BASE}/api.php?act=refund`, { - method: 'POST', - body: params, - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - }); - const data = await response.json() as ZPayRefundResponse; - if (data.code !== 1) { - throw new Error(`ZPAY refund failed: ${data.msg || 'unknown error'}`); - } - return data; -}