Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af9820a2ee | ||
|
|
a3f3fa83f1 | ||
|
|
2590145a2c | ||
|
|
e2018cbcf9 | ||
|
|
a1d3f3b639 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -42,3 +42,6 @@ next-env.d.ts
|
||||
|
||||
# third-party source code (local reference only)
|
||||
/third-party
|
||||
|
||||
# Claude Code project instructions (contains sensitive deployment info)
|
||||
CLAUDE.md
|
||||
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025-present touwaeriol
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -193,7 +193,7 @@ describe('Payment Flow - PC/Mobile, QR/Redirect', () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('EasyPay does not use isMobile flag itself (delegates to frontend)', async () => {
|
||||
it('EasyPay forwards isMobile to client for device=jump on mobile', async () => {
|
||||
mockEasyPayCreatePayment.mockResolvedValue({
|
||||
code: 1,
|
||||
trade_no: 'EP-003',
|
||||
@@ -212,16 +212,14 @@ describe('Payment Flow - PC/Mobile, QR/Redirect', () => {
|
||||
|
||||
await provider.createPayment(request);
|
||||
|
||||
// EasyPay client is called the same way regardless of isMobile
|
||||
// EasyPay client receives isMobile so it can set device=jump
|
||||
expect(mockEasyPayCreatePayment).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
outTradeNo: 'order-ep-003',
|
||||
paymentType: 'alipay',
|
||||
isMobile: true,
|
||||
}),
|
||||
);
|
||||
// No isMobile parameter forwarded to the underlying client
|
||||
const callArgs = mockEasyPayCreatePayment.mock.calls[0][0];
|
||||
expect(callArgs).not.toHaveProperty('isMobile');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,19 +3,17 @@ import { z } from 'zod';
|
||||
import { verifyAdminToken, unauthorizedResponse } from '@/lib/admin-auth';
|
||||
import { prisma } from '@/lib/db';
|
||||
|
||||
const updateChannelSchema = z
|
||||
.object({
|
||||
group_id: z.number().int().positive().optional(),
|
||||
name: z.string().min(1).max(100).optional(),
|
||||
platform: z.string().min(1).max(50).optional(),
|
||||
rate_multiplier: z.number().positive().optional(),
|
||||
description: z.string().max(500).nullable().optional(),
|
||||
models: z.array(z.string()).nullable().optional(),
|
||||
features: z.record(z.string(), z.unknown()).nullable().optional(),
|
||||
sort_order: z.number().int().min(0).optional(),
|
||||
enabled: z.boolean().optional(),
|
||||
})
|
||||
.strict();
|
||||
const updateChannelSchema = z.object({
|
||||
group_id: z.number().int().positive().optional(),
|
||||
name: z.string().min(1).max(100).optional(),
|
||||
platform: z.string().min(1).max(50).optional(),
|
||||
rate_multiplier: z.number().positive().optional(),
|
||||
description: z.string().max(500).nullable().optional(),
|
||||
models: z.union([z.array(z.string()), z.string()]).nullable().optional(),
|
||||
features: z.union([z.record(z.string(), z.unknown()), z.string()]).nullable().optional(),
|
||||
sort_order: z.number().int().min(0).optional(),
|
||||
enabled: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
if (!(await verifyAdminToken(request))) return unauthorizedResponse(request);
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface CreatePaymentOptions {
|
||||
clientIp: string;
|
||||
productName: string;
|
||||
returnUrl?: string;
|
||||
isMobile?: boolean;
|
||||
}
|
||||
|
||||
function normalizeCidList(cid?: string): string | undefined {
|
||||
@@ -68,6 +69,10 @@ export async function createPayment(opts: CreatePaymentOptions): Promise<EasyPay
|
||||
params.cid = cid;
|
||||
}
|
||||
|
||||
if (opts.isMobile) {
|
||||
params.device = 'mobile';
|
||||
}
|
||||
|
||||
const sign = generateSign(params, env.EASY_PAY_PKEY);
|
||||
params.sign = sign;
|
||||
params.sign_type = 'MD5';
|
||||
|
||||
@@ -29,11 +29,12 @@ export class EasyPayProvider implements PaymentProvider {
|
||||
clientIp: request.clientIp || '127.0.0.1',
|
||||
productName: request.subject,
|
||||
returnUrl: request.returnUrl,
|
||||
isMobile: request.isMobile,
|
||||
});
|
||||
|
||||
return {
|
||||
tradeNo: result.trade_no,
|
||||
payUrl: result.payurl,
|
||||
payUrl: (request.isMobile && result.payurl2) || result.payurl,
|
||||
qrCode: result.qrcode,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface EasyPayCreateResponse {
|
||||
trade_no: string;
|
||||
O_id?: string;
|
||||
payurl?: string;
|
||||
payurl2?: string;
|
||||
qrcode?: string;
|
||||
img?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user