import { Injectable, NotFoundException, BadRequestException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Order, OrderStatus, OrderType } from '../entities/order.entity'; import { Course } from '../entities/course.entity'; import { CreateOrderDto } from './dto/create-order.dto'; import { ConfigService } from '../config/config.service'; @Injectable() export class OrdersService { constructor( @InjectRepository(Order) private orderRepository: Repository, @InjectRepository(Course) private courseRepository: Repository, private configService: ConfigService, ) {} async create(userId: number, createOrderDto: CreateOrderDto) { let amount = 0; let orderType = OrderType.PURCHASE; let courseId = null; if (createOrderDto.isVip) { const config = await this.configService.getUiConfig(); amount = config.memberFee || 99; orderType = OrderType.VIP; } else { if (!createOrderDto.courseId) { throw new BadRequestException('Course ID is required for non-VIP orders'); } const course = await this.courseRepository.findOne({ where: { id: createOrderDto.courseId }, }); if (!course) { throw new NotFoundException('Course not found'); } if (!createOrderDto.isDonation && Number(course.price) !== Number(createOrderDto.price)) { throw new BadRequestException('Price mismatch'); } amount = createOrderDto.isDonation ? (createOrderDto.price || 0) : course.price; orderType = createOrderDto.isDonation ? OrderType.DONATION : OrderType.PURCHASE; courseId = course.id; } // Generate simple order number with timestamp to avoid collision under high concurrency const timestamp = Date.now().toString().slice(-6); const orderNo = `${new Date().getFullYear()}${(new Date().getMonth() + 1).toString().padStart(2, '0')}${new Date().getDate().toString().padStart(2, '0')}${timestamp}${Math.floor( Math.random() * 10000, ) .toString() .padStart(4, '0')}`; const order = this.orderRepository.create({ orderNo, userId, courseId, amount, status: OrderStatus.PENDING, orderType, message: createOrderDto.message, }); await this.orderRepository.save(order); return { orderId: order.id, orderNo: order.orderNo, amount: order.amount, }; } async findUserOrders(userId: number) { return this.orderRepository.find({ where: { userId }, relations: ['course'], order: { createdAt: 'DESC' }, }); } async findOne(id: number, userId: number) { const order = await this.orderRepository.findOne({ where: { id, userId }, relations: ['course'], }); if (!order) { throw new NotFoundException('Order not found'); } return order; } }