123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- <?php
- namespace app\common\Service;
- use app\common\model\ParentOrder;
- use app\common\model\Order;
- use app\common\model\OrderGoods;
- use app\common\model\Address;
- use app\common\model\UserCoupon;
- use app\common\Enum\OrderEnum;
- use app\common\exception\BusinessException;
- use app\common\Service\Order\OrderActionService;
- use app\common\Enum\OrderActionEnum;
- use think\Db;
- use think\Exception;
- /**
- * 父订单服务类
- * 管理父子订单的创建、支付和状态更新
- */
- class ParentOrderService
- {
- /**
- * 创建父子订单 - 一个商品一个子订单,统一支付父订单
- * @param int $addressId 地址ID
- * @param int $userId 用户ID
- * @param array $goodsList 商品列表
- * @param int $userCouponId 优惠券ID
- * @param string $remark 备注
- * @param int $profileId 档案ID
- * @return ParentOrder 返回父订单对象
- * @throws BusinessException
- */
- public static function createParentChildOrders($addressId, $userId, $goodsList, $userCouponId = 0, $remark = '', $profileId = 0)
- {
- // 验证地址
- $address = Address::get($addressId);
- if (!$address || $address['user_id'] != $userId) {
- throw new BusinessException("地址未找到");
- }
- if (empty($goodsList)) {
- throw new BusinessException("商品列表不能为空");
- }
- // 验证商品列表格式
- OrderService::validateGoodsList($goodsList);
- $orderTimeout = ShopConfigService::getConfigs('shop.order.order_timeout', false) ?? 3600;
- $platform = request()->header('platform', 'H5');
- $ip = request()->ip();
-
- // 生成父订单号
- $parentOrderSn = 'P' . date("Ymdhis") . sprintf("%08d", $userId) . mt_rand(1000, 9999);
- $parentOrder = null;
- $childOrders = [];
-
- Db::startTrans();
- try {
- // 先创建所有子订单
- $firstOrder = true;
- foreach ($goodsList as $goodsItem) {
- // 创建子订单
- $childOrder = self::createSingleChildOrder($goodsItem, $userId, $address, $firstOrder ? $userCouponId : 0, $remark, $orderTimeout, $platform, $ip, $profileId);
- $childOrders[] = $childOrder;
- $firstOrder = false;
- }
- // 计算父订单总金额
- $totalAmountData = self::calculateTotalAmount($childOrders);
- // 创建父订单
- $parentOrderInfo = [
- 'parent_order_sn' => $parentOrderSn,
- 'user_id' => $userId,
- 'total_amount' => $totalAmountData['total_amount'],
- 'total_goods_price' => $totalAmountData['total_goods_price'],
- 'total_goods_num' => $totalAmountData['total_goods_num'],
- 'total_express_fee' => $totalAmountData['total_express_fee'],
- 'total_discount_fee' => $totalAmountData['total_discount_fee'],
- 'coupon_discount_fee' => $totalAmountData['coupon_discount_fee'],
- 'promo_discount_fee' => 0,
- 'total_order_amount' => $totalAmountData['total_order_amount'],
- 'pay_amount' => $totalAmountData['pay_amount'],
- 'pay_original_amount' => $totalAmountData['pay_amount'],
- 'pay_remain_amount' => $totalAmountData['pay_amount'],
- 'user_coupon_id' => $userCouponId ?: null,
- 'remark' => $remark,
- 'expire_time' => time() + $orderTimeout,
- 'order_status' => OrderEnum::STATUS_CREATE,
- 'pay_status' => 0,
- 'platform' => $platform,
- 'ip' => $ip,
- 'status' => 'normal',
- ];
- $parentOrder = ParentOrder::create($parentOrderInfo, true);
- // 更新子订单的父订单ID
- foreach ($childOrders as $childOrder) {
- $childOrder->parent_order_id = $parentOrder->id;
- $childOrder->save();
- }
- // 提交事务
- Db::commit();
- // 记录操作
- OrderActionService::recordUserAction(
- $parentOrderSn,
- OrderActionEnum::ACTION_CREATE,
- $userId,
- '创建父订单',
- $userId
- );
- } catch (Exception $e) {
- Db::rollback();
- throw new BusinessException("创建父子订单失败: " . $e->getMessage());
- }
- return $parentOrder;
- }
- /**
- * 创建单个子订单
- * @param array $goodsItem 商品项
- * @param int $userId 用户ID
- * @param object $address 地址对象
- * @param int $userCouponId 优惠券ID
- * @param string $remark 备注
- * @param int $orderTimeout 订单超时时间
- * @param string $platform 平台
- * @param string $ip IP地址
- * @param int $profileId 档案ID
- * @return Order
- */
- protected static function createSingleChildOrder($goodsItem, $userId, $address, $userCouponId, $remark, $orderTimeout, $platform, $ip, $profileId = 0)
- {
- // 构建单商品列表
- $singleGoodsList = [$goodsItem];
-
- // 生成子订单号
- $orderSn = date("Ymdhis") . sprintf("%08d", $userId) . mt_rand(1000, 9999);
- // 子订单信息
- $orderInfo = [
- 'type' => 1,
- 'order_sn' => $orderSn,
- 'user_id' => $userId,
- 'amount' => 0,
- 'goods_price' => 0,
- 'goods_num' => 0,
- 'discount_fee' => 0,
- 'coupon_discount_fee' => 0,
- 'promo_discount_fee' => 0,
- 'order_amount' => 0,
- 'express_fee' => 0,
- 'expire_time' => time() + $orderTimeout,
- 'order_status' => OrderEnum::STATUS_CREATE,
- 'invoice_status' => 0,
- 'remark' => $remark,
- 'user_coupon_id' => $userCouponId > 0 ? $userCouponId : null,
- 'ip' => $ip,
- 'status' => 'normal',
- 'platform' => $platform,
- 'parent_order_id' => null, // 稍后更新
- ];
- // 使用OrderService创建订单
- return OrderService::createOrder($address->id, $userId, $singleGoodsList, $userCouponId, $remark, 0, $profileId);
- }
- /**
- * 计算父订单总金额
- * @param array $childOrders 子订单数组
- * @return array
- */
- protected static function calculateTotalAmount($childOrders)
- {
- $totalAmount = 0;
- $totalGoodsPrice = 0;
- $totalGoodsNum = 0;
- $totalExpressFee = 0;
- $totalDiscountFee = 0;
- $couponDiscountFee = 0;
- foreach ($childOrders as $childOrder) {
- $totalAmount = bcadd($totalAmount, $childOrder->amount, 2);
- $totalGoodsPrice = bcadd($totalGoodsPrice, $childOrder->goods_price, 2);
- $totalGoodsNum += $childOrder->goods_num;
- $totalExpressFee = bcadd($totalExpressFee, $childOrder->express_fee, 2);
- $totalDiscountFee = bcadd($totalDiscountFee, $childOrder->discount_fee, 2);
- $couponDiscountFee = bcadd($couponDiscountFee, $childOrder->coupon_discount_fee, 2);
- }
- return [
- 'total_amount' => $totalAmount,
- 'total_goods_price' => $totalGoodsPrice,
- 'total_goods_num' => $totalGoodsNum,
- 'total_express_fee' => $totalExpressFee,
- 'total_discount_fee' => $totalDiscountFee,
- 'coupon_discount_fee' => $couponDiscountFee,
- 'total_order_amount' => bcadd($totalGoodsPrice, $totalExpressFee, 2),
- 'pay_amount' => $totalAmount
- ];
- }
- /**
- * 获取父订单详情
- * @param int $parentOrderId 父订单ID
- * @param int $userId 用户ID
- * @return ParentOrder|null
- */
- public static function getParentOrderDetail($parentOrderId, $userId = 0)
- {
- $parentOrderModel = new ParentOrder();
- $query = $parentOrderModel->with(['childOrders']);
-
- if ($userId > 0) {
- $query->where('user_id', $userId);
- }
-
- return $query->where('id', $parentOrderId)->find();
- }
- /**
- * 根据父订单号获取详情
- * @param string $parentOrderSn 父订单号
- * @return ParentOrder|null
- */
- public static function getParentOrderByOrderSn($parentOrderSn)
- {
- $parentOrderModel = new ParentOrder();
- return $parentOrderModel->with(['childOrders'])
- ->where('parent_order_sn', $parentOrderSn)
- ->find();
- }
- /**
- * 检查父订单是否可以支付
- * @param ParentOrder $parentOrder 父订单对象
- * @return bool
- */
- public static function canPay($parentOrder)
- {
- return $parentOrder->order_status == OrderEnum::STATUS_CREATE && $parentOrder->pay_status == 0;
- }
- /**
- * 检查父订单是否已支付
- * @param ParentOrder $parentOrder 父订单对象
- * @return bool
- */
- public static function isPaid($parentOrder)
- {
- return $parentOrder->pay_status == 1;
- }
- /**
- * 更新父订单支付状态
- * @param ParentOrder $parentOrder 父订单对象
- * @param int $payStatus 支付状态
- * @param string $payType 支付方式
- * @param string $transactionId 第三方交易号
- * @return bool
- */
- public static function updateParentOrderPayStatus($parentOrder, $payStatus, $payType = '', $transactionId = '')
- {
- $updateData = [
- 'pay_status' => $payStatus,
- 'pay_type' => $payType,
- 'transaction_id' => $transactionId
- ];
-
- if ($payStatus == 1) {
- $updateData['pay_time'] = time();
- $updateData['order_status'] = OrderEnum::STATUS_PAY;
- }
-
- return $parentOrder->save($updateData);
- }
- /**
- * 更新子订单状态
- * @param int $parentOrderId 父订单ID
- * @param int $status 订单状态
- * @return bool
- */
- public static function updateChildOrdersStatus($parentOrderId, $status)
- {
- $orderModel = new Order();
- return $orderModel->where('parent_order_id', $parentOrderId)->update(['order_status' => $status]);
- }
- /**
- * 获取父订单的所有商品
- * @param ParentOrder $parentOrder 父订单对象
- * @return array
- */
- public static function getAllOrderGoods($parentOrder)
- {
- $childOrderIds = [];
- foreach ($parentOrder->childOrders as $childOrder) {
- $childOrderIds[] = $childOrder->id;
- }
-
- if (empty($childOrderIds)) {
- return [];
- }
-
- $orderGoodsModel = new OrderGoods();
- return $orderGoodsModel->where('order_id', 'in', $childOrderIds)->select();
- }
- /**
- * 父订单支付成功后的处理
- * @param string $parentOrderSn 父订单号
- * @param string $payType 支付方式
- * @param string $transactionId 第三方交易号
- * @return bool
- */
- public static function handleParentOrderPaySuccess($parentOrderSn, $payType = '', $transactionId = '')
- {
- $parentOrder = self::getParentOrderByOrderSn($parentOrderSn);
- if (!$parentOrder) {
- throw new BusinessException('父订单不存在');
- }
- if (self::isPaid($parentOrder)) {
- throw new BusinessException('父订单已支付');
- }
- Db::startTrans();
- try {
- // 更新父订单支付状态
- self::updateParentOrderPayStatus($parentOrder, 1, $payType, $transactionId);
- // 更新所有子订单状态为已支付
- self::updateChildOrdersStatus($parentOrder->id, OrderEnum::STATUS_PAY);
- // 记录父订单支付操作
- OrderActionService::recordUserAction(
- $parentOrderSn,
- OrderActionEnum::ACTION_PAY,
- $parentOrder->user_id,
- '父订单支付成功',
- $parentOrder->user_id
- );
- // 记录子订单支付操作
- foreach ($parentOrder->childOrders as $childOrder) {
- OrderActionService::recordUserAction(
- $childOrder->order_sn,
- OrderActionEnum::ACTION_PAY,
- $parentOrder->user_id,
- '子订单支付成功(通过父订单)',
- $parentOrder->user_id
- );
- }
- Db::commit();
- return true;
- } catch (Exception $e) {
- Db::rollback();
- throw new BusinessException('处理父订单支付失败: ' . $e->getMessage());
- }
- }
- /**
- * 取消父订单
- * @param int $parentOrderId 父订单ID
- * @param int $userId 用户ID
- * @return bool
- */
- public static function cancelParentOrder($parentOrderId, $userId)
- {
- $parentOrder = self::getParentOrderDetail($parentOrderId, $userId);
- if (!$parentOrder) {
- throw new BusinessException('父订单不存在');
- }
- if (self::isPaid($parentOrder)) {
- throw new BusinessException('已支付的父订单无法取消');
- }
- Db::startTrans();
- try {
- // 更新父订单状态
- $parentOrder->save(['order_status' => OrderEnum::STATUS_CANCEL]);
- // 更新所有子订单状态
- self::updateChildOrdersStatus($parentOrder->id, OrderEnum::STATUS_CANCEL);
- // 恢复库存
- foreach ($parentOrder->childOrders as $childOrder) {
- OrderGoods::setGoodsStocksInc($childOrder->order_sn);
- }
- // 恢复优惠券
- if ($parentOrder->user_coupon_id) {
- $userCouponModel = new UserCoupon();
- $userCouponModel->where('id', $parentOrder->user_coupon_id)
- ->update(['is_used' => 1]);
- }
- Db::commit();
- return true;
- } catch (Exception $e) {
- Db::rollback();
- throw new BusinessException('取消父订单失败: ' . $e->getMessage());
- }
- }
- /**
- * 获取父订单列表
- * @param int $userId 用户ID
- * @param array $param 查询参数
- * @param array $status 状态筛选
- * @return \think\Paginator
- */
- public static function getParentOrderList($userId = 0, $param = [], $status = [])
- {
- $pageSize = $param['pageSize'] ?? 10;
-
- $parentOrderModel = new ParentOrder();
- $query = $parentOrderModel->with(['childOrders']);
-
- if (!empty($userId)) {
- $query->where('user_id', $userId);
- }
-
- if (!empty($status)) {
- $query->whereIn('order_status', $status);
- }
-
- if (isset($param['keywords']) && $param['keywords'] != '') {
- $query->where('parent_order_sn', 'like', '%' . $param['keywords'] . '%');
- }
-
- return $query->order('createtime desc')
- ->paginate($pageSize, false, ['query' => request()->get()]);
- }
- }
|