Spaces:
Sleeping
Sleeping
| 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'; | |
| () | |
| export class OrdersService { | |
| constructor( | |
| (Order) | |
| private orderRepository: Repository<Order>, | |
| (Course) | |
| private courseRepository: Repository<Course>, | |
| 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; | |
| } | |
| } | |