89 lines
2.8 KiB
TypeScript
89 lines
2.8 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { OrderEntity } from '../../../domain/entities/order.entity';
|
|
|
|
export interface StripePaymentResult {
|
|
paymentUrl: string;
|
|
sessionId: string;
|
|
}
|
|
|
|
export interface StripeCallbackResult {
|
|
orderId: string;
|
|
transactionId: string;
|
|
success: boolean;
|
|
}
|
|
|
|
@Injectable()
|
|
export class StripeAdapter {
|
|
constructor(private configService: ConfigService) {}
|
|
|
|
/**
|
|
* Create Stripe checkout session
|
|
*/
|
|
async createPayment(order: OrderEntity): Promise<StripePaymentResult> {
|
|
// In production, use Stripe SDK
|
|
// const stripe = new Stripe(this.configService.get('STRIPE_SECRET_KEY'));
|
|
//
|
|
// const session = await stripe.checkout.sessions.create({
|
|
// payment_method_types: ['card'],
|
|
// line_items: [
|
|
// {
|
|
// price_data: {
|
|
// currency: 'cny',
|
|
// product_data: {
|
|
// name: `iConsulting - ${order.serviceType}`,
|
|
// description: `${order.serviceCategory} 移民评估服务`,
|
|
// },
|
|
// unit_amount: Math.round(order.amount * 100),
|
|
// },
|
|
// quantity: 1,
|
|
// },
|
|
// ],
|
|
// mode: 'payment',
|
|
// success_url: `${this.configService.get('WEB_CLIENT_URL')}/payment/success?order=${order.id}`,
|
|
// cancel_url: `${this.configService.get('WEB_CLIENT_URL')}/payment/cancel?order=${order.id}`,
|
|
// metadata: {
|
|
// orderId: order.id,
|
|
// },
|
|
// });
|
|
|
|
// For development, return mock URL
|
|
const mockSessionId = `cs_mock_${Date.now()}`;
|
|
const webClientUrl = this.configService.get('WEB_CLIENT_URL') || 'http://localhost:5173';
|
|
const mockPaymentUrl = `${webClientUrl}/payment/mock?session=${mockSessionId}&order=${order.id}`;
|
|
|
|
console.log(`[Stripe] Created checkout session for order ${order.id}, amount: ${order.amount}`);
|
|
|
|
return {
|
|
paymentUrl: mockPaymentUrl,
|
|
sessionId: mockSessionId,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Handle Stripe webhook
|
|
*/
|
|
async handleCallback(payload: Record<string, unknown>): Promise<StripeCallbackResult> {
|
|
// In production:
|
|
// 1. Verify webhook signature using STRIPE_WEBHOOK_SECRET
|
|
// 2. Parse the event
|
|
// 3. Handle checkout.session.completed event
|
|
|
|
const eventType = payload.type as string;
|
|
const data = payload.data as Record<string, unknown> | undefined;
|
|
const object = data?.object as Record<string, unknown> | undefined;
|
|
|
|
const metadata = object?.metadata as Record<string, string> | undefined;
|
|
const orderId = metadata?.orderId || (payload.orderId as string);
|
|
const transactionId = (object?.payment_intent as string) || `pi_${Date.now()}`;
|
|
|
|
console.log(`[Stripe] Webhook received: ${eventType} for order ${orderId}`);
|
|
|
|
return {
|
|
orderId,
|
|
transactionId,
|
|
success: eventType === 'checkout.session.completed',
|
|
};
|
|
}
|
|
}
|