12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097 |
- <?php
- namespace app\common\Service;
- use app\common\Enum\GoodsEnum;
- use app\common\model\Order;
- use app\common\model\OrderGoods;
- use app\common\model\Address;
- use app\common\model\UserCoupon;
- use app\common\model\Goods;
- use app\common\model\Sku;
- use app\common\model\Freight;
- use think\Db;
- use think\Exception;
- use app\common\model\OrderAddress;
- use app\common\Enum\OrderEnum;
- use app\common\exception\BusinessException;
- use app\common\Service\Order\OrderActionService;
- use app\common\Enum\OrderActionEnum;
- use app\common\Service\SkuSpec;
- use app\common\Service\ParentOrderService;
- /**
- * 订单服务类
- * 封装订单创建相关逻辑
- *
- * 新增功能:
- * - createSingleGoodsOrders(): 创建单商品订单,一个商品一个订单
- *
- * 使用示例:
- *
- * // 创建单商品订单(一个商品一个订单)
- * $goodsList = [
- * ['goods_id' => 1, 'goods_sku_id' => 10, 'nums' => 2],
- * ['goods_id' => 2, 'goods_sku_id' => 20, 'nums' => 1],
- * ['goods_id' => 3, 'goods_sku_id' => 30, 'nums' => 3]
- * ];
- * $orders = OrderService::createSingleGoodsOrders($addressId, $userId, $goodsList, $userCouponId, $remark);
- * // 返回3个订单对象的数组,每个商品对应一个订单
- *
- * // 创建传统订单(多商品合并为一个订单)
- * $order = OrderService::createOrder($addressId, $userId, $goodsList, $userCouponId, $remark);
- * // 返回1个包含所有商品的订单对象
- */
- class OrderService
- {
- /**
- * 根据商品列表计算订单明细
- * @param array $orderInfo 订单基础信息
- * @param array $goods_list 商品列表
- * @param int $user_id 用户ID
- * @param int $area_id 地区ID
- * @param int $user_coupon_id 优惠券ID
- * @return array
- * @throws
- */
- protected static function computeGoods(&$orderInfo, $goodsList, $userId, $areaId, $userCouponId = 0)
- {
- $config = get_addon_config('shop');
- $orderInfo['amount'] = 0;
- $orderInfo['goods_price'] = 0;
- $orderInfo['goods_num'] = 0;
- $orderInfo['express_fee'] = 0;
- $orderInfo['discount_fee'] = 0;
- $orderInfo['coupon_discount_fee'] = 0;
- $orderInfo['order_amount'] = 0;
- $orderItem = [];
- $shippingTemp = [];
- $userCoupon = null;
- $processedGoodsList = []; // 处理后的商品列表,避免与参数$goodsList冲突
- // 校验优惠券
- if ($userCouponId) {
- $userCouponModel = new UserCoupon();
- $userCoupon = $userCouponModel->checkUserOrUse($userCouponId, $userId);
- $orderInfo['user_coupon_id'] = $userCouponId;
- }
- // 提取所有商品ID和SKU ID,进行批量查询
- $goodsIds = array_column($goodsList, 'goods_id');
- $skuIds = [];
- foreach ($goodsList as $index => $item) {
- if (isset($item['goods_sku_id']) && $item['goods_sku_id'] > 0) {
- $skuIds[] = $item['goods_sku_id'];
- }
- }
- // 批量查询商品信息
- $goodsData = [];
- if (!empty($goodsIds)) {
- $goodsModel = new Goods();
- $goodsCollection = $goodsModel->with(['brand'])
- ->where('id', 'in', $goodsIds)
- ->where('status', GoodsEnum::STATUS_ON_SALE)
- ->select();
- foreach ($goodsCollection as $goods) {
- $goodsData[$goods->id] = $goods;
- }
- }
- // 批量查询SKU信息
- $skuData = [];
- $multiSpecSkuIds = []; // 用于存储多规格商品的SKU ID
- if (!empty($skuIds)) {
- $skuModel = new Sku();
- $skuCollection = $skuModel->where('id', 'in', $skuIds)->select();
- foreach ($skuCollection as $sku) {
- $skuData[$sku->id] = $sku;
- // 过滤出有规格值的SKU ID(spec_value_ids不为空)
- if (!empty($sku->spec_value_ids)) {
- $multiSpecSkuIds[] = $sku->id;
- }
- }
- }
- // 批量查询规格属性字符串(只查询多规格商品的SKU)
- $skuAttrData = [];
- if (!empty($multiSpecSkuIds)) {
- $skuAttrData = SkuSpec::getSkuAttrs($multiSpecSkuIds);
- }
- // 验证并构建商品数据
- foreach ($goodsList as $item) {
- $goods_id = $item['goods_id'];
- $goods_sku_id = $item['goods_sku_id']; // 现在所有商品都应该有SKU ID
- $nums = $item['nums'];
- if ($nums <= 0) {
- throw new BusinessException("商品数量必须大于0");
- }
- // 检查商品是否存在
- if (!isset($goodsData[$goods_id])) {
- throw new BusinessException("商品已下架");
- }
- $goods = $goodsData[$goods_id];
- // 所有商品都必须有SKU(包括单规格商品的默认SKU)
- if (empty($skuData) || !isset($skuData[$goods_sku_id])) {
- throw new BusinessException("商品规格不存在");
- }
- $sku = $skuData[$goods_sku_id];
-
- // 验证SKU是否属于该商品
- if ($sku->goods_id != $goods_id) {
- throw new BusinessException("商品规格不匹配");
- }
-
- // 获取规格属性字符串(单规格商品的sku_attr为空)
- $sku_attr = $skuAttrData[$goods_sku_id] ?? '';
- // 构建商品对象,模拟购物车数据结构
- $goodsItem = (object)[
- 'goods_id' => $goods_id,
- 'goods_sku_id' => $goods_sku_id,
- 'nums' => $nums,
- 'goods' => $goods,
- 'sku' => $sku,
- 'sku_attr' => $sku_attr
- ];
- $processedGoodsList[] = $goodsItem;
- }
-
- // 计算商品价格和运费(统一使用SKU进行计算)
- foreach ($processedGoodsList as $item) {
- $goodsItemData = [];
-
- if (empty($item->goods) || empty($item->sku)) {
- throw new BusinessException("商品已下架");
- }
-
- // 库存验证(统一使用SKU库存)
- if ($item->sku->stocks < $item->nums) {
- throw new BusinessException("商品库存不足,请重新修改数量");
- }
-
- // 统一使用SKU数据进行计算
- $goodsItemData['image'] = !empty($item->sku->image) ? $item->sku->image : $item->goods->image;
- $goodsItemData['price'] = $item->sku->price;
- // $goodsItemData['lineation_price'] = $item->sku->lineation_price;
- $goodsItemData['sku_sn'] = $item->sku->sku_sn;
- $amount = bcmul($item->sku->price, $item->nums, 2);
-
- $goodsItemData['amount'] = $amount;
- // 订单应付金额
- $orderInfo['amount'] = bcadd($orderInfo['amount'], $amount, 2);
- // 商品总价
- $orderInfo['goods_price'] = bcadd($orderInfo['goods_price'], $amount, 2);
- // 商品数量累计
- $orderInfo['goods_num'] += $item->nums;
- $freight_id = $item->goods->express_template_id;
- // 计算邮费【合并运费模板】
- if (!isset($shippingTemp[$freight_id])) {
- $shippingTemp[$freight_id] = [
- 'nums' => $item->nums,
- 'weight' => $item->sku->weight,
- 'amount' => $amount
- ];
- } else {
- $shippingTemp[$freight_id] = [
- 'nums' => bcadd($shippingTemp[$freight_id]['nums'], $item->nums, 2),
- 'weight' => bcadd($shippingTemp[$freight_id]['weight'], $item->sku->weight, 2),
- 'amount' => bcadd($shippingTemp[$freight_id]['amount'], $amount, 2)
- ];
- }
-
- // 创建订单商品数据 (基于正确的表结构)
- $orderItemData = [
- 'user_id' => $userId,
- 'order_sn' => '', // 将在订单创建后补充
- 'goods_sn' => $item->goods->goods_sn ?: '', // 商品货号
- 'sku_sn' => $item->sku->sku_sn ?: '', // SKU编号
- 'goods_type' => $item->goods->type ?: 0, // 商品类型
- 'goods_id' => $item->goods->id,
- 'goods_sku_attr' => $item->sku->sku_attr,
- 'goods_spec_value_ids' => $item->sku->spec_value_ids,
- 'goods_sku_id' => $item->sku->id,
- 'goods_title' => $item->goods->title,
- 'goods_market_price' => $item->sku->market_price ?: 0, // 市场价
- 'goods_original_price' => $item->sku->price, // 商城售价
- 'goods_price' => $amount, // 实付金额
- 'goods_image' => $goodsItemData['image'],
- 'goods_weight' => $item->sku->weight ?: 0,
- 'nums' => $item->nums,
- 'sale_status' => 0, // 销售状态:0=待申请
- 'comment_status' => 0, // 评论状态:0=未评论
- 'status' => 1, // 状态
- 'supplier_id' => $item->goods->supplier_id,
- 'inspection_type_id' => $item->goods->inspection_type_id,
- ];
-
- $orderItem[] = $orderItemData;
- }
-
- // 按运费模板计算
- foreach ($shippingTemp as $key => $item) {
- $shippingfee = Freight::calculate($key, $areaId, $item['nums'], $item['weight'], $item['amount']);
- $orderInfo['express_fee'] = bcadd($orderInfo['express_fee'], $shippingfee, 2);
- }
- // 订单金额(商品价格+运费)
- $orderInfo['order_amount'] = bcadd($orderInfo['goods_price'], $orderInfo['express_fee'], 2);
- // 订单应付金额(暂时等于订单金额,后续会减去优惠)
- $orderInfo['amount'] = $orderInfo['order_amount'];
- // if (!empty($userCoupon)) {
- // // 校验优惠券
- // $goods_ids = array_column($orderItem, 'goods_id');
- // $category_ids = array_column($orderItem, 'category_id');
- // $brand_ids = array_column($orderItem, 'brand_id');
- // $couponModel = new Coupon();
- // $coupon = $couponModel->getCoupon($userCoupon['coupon_id'])
- // ->checkCoupon()
- // ->checkOpen()
- // ->checkUseTime($userCoupon['createtime'])
- // ->checkConditionGoods($goods_ids, $userId, $category_ids, $brand_ids);
- // // 计算折扣金额,判断是使用不含运费,还是含运费的金额
- // $amount = !isset($config['shippingfeecoupon']) || $config['shippingfeecoupon'] == 0 ? $orderInfo['goods_price'] : $orderInfo['order_amount'];
- // list($new_money, $coupon_money) = $coupon->doBuy($amount);
- // // 判断优惠金额是否超出总价,超出则直接设定优惠金额为总价
- // $orderInfo['coupon_discount_fee'] = $coupon_money > $amount ? $amount : $coupon_money;
- // $orderInfo['discount_fee'] = $orderInfo['coupon_discount_fee'];
- // }
- // 计算最终应付金额【订单金额减去折扣】
- $orderInfo['amount'] = max(0, bcsub($orderInfo['order_amount'], $orderInfo['discount_fee'], 2));
- $orderInfo['pay_amount'] = $orderInfo['amount']; // 实际付款金额等于应付金额
- $orderInfo['discount_fee'] = bcadd($orderInfo['discount_fee'], 0, 2);
- return [
- $orderItem,
- $processedGoodsList,
- $userCoupon
- ];
- }
-
- /**
- * 统一的创建订单方法
- * @param int $address_id 地址ID
- * @param int $user_id 用户ID
- * @param array $goods_list 标准化的商品列表
- * @param int $user_coupon_id 优惠券ID
- * @param string $memo 备注
- * @param array $cart_ids 购物车ID数组(如果是购物车模式需要清空)
- * @return Order
- * @throws BusinessException
- */
- public static function createOrder($addressId, $userId, $goodsList, $userCouponId = 0, $remark = '',$supplierId = 0)
- {
- $address = Address::get($addressId);
- if (!$address || $address['user_id'] != $userId) {
- throw new BusinessException("地址未找到");
- }
- if (empty($goodsList)) {
- throw new BusinessException("商品列表不能为空");
- }
- $orderTimeout = ShopConfigService::getConfigs('shop.order.order_timeout',false) ?? 3600;
- $orderSn = date("Ymdhis") . sprintf("%08d", $userId) . mt_rand(1000, 9999);
- // 订单主表信息 (基于新表结构)
- $orderInfo = [
- 'type' => 1, // 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 ?: null,
- 'ip' => request()->ip(), // IP地址
- 'status' => 'normal',
- ];
- $orderInfo['platform'] = request()->header('platform', 'H5');
- // 通过商品列表计算订单明细
- list($orderItem, $calculatedGoodsList, $userCoupon) = self::computeGoods($orderInfo, $goodsList, $userId, $address->area_id, $userCouponId);
- $orderInfo['pay_amount'] = bcsub($orderInfo['order_amount'], $orderInfo['discount_fee'], 2);
- $orderInfo['pay_original_amount'] = $orderInfo['pay_amount'];
- $orderInfo['pay_remain_amount'] = $orderInfo['pay_amount'];
-
- // 创建订单
- $order = self::createOrderWithTransaction($orderInfo, $orderItem, $calculatedGoodsList, $userCoupon, $address);
-
- return $order;
- }
- /**
- * 创建单商品订单 - 一个商品一个订单
- * @param int $addressId 地址ID
- * @param int $userId 用户ID
- * @param array $goodsList 商品列表(支持多商品但会拆分为多个订单)
- * @param int $userCouponId 优惠券ID(仅用于第一个订单)
- * @param string $remark 备注
- * @return array 返回创建的订单数组
- * @throws BusinessException
- */
- public static function createSingleGoodsOrders($addressId, $userId, $goodsList, $userCouponId = 0, $remark = '')
- {
- // 验证地址
- $address = Address::get($addressId);
- if (!$address || $address['user_id'] != $userId) {
- throw new BusinessException("地址未找到");
- }
- if (empty($goodsList)) {
- throw new BusinessException("商品列表不能为空");
- }
- // 验证商品列表格式
- self::validateGoodsList($goodsList);
- $orderTimeout = ShopConfigService::getConfigs('shop.order.order_timeout', false) ?? 3600;
- $platform = request()->header('platform', 'H5');
- $ip = request()->ip();
- $orders = [];
- $firstOrder = true;
- // 为每个商品创建单独的订单
- foreach ($goodsList as $goodsItem) {
- // 构建单商品列表
- $singleGoodsList = [$goodsItem];
-
- // 生成订单号
- $orderSn = date("Ymdhis") . sprintf("%08d", $userId) . mt_rand(1000, 9999);
- // 订单主表信息
- $orderInfo = [
- 'type' => 1, // 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' => $firstOrder && $userCouponId > 0 ? $userCouponId : null, // 优惠券仅用于第一个订单
- 'ip' => $ip,
- 'status' => 'normal',
- 'platform' => $platform,
- ];
- try {
- // 通过单商品列表计算订单明细
- list($orderItem, $calculatedGoodsList, $userCoupon) = self::computeGoods(
- $orderInfo,
- $singleGoodsList,
- $userId,
- $address->area_id,
- $firstOrder && $userCouponId > 0 ? $userCouponId : 0
- );
- $orderInfo['pay_amount'] = bcsub($orderInfo['order_amount'], $orderInfo['discount_fee'], 2);
- $orderInfo['pay_original_amount'] = $orderInfo['pay_amount'];
- $orderInfo['pay_remain_amount'] = $orderInfo['pay_amount'];
- // 创建订单
- $order = self::createOrderWithTransaction($orderInfo, $orderItem, $calculatedGoodsList, $userCoupon, $address);
- $orders[] = $order;
- // 第一个订单创建完成后,后续订单不再使用优惠券
- $firstOrder = false;
- } catch (Exception $e) {
- // 如果某个订单创建失败,记录错误并继续创建其他订单
- \think\Log::error("创建单商品订单失败: " . $e->getMessage() . ", 商品ID: " . $goodsItem['goods_id']);
- throw new BusinessException("创建订单失败: " . $e->getMessage());
- }
- }
- if (empty($orders)) {
- throw new BusinessException("所有订单创建失败");
- }
- return $orders;
- }
- /**
- * 在事务中创建订单
- * @param array $orderInfo 订单信息
- * @param array $orderItem 订单商品列表
- * @param array $goodsList 商品列表
- * @param object $userCoupon 优惠券
- * @param object $address 地址信息
- * @return Order
- * @throws BusinessException
- */
- protected static function createOrderWithTransaction($orderInfo, $orderItem, $goodsList, $userCoupon, $address)
- {
- $order = null;
- Db::startTrans();
- try {
- // 创建订单
- $order = Order::create($orderInfo, true);
-
- // 为每个订单商品添加订单ID和订单号
- foreach ($orderItem as &$item) {
- $item['order_id'] = $order->id;
- $item['order_sn'] = $order->order_sn;
- // 移除临时字段
- unset($item['category_id'], $item['brand_id']);
- }
- unset($item);
- // 创建订单地址信息
- $orderAddressData = [
- 'order_id' => $order->id,
- 'user_id' => $orderInfo['user_id'],
- 'consignee' => $address->receiver,
- 'mobile' => $address->mobile,
- 'province_name' => $address->province->name ?? '',
- 'city_name' => $address->city->name ?? '',
- 'district_name' => $address->area->name ?? '',
- 'address' => $address->address,
- 'province_id' => $address->province_id,
- 'city_id' => $address->city_id,
- 'district_id' => $address->area_id,
- ];
- OrderAddress::create($orderAddressData);
-
- // 减库存
- foreach ($goodsList as $index => $item) {
- if ($item->sku) {
- $item->sku->setDec('stocks', $item->nums);
- }
- $item->goods->setDec("stocks", $item->nums);
- }
-
- // 计算单个商品折扣后的价格 (基于新字段名)
- $saleamount = bcsub($order['amount'], $order['express_fee'], 2);
- $saleratio = $order['goods_price'] > 0 ? bcdiv($saleamount, $order['goods_price'], 10) : 1;
- $saleremains = $saleamount;
-
- foreach ($orderItem as $index => &$item) {
- if (!isset($orderItem[$index + 1])) {
- $saleprice = $saleremains;
- } else {
- $saleprice = $order['discount_fee'] == 0 ? bcmul($item['goods_original_price'], $item['nums'], 2) : bcmul(bcmul($item['goods_original_price'], $item['nums'], 2), $saleratio, 2);
- }
- $saleremains = bcsub($saleremains, $saleprice, 2);
- $item['goods_price'] = $saleprice;
- }
- unset($item);
- // 批量创建订单商品数据
- if (!empty($orderItem)) {
- (new OrderGoods())->saveAll($orderItem);
- }
-
- // 修改地址使用次数
- if ($address) {
- $address->setInc('used_nums');
- }
-
- // 优惠券已使用
- if (!empty($userCoupon)) {
- $userCoupon->save(['is_used' => 2]);
- }
-
- // 提交事务
- Db::commit();
- } catch (Exception $e) {
- Db::rollback();
- throw new BusinessException($e->getMessage());
- }
-
- // 记录操作
- OrderActionService::recordUserAction(
- $orderInfo['order_sn'],
- OrderActionEnum::ACTION_CREATE,
- $orderInfo['user_id'],
- '创建订单',
- $orderInfo['user_id']
- );
-
- // 订单应付金额为0时直接结算
- if ($order['amount'] == 0) {
- // Order::settle($order->order_sn, 0);
- // $order = Order::get($order->id);
- return $order;
- }
-
- return $order;
- }
- /**
- * 验证商品规格参数
- * @param array $goods_list 商品列表
- * @throws BusinessException
- */
- public static function validateGoodsList($goods_list)
- {
- if (empty($goods_list) || !is_array($goods_list)) {
- throw new BusinessException("商品列表不能为空");
- }
- foreach ($goods_list as $item) {
- if (!isset($item['goods_id']) || !is_numeric($item['goods_id']) || $item['goods_id'] <= 0) {
- throw new BusinessException("商品ID无效");
- }
-
- if (!isset($item['nums']) || !is_numeric($item['nums']) || $item['nums'] <= 0) {
- throw new BusinessException("商品数量必须大于0");
- }
-
- if (isset($item['goods_sku_id']) && !is_numeric($item['goods_sku_id'])) {
- throw new BusinessException("商品规格ID无效");
- }
- }
- }
- /**
- * 创建父子订单 - 每个商品一个子订单,统一支付父订单
- * @param int $addressId 地址ID
- * @param int $userId 用户ID
- * @param array $goodsList 商品列表
- * @param int $userCouponId 优惠券ID
- * @param string $remark 备注
- * @return array 返回父订单和子订单信息
- * @throws BusinessException
- */
- public static function createParentChildOrders($addressId, $userId, $goodsList, $userCouponId = 0, $remark = '')
- {
- return ParentOrderService::createParentChildOrders($addressId, $userId, $goodsList, $userCouponId, $remark);
- }
- /**
- * 统一的订单计算方法(用于预览订单)
- * @param array $goods_list 标准化的商品列表
- * @param int $user_id 用户ID
- * @param int $area_id 地区ID
- * @param int $user_coupon_id 优惠券ID
- * @return array
- * @throws BusinessException
- */
- public static function calculateOrder($goodsList, $userId, $areaId = 0, $userCouponId = 0)
- {
- if (empty($goodsList)) {
- throw new BusinessException("商品列表不能为空");
- }
-
- // 验证商品列表格式
- self::validateGoodsList($goodsList);
- // 订单基础信息(用于计算,不包含订单号)
- $orderInfo = [
- '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, // 运费
- ];
- // 计算商品明细
- list($orderItem, $calculatedGoodsList, $userCoupon) = self::computeGoods($orderInfo, $goodsList, $userId, $areaId, $userCouponId);
- return [
- 'orderItem' => $orderItem,
- 'goodsList' => $calculatedGoodsList,
- 'orderInfo' => $orderInfo,
- 'userCoupon' => $userCoupon
- ];
- }
- /**
- * 订单列表
- *
- * @param $param
- * @return \think\Paginator
- */
- public static function getOrderList($userId = 0, $param =[],$status = [],$supplierId = 0)
- {
- $pageSize = 10;
- if (!empty($param['pageSize'])) {
- $pageSize = $param['pageSize'];
- }
- $orderModel = new Order();
- return $orderModel->with(['orderGoods'])
- ->where(function ($query) use ($param,$userId,$status) {
- if (!empty($userId)) {
- $query->where('user_id', $userId);
- }
-
- if (!empty($status)) {
- $query->whereIn('order_status', $status );
- }
-
- if (isset($param['keywords']) && $param['keywords'] != '') {
- $query->where('order_sn', 'in', function ($query) use ($param) {
- return $query->name('shop_order_goods')->where('order_sn|goods_title', 'like', '%' . $param['q'] . '%')->field('order_sn');
- });
- }
- if (!empty($supplierId)) {
- $query->where('order_sn', 'in', function ($query) use ($supplierId) {
- return $query->name('shop_order_goods')->where('supplier_id', $supplierId)->field('order_sn');
- });
- }
- })
- ->order('createtime desc')
- ->paginate($pageSize, false, ['query' => request()->get()]);
- }
- /**
- *
- * @ 订单信息
- * @param $orderId
- * @param $userId
- * @return array|false|\PDOStatement|string|Model
- */
- public static function getDetail($orderId = 0, $userId = 0)
- {
- $orderModel = new Order();
- return $orderModel->with(['orderGoods'])
- ->where('id', $orderId)
- ->where(function($query) use ($userId){
- if($userId > 0){
- $query->where('user_id', $userId);
- }
- })
- ->find();
- }
- public static function getDetailByOrderSn($orderSn)
- {
- $orderModel = new Order();
- return $orderModel->with(['orderGoods'])
- ->where('order_sn', $orderSn)
- ->find();
- }
- // 查询地址信息
- public static function getAddressInfo($orderId)
- {
- return OrderAddress::where('order_id', $orderId)->find();
- }
-
- /**
- * 判断订单是否失效
- * @param $order_sn
- * @return bool
- */
- public static function isExpired($orderSn)
- {
- $orderInfo = self::getByOrderSn($orderSn);
- //订单过期
- if (!$orderInfo['orderstate'] && !$orderInfo['paystate'] && time() > $orderInfo['expiretime']) {
- // 启动事务
- Db::startTrans();
- try {
- $orderInfo->save(['orderstate' => 2]);
- //库存恢复
- OrderGoods::setGoodsStocksInc($orderInfo->order_sn);
- // //恢复优惠券
- // UserCoupon::resetUserCoupon($orderInfo->user_coupon_id, $orderInfo->order_sn);
- // 提交事务
- Db::commit();
- } catch (\Exception $e) {
- // 回滚事务
- Db::rollback();
- }
- return true;
- }
- return false;
- }
- public static function getByOrderSn($orderSn)
- {
- return Order::where('order_sn', $orderSn)->find();
- }
- public static function getByOrderId($orderId)
- {
- return Order::where('id', $orderId)->find();
- }
- // 获取状态订单统计
- public static function getOrderStatusCount($userId = 0)
- {
- $info = [];
- $info['unpay'] = Order::where('user_id', $userId)->where('order_status',OrderEnum::STATUS_CREATE)->count();
- $info['unsend'] = Order::where('user_id', $userId)->where('order_status',OrderEnum::STATUS_INSPECTION_PASS)->count();
- $info['unrec'] = Order::where('user_id', $userId)->where('order_status',OrderEnum::STATUS_SHIP)->count();
- $info['uneva'] = Order::where('user_id', $userId)->where('order_status',OrderEnum::STATUS_CONFIRM)->count();
- $info['inspect'] = Order::where('user_id', $userId)
- ->whereIn('order_status',[
- OrderEnum::STATUS_PAY,
- OrderEnum::STATUS_INSPECTION,
- OrderEnum::STATUS_INSPECTION_FAIL])
- ->count();
-
- return $info;
- }
- // 更新订单状态
- public static function updateOrderStatus($orderId = 0, $userId = 0, $status = 0)
- {
-
- $order = self::getDetail($orderId, $userId);
- if (!$order) {
- throw new BusinessException('订单不存在!');
- }
- // 验证状态
- // if (!OrderEnum::isValidOrderStatus($status)) {
- // throw new BusinessException('状态不合法!');
- // }
- // 要处理每个状态对应的时间字段在枚举类中
- $timeField = OrderEnum::STATUS_TIME_MAP[$status];
- $updateData = [
- 'order_status' => $status,
- $timeField => time()
- ];
- Order::where('id', $orderId)->update($updateData);
- return $order;
- }
- /**
- * 获取供应商订单列表 - 关联查询方式
- * @param int $supplierId 供应商ID
- * @param int $userId 用户ID(可选)
- * @param array $param 查询参数
- * @param array $status 订单状态筛选
- * @return \think\Paginator
- */
- public static function getSupplierOrderList($supplierId, $userId = 0, $param = [], $status = [])
- {
- $pageSize = $param['page_size'] ?? 10;
-
- return Order::alias('o')
- ->join('shop_order_goods og', 'o.order_sn = og.order_sn', 'inner')
- ->with(['orderGoods' => function($query) use ($supplierId) {
- $query->where('supplier_id', $supplierId);
- }])
- ->where('og.supplier_id', $supplierId)
- ->where(function ($query) use ($param, $userId, $status) {
- if (!empty($userId)) {
- $query->where('o.user_id', $userId);
- }
-
- if (!empty($status)) {
- $query->whereIn('o.order_status', $status);
- }
-
- if (isset($param['keywords']) && $param['keywords'] != '') {
- $query->where(function($subQuery) use ($param) {
- $subQuery->where('o.order_sn', 'like', '%' . $param['keywords'] . '%')
- ->whereOr('og.goods_title', 'like', '%' . $param['keywords'] . '%');
- });
- }
- })
- ->field('o.*')
- ->group('o.id')
- ->order('o.createtime desc')
- ->paginate($pageSize, false, ['query' => request()->get()]);
- }
- /**
- * 获取供应商订单详情 - 支持订单ID和订单号两种方式
- * @param mixed $orderParam 订单ID或订单号
- * @param int $supplierId 供应商ID
- * @param int $userId 用户ID(可选,用于权限验证)
- * @return array|null
- */
- public static function getSupplierOrderDetail($orderParam, $supplierId, $userId = 0)
- {
- // 根据参数类型判断是订单ID还是订单号
- if (is_numeric($orderParam)) {
- // 数字类型,当作订单ID处理
- $query = Order::where('id', $orderParam);
- } else {
- // 字符串类型,当作订单号处理
- $query = Order::where('order_sn', $orderParam);
- }
-
- // 如果指定了用户ID,添加用户权限验证
- if (!empty($userId)) {
- $query->where('user_id', $userId);
- }
-
- $order = $query->find();
- if (!$order) {
- return null;
- }
-
- // 获取该供应商在此订单中的商品
- $orderGoods = OrderGoods::where('order_sn', $order->order_sn)
- ->where('supplier_id', $supplierId)
- ->select();
-
- // 如果该供应商在此订单中没有商品,返回null
- if (empty($orderGoods)) {
- return null;
- }
-
- $order->order_goods = $orderGoods;
- return $order;
- }
- /**
- * 获取供应商订单统计
- * @param int $supplierId 供应商ID
- * @param int $userId 用户ID(可选)
- * @return array
- */
- public static function getSupplierOrderStatusCount($supplierId, $userId = 0)
- {
- $baseQuery = function($status) use ($supplierId, $userId) {
- $query = Order::alias('o')
- ->join('shop_order_goods og', 'o.order_sn = og.order_sn', 'inner')
- ->where('og.supplier_id', $supplierId)
- ->where('o.order_status', $status);
-
- if (!empty($userId)) {
- $query->where('o.user_id', $userId);
- }
-
- return $query->count('DISTINCT o.id');
- };
-
- return [
- 'unpay' => $baseQuery(OrderEnum::STATUS_CREATE), // 待付款
- 'unsend' => $baseQuery(OrderEnum::STATUS_PAY), // 待发货
- 'unrec' => $baseQuery(OrderEnum::STATUS_SHIP), // 待收货
- 'uneva' => $baseQuery(OrderEnum::STATUS_CONFIRM), // 待评价
- ];
- }
- /**
- * 验证订单和订单商品是否存在
- * @param int $orderId 订单ID
- * @param int $orderGoodsId 订单商品ID
- * @return array|false 返回订单和订单商品信息,不存在返回false
- */
- public static function validateOrderAndOrderGoods($orderId, $orderGoodsId)
- {
- // 查询订单
- $order = Order::where('id', $orderId)->find();
- if (!$order) {
- return false;
- }
-
- // 查询订单商品
- $orderGoods = OrderGoods::where('id', $orderGoodsId)
- ->where('order_id', $orderId)
- ->find();
- if (!$orderGoods) {
- return false;
- }
-
- return [
- 'order' => $order,
- 'order_goods' => $orderGoods
- ];
- }
- /**
- * 更新订单商品的验收状态
- * @param int $orderGoodsId 订单商品ID
- * @param int $inspectStatus 验收状态 0:待验收 1:验收通过 2:验收不通过
- * @return bool
- */
- public static function updateOrderGoodsInspectStatus($orderGoodsId, $inspectStatus,$inspectUid = 0)
- {
- return OrderGoods::where('id', $orderGoodsId)->update([
- 'inspect_status' => $inspectStatus,
- 'inspect_time' => time(),
- 'inspect_id' => $inspectUid
- ]);
- }
- /**
- * 检查订单中所有商品的验收状态
- * @param int $orderId 订单ID
- * @return array 返回验收状态统计
- */
- public static function checkOrderInspectStatus($orderId)
- {
- $orderGoods = OrderGoods::where('order_id', $orderId)->select();
-
- $statusCount = [
- 'total' => count($orderGoods), // 总商品数
- 'pending' => 0, // 待验收
- 'passed' => 0, // 验收通过
- 'failed' => 0 // 验收不通过
- ];
-
- foreach ($orderGoods as $goods) {
- switch ($goods['inspect_status']) {
- case 0:
- $statusCount['pending']++;
- break;
- case 1:
- $statusCount['passed']++;
- break;
- case 2:
- $statusCount['failed']++;
- break;
- }
- }
-
- return $statusCount;
- }
- /**
- * 根据验收状态决定是否更新订单状态
- * @param int $orderId 订单ID
- * @param int $userId 用户ID
- * @return bool
- */
- public static function updateOrderStatusByInspectResult($orderId, $userId = 0)
- {
- $inspectStatus = self::checkOrderInspectStatus($orderId);
-
- // 如果所有商品都验收完成(没有待验收的商品)
- if ($inspectStatus['pending'] == 0) {
- // 如果所有商品都验收通过
- if ($inspectStatus['failed'] == 0 && $inspectStatus['passed'] > 0) {
- // 更新订单状态为验收通过
- return self::updateOrderStatus($orderId, $userId, OrderEnum::STATUS_INSPECTION_PASS);
- }
- // 如果所有商品都验收不通过
- elseif ($inspectStatus['failed'] > 0 && $inspectStatus['passed'] == 0) {
- // 更新订单状态为验收失败
- return self::updateOrderStatus($orderId, $userId, OrderEnum::STATUS_INSPECTION_FAIL);
- }
- // 如果部分商品验收通过,部分不通过
- elseif ($inspectStatus['failed'] > 0 && $inspectStatus['passed'] > 0) {
- // 混合状态,由业务人员手动处理,不自动更新订单状态
- return true;
- }
- }
-
- return true;
- }
- /**
- * 更新订单商品的发货状态
- * @param int $orderGoodsId 订单商品ID
- * @param string $expressName 快递公司
- * @param string $expressNo 快递单号
- * @param array $expressImage 快递图片
- * @return bool
- */
- public static function updateOrderGoodsDeliveryStatus($orderGoodsId, $expressName, $expressNo, $expressImage = [],$orderExpressId = 0)
- {
- $updateData = [
- 'express_name' => $expressName,
- 'express_no' => $expressNo,
- 'express_image' => is_array($expressImage) ? json_encode($expressImage) : $expressImage,
- 'delivery_status' => 1, // 已发货
- 'updatetime' => time(),
- 'order_express_id' =>$orderExpressId
- ];
-
- return OrderGoods::where('id', $orderGoodsId)->update($updateData);
- }
- /**
- * 检查订单中所有商品的发货状态
- * @param int $orderId 订单ID
- * @return array 返回发货状态统计
- */
- public static function checkOrderDeliveryStatus($orderId)
- {
- $orderGoods = OrderGoods::where('order_id', $orderId)->select();
-
- $statusCount = [
- 'total' => count($orderGoods), // 总商品数
- 'pending' => 0, // 待发货
- 'delivered' => 0, // 已发货
- ];
-
- foreach ($orderGoods as $goods) {
- if ($goods['delivery_status'] == 1) {
- $statusCount['delivered']++;
- } else {
- $statusCount['pending']++;
- }
- }
-
- return $statusCount;
- }
- /**
- * 根据发货状态决定是否更新订单状态
- * @param int $orderId 订单ID
- * @param int $userId 用户ID
- * @return bool
- */
- public static function updateOrderStatusByDeliveryResult($orderId, $userId = 0)
- {
- $deliveryStatus = self::checkOrderDeliveryStatus($orderId);
-
- // 如果所有商品都已发货(没有待发货的商品)
- if ($deliveryStatus['pending'] == 0 && $deliveryStatus['delivered'] > 0) {
- // 更新订单状态为已发货
- return self::updateOrderStatus($orderId, $userId, OrderEnum::STATUS_SHIP);
- }
-
- return true;
- }
- /**
- * 验证订单商品是否可以发货
- * @param int $orderId 订单ID
- * @param int $orderGoodsId 订单商品ID
- * @return array|false 返回订单和订单商品信息,验证失败返回false
- */
- public static function validateOrderGoodsForDelivery($orderId, $orderGoodsId)
- {
- // 验证订单和订单商品是否存在
- $orderData = self::validateOrderAndOrderGoods($orderId, $orderGoodsId);
- if (!$orderData) {
- return false;
- }
-
- $orderGoods = $orderData['order_goods'];
- // 检查订单商品的状态是都验货通过才可以发货
- // if ($orderGoods['inspect_status'] !== 1) {
- // return false;
- // }
- if (empty($orderGoods['inspect_time'])) {
- return false;
- }
- // 检查该订单商品是否已经发货
- if ($orderGoods['delivery_status'] == 1) {
- return false;
- }
-
- return $orderData;
- }
- }
|