import { GenericCrudService } from '../../utils/generic-crud.service'; import { DataSource, Repository } from 'typeorm'; import { Order } from './order.entity'; import { OrderGoods } from './order-goods.entity'; import { Goods } from '../goods/goods.entity'; import { DeliveryAddress } from '../delivery-address/delivery-address.entity'; import type { CreateOrderRequest } from './schemas/create-order.schema'; export class OrderService extends GenericCrudService { private orderGoodsRepository: Repository; private goodsRepository: Repository; private deliveryAddressRepository: Repository; constructor(dataSource: DataSource) { super(dataSource, Order); this.orderGoodsRepository = dataSource.getRepository(OrderGoods); this.goodsRepository = dataSource.getRepository(Goods); this.deliveryAddressRepository = dataSource.getRepository(DeliveryAddress); } /** * 创建订单 * @param data 创建订单请求数据 * @param userId 用户ID * @returns 创建的订单信息 */ async createOrder(data: CreateOrderRequest, userId: number): Promise<{ orderId: number; orderNo: string; amount: number; payAmount: number; }> { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { const { addressId, productOwn, consumeFrom, products } = data; // 验证商品信息并计算总价 let totalAmount = 0; let totalCostAmount = 0; const goodsInfo = []; for (const item of products) { const goods = await this.goodsRepository.findOne({ where: { id: item.id } }); if (!goods) { throw new Error(`商品ID ${item.id} 不存在`); } if (goods.stock < item.num) { throw new Error(`商品 ${goods.name} 库存不足`); } const itemAmount = goods.price * item.num; const itemCostAmount = goods.costPrice * item.num; totalAmount += itemAmount; totalCostAmount += itemCostAmount; goodsInfo.push({ goods, quantity: item.num, amount: itemAmount, costAmount: itemCostAmount }); } // 获取收货地址信息 let deliveryAddress = null; if (addressId) { deliveryAddress = await this.deliveryAddressRepository.findOne({ where: { id: addressId, userId } }); if (!deliveryAddress) { throw new Error('收货地址不存在'); } } // 生成订单号 const orderNo = this.generateOrderNo(); // 创建订单 const order = this.repository.create({ orderNo, userId, amount: totalAmount, costAmount: totalCostAmount, payAmount: totalAmount, // 这里可以根据优惠规则计算实际支付金额 orderType: 1, // 实物订单 payType: consumeFrom === '积分兑换' ? 1 : 2, // 根据消费来源设置支付类型 payState: 0, // 未支付 state: 0, // 未发货 addressId: addressId || 0, merchantId: goodsInfo[0]?.goods.merchantId || 0, supplierId: goodsInfo[0]?.goods.supplierId || 0, createdBy: userId, updatedBy: userId, // 设置收货地址信息(如果提供) ...(deliveryAddress && { receiverMobile: deliveryAddress.phone, recevierName: deliveryAddress.name, recevierProvince: deliveryAddress.receiverProvince, recevierCity: deliveryAddress.receiverCity, recevierDistrict: deliveryAddress.receiverDistrict, recevierTown: deliveryAddress.receiverTown, address: deliveryAddress.address }) }); const savedOrder = await queryRunner.manager.save(order); // 创建订单商品明细 const orderGoodsList = goodsInfo.map(info => ({ orderId: savedOrder.id, orderNo, goodsId: info.goods.id, goodsName: info.goods.name, imageFileId: info.goods.imageFileId, goodsType: info.goods.goodsType, supplierId: info.goods.supplierId, costPrice: info.goods.costPrice, price: info.goods.price, num: info.quantity, freightAmount: 0, state: 0, createdBy: userId, updatedBy: userId })); await queryRunner.manager.save(OrderGoods, orderGoodsList); // 更新商品库存 for (const item of goodsInfo) { await queryRunner.manager.update(Goods, item.goods.id, { stock: () => `stock - ${item.quantity}`, salesNum: () => `sales_num + ${item.quantity}` }); } await queryRunner.commitTransaction(); return { orderId: savedOrder.id, orderNo: savedOrder.orderNo, amount: savedOrder.amount, payAmount: savedOrder.payAmount }; } catch (error) { await queryRunner.rollbackTransaction(); throw error; } finally { await queryRunner.release(); } } /** * 生成订单号 * 格式:年月日时分秒 + 6位随机数 */ private generateOrderNo(): string { const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); const hour = String(now.getHours()).padStart(2, '0'); const minute = String(now.getMinutes()).padStart(2, '0'); const second = String(now.getSeconds()).padStart(2, '0'); const random = String(Math.floor(Math.random() * 1000000)).padStart(6, '0'); return `ORD${year}${month}${day}${hour}${minute}${second}${random}`; } }