File size: 2,949 Bytes
8268e91
 
 
 
 
73746a8
 
426f2a4
73746a8
 
426f2a4
73746a8
 
 
 
 
 
 
 
426f2a4
73746a8
 
 
426f2a4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73746a8
426f2a4
 
 
73746a8
 
f45e448
 
 
8268e91
 
 
 
73746a8
 
 
 
426f2a4
 
73746a8
426f2a4
 
73746a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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<Order>,
    @InjectRepository(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;
  }
}