// +---------------------------------------------------------------------- namespace App\Services\Api; use App\Models\AccountLogModel; use App\Models\CartsModel; use App\Models\GoodsModel; use App\Models\MemberCouponModel; use App\Models\MemberModel; use App\Models\MerchantModel; use App\Models\OrderGoodsModel; use App\Models\OrderModel; use App\Services\BaseService; use App\Services\ConfigService; use App\Services\RedisService; use App\Services\SupplyService; use Illuminate\Support\Facades\DB; /** * 订单管理-服务类 * @author laravel开发员 * @since 2020/11/11 * Class OrderService * @package App\Services\Api */ class OrderService extends BaseService { // 静态对象 protected static $instance = null; /** * 构造函数 * @author laravel开发员 * @since 2020/11/11 * OrderService constructor. */ public function __construct() { $this->model = new OrderModel(); } /** * 静态入口 * @return static|null */ public static function make() { if (!self::$instance) { self::$instance = (new static()); } return self::$instance; } /** * @param $params * @param int $pageSize * @return array */ public function getDataList($params, $pageSize = 15) { $where = ['a.mark' => 1,'a.is_hide'=>0]; $merchId = isset($params['merch_id']) ? $params['merch_id'] : 0; if ($merchId > 0) { $where['a.merch_id'] = $merchId; } $merchUid = isset($params['merch_uid']) ? $params['merch_uid'] : 0; if ($merchUid > 0) { $where['a.merch_uid'] = $merchUid; } // var_dump($params); $list = $this->model->from('orders as a')->with(['goods']) ->leftJoin('member as b', 'a.user_id', '=', 'b.id') ->where($where) ->where(function ($query) use ($params) { $keyword = isset($params['kw']) ? $params['kw'] : ''; if ($keyword) { $query->where('a.order_no', 'like', "%{$keyword}%"); } }) ->where(function ($query) use ($params) { $status = isset($params['status']) ? $params['status'] : 0; $userId = isset($params['user_id']) ? $params['user_id'] : 0; $type = isset($params['type']) ? $params['type'] : 0; if ($userId) { $query->where('a.user_id', '=', $userId); } if ($type > 0) { $query->where('a.type', '=', $type); } if ($status > 0) { $query->where('a.status', '=', $status); }else{ $query->where('a.status', '>', 1); } }) ->select(['a.*', 'b.nickname', 'b.trc_url']) ->orderBy('a.pay_time', 'desc') ->orderBy('a.id', 'desc') ->paginate($pageSize > 0 ? $pageSize : 9999999); $list = $list ? $list->toArray() : []; if ($list) { $refundStatusArr = [1=>'退款中',2=>'已退款',3=>'退款失败']; $statusArr = [1=>'待付款',2=>'待发货',3=>'待收货',4=>'已完成',5=>'已售后']; $supplyList = config('goods.supplyList'); foreach ($list['data'] as &$item) { $item['create_time'] = $item['create_time'] ? datetime($item['create_time'], 'Y-m-d H:i:s') : ''; $item['pay_time'] = $item['pay_time'] ? datetime($item['pay_time'], 'Y-m-d H:i:s') : ''; $status = isset($item['status'])? $item['status'] : 0; $item['status_text'] = '待付款'; $item['refund_status_text'] = ''; if($status){ if($item['type'] == 2){ $item['status_text'] = isset($serviceStatusArr[$status])? $serviceStatusArr[$status] : ''; }else{ $item['status_text'] = isset($statusArr[$status])? $statusArr[$status] : ''; } } $refundStatus = isset($item['refund_status'])? $item['refund_status'] : 0; if($refundStatus && $status != 4){ $item['refund_status_text'] = isset($refundStatusArr[$refundStatus])? $refundStatusArr[$refundStatus] : ''; } $goods = isset($item['goods'])? $item['goods'] : []; if($goods){ $isRefund = false; foreach ($goods as &$v){ $v['supply_name'] = isset($supplyList[$v['supply_type']]) ? $supplyList[$v['supply_type']] : ''; $v['main_img'] = isset($v['main_img']) && $v['main_img']? get_image_url($v['main_img']) : ''; $v['sku_attr'] = isset($v['sku_attr']) && $v['sku_attr']? json_decode($v['sku_attr'], true) : []; if(!in_array($v['refund_status'],[1,2,3]) && $item['status'] != 4){ $isRefund = true; $v['is_refund'] = 1; } } unset($v); $item['is_refund'] = $isRefund; } $item['goods'] = $goods? $goods : []; } unset($item); } return [ 'pageSize' => $pageSize, 'total' => isset($list['total']) ? $list['total'] : 0, 'counts' => [], 'list' => isset($list['data']) ? $list['data'] : [] ]; } /** * 购买商品 * @param $userId 用户ID * @param $params * @return array|false */ public function buySubmit($userId, $params) { $payType = isset($params['pay_type'])? intval($params['pay_type']) : 0; $type = isset($params['type']) && $params['type']? intval($params['type']) : 1; $amount = isset($params['total']) && $params['total']? floatval($params['total']) : 0; $couponId = isset($params['coupon_id'])? intval($params['coupon_id']) : 0; $addressId = isset($params['address_id'])? intval($params['address_id']) : 0; $freightAddressId = isset($params['freight_address_id'])? intval($params['freight_address_id']) : 0; $payPassword = isset($params['pay_password'])? trim($params['pay_password']) : ''; $skuList = isset($params['sku_list'])? $params['sku_list'] : []; $ids = isset($params['ids'])? $params['ids'] : []; $cartIds = isset($params['cart_ids'])? trim($params['cart_ids']) : ''; $cartIds = $cartIds? explode('|', $cartIds) : []; if(empty($skuList) || empty($ids) || $addressId<=0 || $freightAddressId<=0 || $payType<=0){ $this->error = 2420; return false; } // 锁 $cacheKey = "caches:orders:buy:{$userId}"; if(RedisService::get($cacheKey)){ $this->error = 1053; return false; } // 订单商品 $goodsList = GoodsService::make()->getOrderGoods($userId, $ids); if(empty($goodsList)){ $this->error = 2903; return false; } // 格式化 $skuArr = []; $skuAttr = []; foreach ($skuList as $v){ $skuArr[$v['goods_id']] = [ 'sku_id'=> $v['sku_id'], 'num'=> intval($v['num']), ]; $skuAttr[$v['goods_id']] = $v['attr']; } $skuList = $skuArr; $goodsNum = 0; $orderTotal = 0; $orderXdTotal = 0; $merchId = 0; $orderNo = get_order_num('XS'); // 价格参数 $goods = []; $usdtPrice = RedisService::get("caches:wallets:usdt_rate"); if($usdtPrice<=0){ $usdtCnyPrice = ConfigService::make()->getConfigByCode('usdt_cny_price', 7.2); $usdtPrice = $usdtCnyPrice>0 && $usdtCnyPrice< 100? $usdtCnyPrice : 0; } $xdPrice = ConfigService::make()->getConfigByCode('xd_price', 100); $xdPrice = $xdPrice > 0 && $xdPrice <= 10000 ? $xdPrice : 100; foreach($goodsList as $item){ $goodsId = isset($item['goods_id'])? $item['goods_id'] : 0; $merchId = isset($item['merch_id'])? $item['merch_id'] : 0; $num = isset($skuList[$goodsId]['num'])? intval($skuList[$goodsId]['num']) : 0; $skuId = isset($skuList[$goodsId]['sku_id'])? intval($skuList[$goodsId]['sku_id']) : 0; $skuInfo = GoodsService::make()->getSkuInfo($skuId); $price = isset($skuInfo['plat_price'])? $skuInfo['plat_price'] : 0; $attr = isset($skuAttr[$goodsId])? $skuAttr[$goodsId] : []; if($num>0 && $skuId >0 && $price>0){ $item['price'] = GoodsService::make()->getRealSalePrice($price); // 浮动后星豆价 $price = GoodsService::make()->getRealSalePrice($price,3); // 浮动后原售价 $total = moneyFormat($price * $num, 2); $xdTotal = moneyFormat($item['price'] * $num, 2); // 订单商品 $skuSn = isset($skuInfo['sku_sn'])? $skuInfo['sku_sn'] : ''; $item['order_no'] = $orderNo; $item['sku_id'] = $skuId; $item['sku_sn'] = $skuSn; $item['total'] = $total; $item['xd_total'] = $xdTotal; $item['num'] = $num; $item['sku_attr'] = $attr? json_encode($attr, 256) : ''; $item['create_time'] = time(); $item['update_time'] = time(); $item['status'] = 1; $item['mark'] = 1; // 订单金额 $orderTotal += $total; $orderXdTotal += $xdTotal; $goodsNum += $num; unset($item['sku_list']); $goods[$skuSn] = $item; }else{ unset($item); } } unset($item); if($orderXdTotal<=0 || $goodsNum<=0){ $this->error = 2904; return false; } // 优惠券 $couponPrice = 0; if($couponId > 0){ } // 验证用户 $userInfo = MemberModel::where(['id'=> $userId,'mark'=> 1,'status'=> 1]) ->select(['id','nickname','pay_password','balance','parent_id','parents']) ->first(); $userInfo = $userInfo? $userInfo->toArray() : []; $userPayPassword = isset($userInfo['pay_password'])? $userInfo['pay_password'] : ''; $userXd = isset($userInfo['balance'])? floatval($userInfo['balance']) : 0.00; if(empty($userInfo)){ $this->error = 2024; return false; } // 余额支付支付密码验证 if($payType == 10 && empty($userPayPassword)){ $this->error =1040; return false; } // 星豆余额支付交易密码 $payPassword = get_password($payPassword); if($payType == 10 && $payPassword != $userPayPassword){ $this->error = 2038; return false; } // 运费 $skus = array_values($skuList); if(!$freightData = GoodsService::make()->getFreight($userId, $freightAddressId, $skus)){ $this->error = GoodsService::make()->getError()?? 2905; return false; } $freight = isset($freightData['freight'])? floatval($freightData['freight']) : 0; $payTotal = moneyFormat($orderXdTotal+$freight,2); if(intval($amount) != intval($payTotal)){ $this->error = 2906; return false; } // 星豆余额支付验证 if($payType == 10 && $userXd < $payTotal){ $this->error = 2304; return false; } // 收货地址 $addressInfo = MemberAddressService::make()->getBindInfo($userId, $addressId); $addressText = isset($addressInfo['address_text'])? $addressInfo['address_text'] : ''; $city = isset($addressInfo['city'])? $addressInfo['city'] : ''; $realname = isset($addressInfo['realname'])? $addressInfo['realname'] : ''; $mobile = isset($addressInfo['mobile'])? $addressInfo['mobile'] : ''; $address = isset($addressInfo['address'])? $addressInfo['address'] : ''; if(empty($addressText) || empty($addressInfo) || empty($realname) || empty($mobile)){ $this->error = 2902; return false; } $merchUId = 0; // 奖励待返积分 $waitScoreRate = ConfigService::make()->getConfigByCode('shop_award_score_rate',0); $waitScoreRate = $waitScoreRate>=0 && $waitScoreRate<=1000? $waitScoreRate : 0; $awardWaitScore = moneyFormat($orderXdTotal * $waitScoreRate/100, 2); // 算力奖励 $powerRate = ConfigService::make()->getConfigByCode('shop_award_power_rate',0); $powerRate = $powerRate>=0 && $powerRate<=1000? $powerRate : 0; $awardPowerNum = moneyFormat($orderXdTotal * $powerRate/100, 2); // 订单数据 $order = [ 'user_id'=> $userId, 'order_no'=> $orderNo, 'merch_id'=> $merchId, 'merch_uid'=> $merchUId, 'type'=> $type, 'price'=> 0.00, 'xd_price'=> $xdPrice, 'num'=> $goodsNum, 'city'=> $city, 'real_name'=> $realname, 'mobile'=> $mobile, 'address'=> $address && $addressText? $addressText.' '.$address : $addressText, 'total'=> $orderTotal, 'xd_total'=> $orderXdTotal, 'pay_type'=> $payType, 'pay_money'=> $payTotal, 'delivery_type'=> 1, 'coupon_id'=> $couponId, 'coupon_price'=> $couponPrice, 'postage'=> $freight, 'award_wait_score'=> $awardWaitScore, 'award_power_num'=> $awardPowerNum, 'create_time'=> time(), 'update_time'=> time(), 'remark'=> isset($params['remark'])? trim($params['remark']) : '', 'status'=> 1, 'mark'=> 1, ]; // 站外订单提交 RedisService::set($cacheKey, $order, rand(2,3)); $orderParams = [ 'third_order'=> $orderNo, 'address_id'=> $freightAddressId, 'sku_list'=> $skus, 'receiver'=> $realname, 'receiver_phone'=> $mobile, 'address'=> $address, 'other'=> isset($params['remark'])? $params['remark'] : '', ]; $result = SupplyService::make()->getApiData('orderSubmit', $orderParams); $orderSku = isset($result['sku'])? $result['sku'] : []; $outOrderNo = isset($result['out_order_no'])? $result['out_order_no'] : ''; if(empty($result)){ RedisService::clear($cacheKey); $this->error = SupplyService::make()->getError(); return false; } // 订单回单数据 $order['out_order_no'] = $outOrderNo; if($orderSku){ foreach ($orderSku as $item){ if($item['goodsSkuCode'] && isset($goods[$item['goodsSkuCode']])){ $goods[$item['goodsSkuCode']]['expense'] = isset($item['expense'])? $item['expense'] : 0; $goods[$item['goodsSkuCode']]['service_price'] = isset($item['service_price'])? $item['service_price'] : 0; } } } if(!$orderId = $this->model->insertGetId($order)){ $this->error = 2907; RedisService::clear($cacheKey); return false; } // 写入订单商品 $goods = array_values($goods); if($orderId && !OrderGoodsModel::insert($goods)){ $this->error = 2908; RedisService::clear($cacheKey); return false; } DB::beginTransaction(); // 支付处理 $payment = []; $dateTime = date('Y-m-d H:i:s'); switch($payType){ case 10: // 星豆余额支付 // 扣除余额 $updateData = [ 'balance'=> DB::raw("balance - {$payTotal}"), // 扣除星豆 'update_time'=>time() ]; if(!MemberModel::where(['id'=> $userId])->update($updateData)){ DB::rollBack(); $this->error = 1042; RedisService::clear($cacheKey); return false; } // 余额明细 $log = [ 'user_id' => $userId, 'source_id' => $orderId, 'source_order_no' => $orderNo, 'type' => 3, 'coin_type' => 2, 'user_type'=> 1, 'money' => $payTotal, 'actual_money' => $payTotal, 'balance' => $userXd, 'create_time' => time(), 'update_time' => time(), 'remark' => "商城购物消费", 'status' => 1, 'mark' => 1, ]; if(!AccountLogModel::insertGetId($log)){ DB::rollBack(); $this->error = 2029; RedisService::clear($cacheKey); return false; } // 更新订单状态 $updateData = ['status'=>2,'pay_status'=> 1,'pay_time'=>date('Y-m-d H:i:s'),'update_time'=>time()]; if(!$this->model->where(['id'=> $orderId,'mark'=>1])->update($updateData)){ DB::rollBack(); $this->error = 2909; RedisService::clear($cacheKey); return false; } $payStatus = 1; break; default: $this->error = 1030; return false; } // 更新优惠券状态 if($couponId>0 && !MemberCouponModel::where(['id'=> $couponId,'mark'=>1])->update(['status'=> 2,'update_time'=>time()])){ DB::rollBack(); $this->error = 2908; RedisService::clear($cacheKey); return false; } // 购物车处理 if($cartIds){ CartsModel::where(['user_id'=> $userId,'status'=>1,'mark'=>1]) ->whereIn('id', $cartIds) ->update(['status'=>2,'update_time'=>time()]); RedisService::clear("caches:members:cartList:{$userId}"); RedisService::clear("caches:members:cartCount:{$userId}"); } // 已支付 RedisService::clear($cacheKey); if($payStatus == 1){ // 支付成功订单通知 $message = "您在{$dateTime}(UTC+8)创建的订单【{$orderNo}】,金额{$payTotal}星豆,已支付成功,请耐心等候发货。"; MessageService::make()->pushMessage($userId,"订单支付成功",$message, 2); DB::commit(); $this->error = 2910; return [ 'id'=> $orderId, 'out_order_no'=> $outOrderNo, 'total'=> $payTotal, 'pay_type'=> $payType, ]; }else{ // 下单成功订单通知 $message = "您在{$dateTime}(UTC+8)创建订单【{$orderNo}】成功,请尽快完成支付。"; MessageService::make()->pushMessage($userId,"订单创建成功",$message, 2); DB::commit(); $this->error = 2911; return [ 'id'=> $orderId, 'out_order_no'=> $outOrderNo, 'total'=> $payTotal, 'pay_type'=> $payType, ]; } } /** * 详情 * @param $id * @return mixed */ public function getInfo($id, $userId=0) { $where = [ 'a.mark' => 1]; if(intval($id) == $id){ $where['a.id'] = $id; }else{ $where['a.order_no'] = $id; } $info = $this->model->with(['goods']) ->from('orders as a') ->leftJoin('member as b', 'b.id', '=', 'a.user_id') ->where($where) ->select(['a.*', 'b.nickname', 'b.mobile as buy_mobile']) ->first(); if ($info) { $info['create_time_text'] = $info['create_time'] ? datetime($info['create_time'], 'Y-m-d H:i:s') : ''; $info['pay_time'] = $info['pay_time']? datetime($info['pay_time'], 'Y-m-d H:i:s') : ''; $info['complete_time'] = $info['pay_time']? dateFormat($info['complete_time'], 'Y-m-d H:i:s') : ''; $info['mobile_text'] = isset($info['mobile'])? format_mobile($info['mobile']) : ''; if(isset($info['goods']) && $info['goods']){ foreach ($info['goods'] as &$item){ $item['main_img'] = $item['main_img']? get_image_url($item['main_img']) : ''; $item['sku_attr'] = $item['sku_attr']? json_decode($item['sku_attr'],true) :[]; $item['retail_price1'] = $item['retail_price']; $item['retail_price'] = GoodsService::make()->getRealSalePrice($item['cost_price']); } unset($item); } $payTypes = [10=>'星豆余额支付']; if(isset($info['pay_type'])){ $info['pay_text'] = isset($payTypes[$info['pay_type']])? $payTypes[$info['pay_type']] : '其他'; } $deliveryTypes = [1=>'快递配送']; if(isset($info['pay_type'])){ $info['delivery_text'] = isset($deliveryTypes[$info['delivery_type']])? $deliveryTypes[$info['delivery_type']] : '其他'; } } return $info; } /** * 订单支付 * @param $userId * @param $params */ public function pay($userId, $params) { return true; } /** * 申请退款 * @param $userId * @param $params * @return bool */ public function refund($userId, $params) { $id = isset($params['id']) ? $params['id'] : 0; $refundType = isset($params['refund_type']) ? $params['refund_type'] : 0; $refundRemark = isset($params['remark']) ? $params['remark'] : ''; $skuSn = isset($params['sku_sn']) ? $params['sku_sn'] : ''; $info = $this->model->with(['goods'])->where(['id' => $id, 'mark' => 1]) ->select(['id','order_no','out_order_no','user_id','merch_id','pay_money','coupon_id','pay_status','status','refund_status','pay_time']) ->first(); $status = isset($info['status']) ? $info['status'] : 0; $orderNo = isset($info['order_no']) ? $info['order_no'] : ''; $outOrderNo = isset($info['out_order_no']) ? $info['out_order_no'] : ''; $orderUserId = isset($info['user_id']) ? $info['user_id'] : 0; $payStatus = isset($info['pay_status']) ? $info['pay_status'] : 0; $refundStatus = isset($info['refund_status']) ? $info['refund_status'] : 0; $goods = isset($info['goods']) ? $info['goods'] : []; if (!$id || empty($info)) { $this->error = 2912; return false; } // 非法操作 if($userId != $orderUserId){ $this->error = 2913; return false; } if(!in_array($status, [2,3,5])){ $this->error = 2914; return false; } if($refundStatus>0 && $refundStatus != 2){ $this->error = 2915; return false; } if(!in_array($refundType,[1,2,3,4])){ $this->error = 2922; return false; } // 多商品退款暂不开放 /*if(count($goods)>1){ $this->error = 2920; return false; }*/ // 站外售后验证 $result = SupplyService::make()->getApiData('getAfterCan',['plat_order_no'=> $outOrderNo]); $orderGoods = isset($result['order_goods'])? $result['order_goods'] : []; $orderGoodsInfo = isset($orderGoods[0])? $orderGoods[0] : []; $orderGoodsId = isset($orderGoodsInfo['order_goods_id'])? $orderGoodsInfo['order_goods_id'] : 0; $orderGoodsSkuSn = isset($orderGoodsInfo['goods_sku'])? $orderGoodsInfo['goods_sku'] : ''; $orderAfterNum= isset($orderGoodsInfo['after_num'])? $orderGoodsInfo['after_num'] : 0; if(empty($orderGoods) || empty($orderGoodsInfo) || empty($orderGoodsId) || empty($orderGoodsSkuSn)){ $this->error = 2918; return false; } // 商品验证 if($skuSn){ // 多商品中的一个 $canRefund = false; foreach($orderGoods as $item){ $outRefundStatus = isset($item['status'])? intval($item['status']) : 0; $goodsSkuSn = isset($item['goods_sku'])? $item['goods_sku'] : ''; $orderAfterNum = isset($item['after_num'])? $item['after_num'] : 0; if($goodsSkuSn == $skuSn && $outRefundStatus ==1 && $orderAfterNum>0){ $canRefund = true; $orderGoodsId = isset($item['order_goods_id'])? $item['order_goods_id'] : ''; } } if(!$canRefund){ $this->error = 2921; return false; } } // 单商品 else{ $skuSn = $orderGoodsSkuSn; $outRefundStatus = isset($orderGoodsInfo['status'])? $orderGoodsInfo['status'] : 0; if($outRefundStatus == 0){ $this->error = 2921; return false; } } // 站外申请售后 $data = [ 'plat_order_no'=> $outOrderNo, 'goods_sku'=> $skuSn, 'after_num'=> $orderAfterNum, 'order_goods_id'=> $orderGoodsId, 'after_type'=> $refundType, 'explain'=> $refundRemark, ]; $result = SupplyService::make()->getApiData('applyAfter', $data); $platAfterNo = isset($result['plat_after_no'])? $result['plat_after_no'] : ''; if(empty($platAfterNo) || empty($result)){ $this->error = 2925; return false; } // 处理 DB::beginTransaction(); if(!$this->model->where(['id'=> $id,'mark'=>1])->update(['status'=> 5,'refund_status'=>1,'refund_temp_status'=> $status,'refund_type'=> $refundType,'refund_remark'=> $refundRemark,'update_time'=>time()])){ $this->error = 2917; DB::rollBack(); return false; } if(!OrderGoodsModel::where(['order_no'=> $orderNo,'sku_sn'=>$skuSn])->update(['plat_after_no'=> $platAfterNo,'order_goods_id'=> $orderGoodsId,'refund_status'=>1,'update_time'=>time()])){ $this->error = 2917; DB::rollBack(); return false; } $this->error = 2916; DB::commit(); return ['status_text'=>'已售后','refund_text'=>'待审核','id'=> $id]; } /** * 申请退款取消 * @param $userId * @param $params * @return bool */ public function refundCancel($userId, $params) { $id = isset($params['id']) ? $params['id'] : 0; $info = $this->model->where(['id' => $id, 'mark' => 1]) ->select(['id','user_id','merch_id','order_no','pay_money','coupon_id','status','refund_status','refund_temp_status','pay_time']) ->first(); $status = isset($info['status']) ? $info['status'] : 0; $orderNo = isset($info['order_no']) ? $info['order_no'] : ''; $orderUserId = isset($info['user_id']) ? $info['user_id'] : 0; $refundStatus = isset($info['refund_status']) ? $info['refund_status'] : 0; $tempStatus = isset($info['refund_temp_status']) ? $info['refund_temp_status'] : 0; if (!$id || empty($info)) { $this->error = 2912; return false; } // 非法操作 if($userId != $orderUserId){ $this->error = 2913; return false; } if($status != 5){ $this->error = 2914; return false; } if($refundStatus != 1){ $this->error = 2927; return false; } // 售后商品 $platAfterNo = OrderGoodsModel::where(['order_no'=> $orderNo])->whereIn('refund_status',[1,2])->value('plat_after_no'); if(empty($platAfterNo)){ $this->error = 2928; return false; } // 取消售后 $result = SupplyService::make()->getApiData('applyAfterCancel',['after_order_no'=> $platAfterNo,'explain'=>'用户取消']); if(!$result){ $this->error = SupplyService::make()->getError(); return false; } // 处理 DB::beginTransaction(); $updateData = ['status'=> $tempStatus,'refund_status'=>0,'refund_remark'=> '','update_time'=>time()]; if(!$this->model->where(['id'=> $id,'mark'=>1])->update($updateData)){ DB::rollBack(); $this->error = 2929; return false; } if(!OrderGoodsModel::where(['order_no'=> $orderNo,'plat_after_no'=>$platAfterNo])->update(['refund_status'=>0,'update_time'=>time()])){ $this->error = 2929; DB::rollBack(); return false; } DB::commit(); $statusArr = [1=>'待付款',2=>'待发货',3=>'待收货',4=>'已完成',5=>'已售后']; $this->error = 2930; return ['status'=> $tempStatus,'refund_text'=>'','status_text'=>isset($statusArr[$tempStatus])? $statusArr[$tempStatus]:'']; } /** * 售后确认通过 * @param $userId * @param $params * @return bool */ public function refundConfirm($userId, $params) { $orderId = isset($params['id']) ? $params['id'] : 0; $goodsId = isset($params['goods_id']) ? $params['goods_id'] : 0; $platAfterNo = isset($params['plat_after_no']) ? $params['plat_after_no'] : ''; $info = $this->model->with(['goods','member'])->where(['id' => $orderId, 'mark' => 1]) ->select(['id','user_id','merch_id','order_no','xd_total','pay_money','coupon_id','status','refund_status','pay_time']) ->first(); $status = isset($info['status']) ? $info['status'] : 0; $orderNo = isset($info['order_no']) ? $info['order_no'] : ''; $orderUserId = isset($info['user_id']) ? $info['user_id'] : 0; $refundStatus = isset($info['refund_status']) ? $info['refund_status'] : 0; $payTotal = isset($info['pay_money']) ? $info['pay_money'] : 0; $userInfo = isset($info['member']) ? $info['member'] : []; $goods = isset($info['goods']) ? $info['goods'] : []; if (!$orderId || empty($info)) { $this->error = 2912; return false; } if($status != 5){ $this->error = 2914; return false; } if($refundStatus != 1){ $this->error = 2927; return false; } if(empty($goods)){ $this->error = 2933; return false; } if(empty($userInfo)){ $this->error = 3003; return false; } // 售后商品处理 DB::beginTransaction(); $refundTotal = 0; $goodsName = ''; foreach ($goods as $item){ $id = isset($item['goods_id'])? $item['goods_id'] : 0; $goodsRefundStatus = isset($item['refund_status'])? $item['refund_status'] : 0; // $goodsPlatAfterNo = isset($item['plat_after_no'])? $item['plat_after_no'] : 0; $xdTotal = isset($item['xd_total'])? $item['xd_total'] : 0; if(($goodsId == 0 && $goodsRefundStatus != 3) || (in_array($goodsRefundStatus,[1,2]) && $id == $goodsId)){ if(!OrderGoodsModel::where(['goods_id'=> $id,'order_no'=> $orderNo])->update(['refund_status'=>3,'update_time'=>time()])){ DB::rollBack(); $this->error = 2934; return false; } $refundTotal+= $xdTotal; $goodsName = $goodsId? $item['goods_name'] : '全部'; } } // 统一退款处理 if($refundTotal<=0){ DB::rollBack(); $this->error = 2935; return false; } // 订单售后状态 if(!$this->model->where(['id'=> $orderId,'mark'=>1])->update(['refund_status'=> 3,'update_time'=>time()])){ DB::rollBack(); $this->error = 2932; return false; } // 退款进账 $updateData = ['balance'=> DB::raw("balance + {$refundTotal}"),'update_time'=>time()]; if(!MemberModel::where(['id'=> $orderUserId])->update($updateData)){ DB::rollBack(); $this->error = 2028; return false; } // 账户明细 $userXd = isset($userInfo['balance'])? $userInfo['balance'] : 0; $log = [ 'user_id' => $orderUserId, 'source_id' => $orderId, 'source_order_no' => $orderNo, 'type' => 7, 'coin_type' => 2, 'user_type'=> 1, 'money' => $refundTotal, 'actual_money' => $refundTotal, 'balance' => $userXd, 'create_time' => time(), 'update_time' => time(), 'remark' => "商城订单售后退款", 'status' => 1, 'mark' => 1, ]; if(!AccountLogModel::insertGetId($log)){ DB::rollBack(); $this->error = 2029; return false; } // 退款消息 $dateTime = date('Y-m-d H:i:s'); if($goodsId){ $message = "您的订单在{$dateTime}(UTC+8)已成功售后:\n售后商品:{$goodsName}\n售后订单:{$orderNo}\n售后交易订单:{$platAfterNo}\n订单金额:{$payTotal}\n退款星豆:{$refundTotal} \n退款前:{$userXd} 星豆\n"; }else{ $message = "您的订单在{$dateTime}(UTC+8)已成功售后:\n售后商品:{$goodsName}\n售后订单:{$orderNo}\n订单金额:{$payTotal}\n退款星豆:{$refundTotal} \n退款前:{$userXd} 星豆\n"; } MessageService::make()->pushMessage($userId, '每日积分返还星豆奖励', $message,3); DB::commit(); $this->error = 2936; return ['order_id'=>$orderId,'goods_id'=>$goodsId,'plat_after_no'=>$platAfterNo,'pay_total'=>$payTotal,'refund_total'=>$refundTotal]; } /** * 收货/已完成 * @return bool */ public function complete($userId, $params) { $id = isset($params['id']) ? $params['id'] : 0; $info = $this->model->with(['goods']) ->where(['id' => $id, 'mark' => 1]) ->select(['id','user_id','order_no','out_order_no','merch_uid','xd_total','pay_money','type','postage','award_wait_score','award_power_num','award_score','merch_bonus','coupon_id','status','refund_status','pay_time']) ->first(); $status = isset($info['status']) ? $info['status'] : 0; $orderUserId = isset($info['user_id']) ? $info['user_id'] : 0; $orderNo = isset($info['order_no']) ? $info['order_no'] : ''; $goods = isset($info['goods'])? $info['goods'] : []; if (!$id || empty($info)) { $this->error = 2912; return false; } // 非法操作 if($userId && $orderUserId != $userId){ $this->error = 2913; return false; } // 订单状态 if (!in_array($status, [2,3,5])) { $this->error = 2914; return false; } $realXdTotal = 0; $hasGoods = false; foreach($goods as $item){ if(!in_array($item['refund_status'],[3])){ $hasGoods = true; $realXdTotal += $item['xd_total']; } } if(!$hasGoods || $realXdTotal <=0){ $this->error = 2931; return false; } // TODO 确认数据处理 DB::beginTransaction(); // 更新订单状态 if (!$this->model->where(['id' => $id])->update(['status' => 4, 'update_time' => time()])) { DB::rollBack(); $this->error = 2932; return false; } // 更新商品/服务销量 if($goods){ foreach($goods as $item){ $num = isset($item['num'])? $item['num'] : 0; if($num>0){ GoodsModel::where(['goods_id'=> $item['goods_id'],'mark'=>1])->update([ 'sales'=> DB::raw("sales + {$num}"),'update_time'=> time() ]); } } } // 完成订单消息 $dateTime = date('Y-m-d H:i:s'); $message = "您在{$dateTime}(UTC+8)成功完成购物订单【{$orderNo}】交易。"; MessageService::make()->pushMessage($orderUserId,"订单交易完成",$message, 2); // 订单结算奖励和佣金 if(!$result = FinanceService::make()->settleOrder($info, $realXdTotal)){ DB::rollBack(); $this->error = FinanceService::make()->getError(); return false; } DB::commit(); $this->error = 1002; return $result; } /** * 隐藏删除 * @return false */ public function hide($userId, $params) { $id = isset($params['id']) ? $params['id'] : 0; $info = $this->model->where(['id' => $id, 'mark' => 1]) ->select(['id','user_id','order_no','status','is_hide']) ->first(); if (!$id || empty($info)) { $this->error = 2912; return false; } $isHide = isset($info['is_hide'])? $info['is_hide'] : 0; if($isHide >0){ $this->error = 2914; return false; } if($this->model->where(['id'=> $id])->update(['is_hide'=>2,'update_time'=>time()])) { $this->error = 1002; return true; }else{ $this->error = 1003; return false; } } /** * 查询物流信息 * @param $userId 用户 * @param $params * @return array|false|mixed */ public function getTrack($userId, $params) { $outOrderNo = isset($params['out_order_no'])? $params['out_order_no'] : ''; if(empty($outOrderNo)){ $this->error = 2014; return false; } $cacheKey = "caches:orders:track_{$userId}_{$outOrderNo}"; $data = RedisService::get($cacheKey); if($data || RedisService::exists($cacheKey)){ return $data? $data : []; } $result = SupplyService::make()->getApiData('getOrderTrack',['out_order_no'=> $outOrderNo]); $data = isset($result['logistics'])? $result['logistics'] : []; if($data){ RedisService::set($cacheKey, $data, rand(30, 60)); $this->error = 1010; return $data; }else{ $this->error = 2924; return false; } } /** * 查询售后信息 * @param $userId 用户 * @param $params * @return array|false|mixed */ public function getAfter($userId, $params) { $platAfterNo = isset($params['plat_after_no'])? $params['plat_after_no'] : ''; if(empty($platAfterNo)){ $this->error = 2014; return false; } $cacheKey = "caches:orders:after_{$userId}_{$platAfterNo}"; $data = RedisService::get($cacheKey); if($data || RedisService::exists($cacheKey)){ return $data? $data : []; } $result = SupplyService::make()->getApiData('getAfterStatus',['plat_after_no'=> $platAfterNo]); if($result){ $result['goods'] = []; $goods = OrderGoodsModel::where(['plat_after_no'=> $platAfterNo])->first(); if($goods){ $goods['sku_attr'] = isset($goods['sku_attr']) && $goods['sku_attr']? json_decode($goods['sku_attr'], true) : []; $result['goods'] = $goods; } RedisService::set($cacheKey, $result, rand(30, 60)); $this->error = 1010; return $result; }else{ $this->error = 2926; return false; } } /** * 订单发货状态自动处理 * @return array|false */ public function updateOrderStatus() { set_time_limit(0); $cacheKey = "cache:orders:update_lock"; if(RedisService::get($cacheKey)){ $this->error = 3001; return false; } $page = RedisService::get('caches:orders:update_page'); $page = $page? $page+1 : 1; $catchNum = ConfigService::make()->getConfigByCode('update_order_num',100); $pageSize = $catchNum>10 && $catchNum<=200? $catchNum : 100; $orders = $this->model->whereIn('status',[2,3]) ->where(['mark'=>1]) ->select(['id','user_id','order_no','out_order_no','status']) ->orderBy('pay_time','asc') ->offset(($page-1)*$pageSize) ->limit($pageSize) ->get(); $orders = $orders? $orders->toArray() : []; RedisService::set($cacheKey, $orders, rand(30,60)); $success = 0; $deliverCount = 0; if($orders){ foreach ($orders as $item){ $orderId = isset($item['id'])? $item['id'] : 0; $orderNo = isset($item['order_no'])? $item['order_no'] : ''; $outOrderNo = isset($item['out_order_no'])? $item['out_order_no'] : ''; if(empty($orderNo) || empty($outOrderNo)){ continue; } $lockCacheKey = "caches:orders:update:{$orderNo}_{$outOrderNo}"; if(RedisService::get($lockCacheKey.'_lock')){ continue; } $data = [ 'out_order_no'=> $outOrderNo, 'third_order_no'=> $orderNo, ]; $result = SupplyService::make()->getApiData('getOrderDetail', $data); if(empty($result)){ RedisService::clear($lockCacheKey.'_lock'); continue; } $orderStatus = isset($result['status'])? $result['status'] : 0; $deliveryTime = isset($result['delivery_time']) && $result['delivery_time']? strtotime($result['delivery_time']) : time(); $supplyOrderNo = isset($result['supply_order_no']) && $result['supply_order_no']? $result['supply_order_no'] : ''; // 已发货,待收货 if($orderStatus == 3){ if($this->model->where(['order_no'=> $orderNo])->update(['supply_order_no'=>$supplyOrderNo,'express_time'=> $deliveryTime,'status'=>3,'update_time'=>time()])){ $deliverCount++; } } // 已完成 else if(in_array($orderStatus,[4,7])) { if($this->complete(0,['order_id'=> $orderId,'supply_order_no'=>$supplyOrderNo])){ $success++; } } RedisService::clear($lockCacheKey.'_lock'); } } RedisService::clear($cacheKey); return ['count'=> count($orders),'success'=> $success, 'delivery'=>$deliverCount]; } /** * 售后订单自动处理 * @return array|false */ public function updateOrderRefundStatus() { set_time_limit(0); $cacheKey = "cache:orders:update_lock"; if(RedisService::get($cacheKey)){ $this->error = 3001; return false; } $page = RedisService::get('caches:orders:update_page'); $page = $page? $page+1 : 1; $catchNum = ConfigService::make()->getConfigByCode('update_order_num',100); $pageSize = $catchNum>10 && $catchNum<=200? $catchNum : 100; $orders = OrderGoodsModel::from('orders_goods as a') ->leftJoin('orders as b','b.order_no','=','a.order_no') ->whereIn('a.refund_status',[1,2]) ->where(['a.mark'=>1]) ->select(['b.id','b.user_id','b.order_no','b.out_order_no','a.refund_status','a.goods_id','a.plat_after_no','b.status','a.goods_id','a.sku_sn']) ->orderBy('create_time','asc') ->offset(($page-1)*$pageSize) ->limit($pageSize) ->get(); $orders = $orders? $orders->toArray() : []; RedisService::set($cacheKey, $orders, rand(30,60)); $success = 0; $refundCount = 0; if($orders){ foreach ($orders as $item){ $orderId = isset($item['id'])? $item['id'] : 0; $goodsId = isset($item['goods_id'])? $item['goods_id'] : 0; $orderNo = isset($item['order_no'])? $item['order_no'] : ''; $outOrderNo = isset($item['out_order_no'])? $item['out_order_no'] : ''; $platAfterNo = isset($item['plat_after_no'])? $item['plat_after_no'] : ''; if(empty($orderNo) || empty($outOrderNo) || empty($platAfterNo)){ continue; } $lockCacheKey = "caches:orders:refund:{$orderNo}_{$platAfterNo}"; if(RedisService::get($lockCacheKey.'_lock')){ continue; } $data = [ 'out_order_no'=> $outOrderNo, 'third_order_no'=> $orderNo, ]; $result = SupplyService::make()->getApiData('getAfterStatus', $data); if(empty($result)){ RedisService::clear($lockCacheKey.'_lock'); continue; } $orderStatus = isset($result['status'])? $result['status'] : 0; $goodsSkuSn = isset($result['goods_sku']) && $result['goods_sku']? $result['goods_sku'] : ''; // 售后中 if(in_array($orderStatus,[2,4,5,6])){ if(OrderGoodsModel::where(['plat_after_no'=> $platAfterNo])->update(['refund_status'=>$orderStatus,'update_time'=>time()])){ $refundCount++; } } // 已完成 else if(in_array($orderStatus,[3])) { if($this->refundConfirm(0,['order_id'=> $orderId,'goods_id'=>$goodsId,'plat_after_no'=>$platAfterNo])){ $success++; } } RedisService::clear($lockCacheKey.'_lock'); } } RedisService::clear($cacheKey); return ['count'=> count($orders),'success'=> $success, 'refund'=>$refundCount]; } }