// +---------------------------------------------------------------------- namespace App\Services\Common; use App\Models\ActionLogModel; use App\Models\OrderModel; use App\Services\BaseService; use App\Services\MpService; use App\Services\RedisService; use Illuminate\Support\Facades\DB; /** * 订单管理-服务类 * @author laravel开发员 * @since 2020/11/11 * Class OrderService * @package App\Services\Common */ 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) { $query = $this->model->where('mark', 1); // 企业筛选 if (isset($params['store_id']) && $params['store_id'] > 0) { $query->where('store_id', $params['store_id']); } // 会议 if (isset($params['meeting_id']) && $params['meeting_id'] > 0) { $query->where('meeting_id', $params['meeting_id']); } // 用户筛选 if (isset($params['user_id']) && $params['user_id'] > 0) { $query->where('user_id', $params['user_id']); } // 状态筛选 if (isset($params['status']) && $params['status'] > 0) { $query->where('status', $params['status']); } // 退款状态筛选 if (isset($params['refund_status']) && $params['refund_status'] > 0) { $query->where('refund_status', $params['refund_status']); } // 单号 if (isset($params['order_no']) && $params['order_no']) { $keyword = $params['order_no']; $query->where(function ($q) use ($keyword) { $q->where('order_no', 'like', '%' . $keyword . '%') ->orWhere('transaction_id', 'like', '%' . $keyword . '%'); }); } // 时间 if (isset($params['date']) && $params['date']) { $date = $params['date']; $start = $date[0] ?? ''; $end = $date[1] ?? ''; if ($start) { $query->where('create_time', '>=', strtotime($start)); } if ($end && $start < $end) { $query->where('create_time', '<=', strtotime($end)); }else if ($end && $start == $end) { $query->where('create_time', '<', strtotime($end)+86400); } } // 关键词搜索(订单号、商品名称、收货人手机) if (isset($params['keyword']) && $params['keyword']) { $keyword = $params['keyword']; $query->where(function ($q) use ($keyword) { $q->where('receiver_name', 'like', '%' . $keyword . '%') ->orWhere('receiver_mobile', 'like', '%' . $keyword . '%') ->orWhereHas('user', function ($q1) use ($keyword) { $q1->where('mobile', 'like', '%' . $keyword . '%'); }) ->orWhereHas('orderGoods', function ($q2) use ($keyword) { $q2->where('goods_name', 'like', '%' . $keyword . '%'); }); }); } $query1 = clone $query; $query2 = clone $query; $query3 = clone $query; $query4 = clone $query; $counts = [ 'total' => $query1->count('id'), 'totalAmount' => $query2->where(['status'=>4])->sum('pay_total'), 'pending' => $query3->whereIn('status',[1,2])->count('id'), 'complete' => $query4->where(['status'=>4])->count('id'), ]; $list = $query->with(['user', 'orderGoods', 'store','meeting']) ->orderBy('create_time', 'desc') ->orderBy('id', 'desc') ->paginate($pageSize); $list = $list ? $list->toArray() : []; if ($list && isset($list['data'])) { foreach ($list['data'] as &$item) { $item['create_time'] = $item['create_time'] ? date('Y-m-d H:i:s', strtotime($item['create_time'])) : ''; $item['update_time'] = $item['update_time'] ? date('Y-m-d H:i:s', strtotime($item['update_time'])) : ''; $item['user'] = $item['user'] ?? []; $item['store'] = $item['store'] ?? []; $item['meeting'] = $item['meeting'] ?? []; // 获取第一个商品信息(thumb已通过Model访问器处理) $item['goods'] = isset($item['order_goods'][0]) ? $item['order_goods'][0] : null; $item['real_total'] = $item['pay_total']; $item['pay_total'] = moneyFormat($item['pay_total'] + $item['delivery_fee'], 2); //$item['refund_amount'] = $item['refund_amount']?$item['refund_amount']:$item['pay_total']; } } return [ 'msg' => '操作成功', 'code' => 0, 'data' => $list['data'] ?? [], 'count' => $list['total'] ?? 0, 'counts' => $counts, ]; } /** * 获取订单详情 */ public function getInfo($id) { $info = $this->model->where('id', $id)->where('mark', 1) ->with(['user', 'orderGoods', 'store','meeting','commissions']) ->first(); if (!$info) { return ['code' => 1, 'msg' => '订单不存在']; } $info = $info->toArray(); $info['create_time'] = $info['create_time'] ? date('Y-m-d H:i:s', strtotime($info['create_time'])) : ''; $info['update_time'] = $info['update_time'] ? date('Y-m-d H:i:s', strtotime($info['update_time'])) : ''; $info['real_total'] = $info['pay_total']; $info['pay_total'] = moneyFormat($info['pay_total'] + $info['delivery_fee'], 2); if (isset($info['order_goods'])) { foreach ($info['order_goods'] as &$goods) { $goods['thumb'] = $goods['thumb'] ? get_image_url($goods['thumb']) : ''; $goods['create_time'] = $goods['create_time'] ? date('Y-m-d H:i:s', strtotime($goods['create_time'])) : ''; $goods['update_time'] = $goods['update_time'] ? date('Y-m-d H:i:s', strtotime($goods['update_time'])) : ''; } } return ['code' => 0, 'msg' => '操作成功', 'data' => $info]; } /** * 查询 * @param $params * @return \Illuminate\Database\Eloquent\Builder */ public function getQuery($params) { $where = ['a.mark' => 1]; $userId = isset($params['user_id']) ? $params['user_id'] : 0; return $this->model->with(['user', 'goods'])->from('orders as a') ->leftJoin('member as b', 'a.user_id', '=', 'b.id') ->leftJoin('goods as c', 'c.id', '=', 'a.goods_id') ->where($where) ->where(function ($query) use ($params) { $keyword = isset($params['keyword']) ? $params['keyword'] : ''; if ($keyword) { $query->where('a.order_no', 'like', "%{$keyword}%"); } // 接单人 $account = isset($params['account']) ? $params['account'] : ''; if ($account) { $query->where(function ($query) use ($account) { $query->where('b.nickname', 'like', "%{$account}%")->orWhere('b.mobile', 'like', "%{$account}%"); }); } // 商品 $goodsId = isset($params['goods_id']) ? intval($params['goods_id']) : 0; $goods = isset($params['goods']) ? trim($params['goods']) : ''; if ($goods) { $query->where(function ($query) use ($goods) { $query->where('c.goods_name', 'like', "%{$goods}%"); if (preg_match("/^(1[0-9]+|[1-9]+)$/", $goods)) { $query->where('a.goods_id', intval($goods)); } else { $query->where('c.goods_name', 'like', "%{$goods}%"); } }); } if ($goodsId > 0) { $query->where('a.goods_id', intval($goodsId)); } }) ->where(function ($query) use ($params) { $status = isset($params['status']) ? $params['status'] : 0; if ($status == 0) { $query->whereIn('a.status', [2, 3]); } else if ($status) { $query->where('a.status', $status); } }) ->where(function ($query) use ($userId) { if ($userId) { $query->where('a.user_id', '=', $userId); } }); } /** * 添加或编辑 * @return array * @since 2020/11/11 * @author laravel开发员 */ public function edit() { $params = request()->post(); return parent::edit($params); // TODO: Change the autogenerated stub } /** * 删除订单 */ public function delete() { $id = request()->post('id'); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } if (is_array($id)) { $result = $this->model->whereIn('id', $id)->update(['mark' => 0]); } else { $result = $this->model->where('id', $id)->update(['mark' => 0]); } if ($result) { ActionLogModel::setTitle("删除订单"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => '删除成功']; } return ['code' => 1, 'msg' => '删除失败']; } /** * 更新订单状态 */ public function status() { $id = request()->post('id'); $status = request()->post('status'); $refundStatus = request()->post('refund_status'); $refundRemark = request()->post('refund_remark', ''); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } $updateData = ['update_time' => time()]; // 更新订单状态 if ($status !== null) { $updateData['status'] = $status; // 如果是完成订单,计算佣金 if ($status == 4) { $order = $this->model->find($id); if ($order) { $updateData['bonus'] = round($order->pay_total * 0.05, 2); } } } // 更新退款状态 if ($refundStatus !== null) { $updateData['refund_status'] = $refundStatus; $updateData['refund_remark'] = $refundRemark; // 如果同意退款,保持原订单状态不变 // 退款状态通过 refund_status 字段管理 } $result = $this->model->where('id', $id)->update($updateData); if ($result !== false) { ActionLogModel::setTitle("更新订单状态"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => '操作成功']; } return ['code' => 1, 'msg' => '操作失败']; } /** * 完成支付 */ public function completePay() { $id = request()->post('id'); $transactionId = request()->post('transaction_id', ''); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } $order = $this->model->find($id); if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } if ($order->status != 1) { return ['code' => 1, 'msg' => '订单状态不正确']; } $updateData = [ 'status' => 2, // 已付款 'transaction_id' => $transactionId ?: 'PAY' . time() . rand(1000, 9999), 'pay_at' => date('Y-m-d H:i:s'), 'remark' => '人工审核支付', 'update_time' => time() ]; $result = $this->model->where('id', $id)->update($updateData); if ($result) { ActionLogModel::setTitle("订单完成支付"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => '支付完成']; } return ['code' => 1, 'msg' => '操作失败']; } /** * 获取小程序快递公司列表 * @return array */ public function getDeliveryList() { $deliveryType = \App\Services\ConfigService::make()->getConfigByCode('delivery_type',1); $cacheKey = "caches:orders:deliveryList_{$deliveryType}"; $datas = RedisService::get($cacheKey); if($datas){ return ['code' => 0, 'msg' =>'获取成功', 'data'=>$datas]; } if($deliveryType==1){ $deliveryList = []; $result = MpService::make()->requestApi('getDelivery'); $list = isset($result['delivery_list'])?$result['delivery_list'] : []; if($list){ foreach ($list as $item){ $deliveryList[$item['delivery_id']] = $item; } }else{ $deliveryList = config('platform.mpDeliveryList'); } RedisService::set($cacheKey, $deliveryList, rand(3600, 7200)); }else{ $deliveryList = config('platform.deliveryList'); } return ['code' => 0, 'msg' =>'获取成功', 'data'=>$deliveryList]; } /** * 订单发票上传 */ public function ticketOrder() { $id = request()->post('id'); $ticketImg = request()->post('ticket_img', ''); if (!$id || empty($ticketImg)) { return ['code' => 1, 'msg' => '参数错误']; } $order = $this->model->with(['user','orderGoods'])->find($id); if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } if ($order->status == 1) { return ['code' => 1, 'msg' => '订单状态不正确,只有已付款订单可以上传发票']; } $this->model->where(['id'=> $id])->update(['ticket_img'=>get_image_path($ticketImg)]); return ['code' => 0, 'msg' => '上传成功']; } /** * 订单发货 */ public function deliverOrder() { $id = request()->post('id'); $deliveryCompany = request()->post('delivery_company', ''); $deliveryNo = request()->post('delivery_no', ''); $deliveryCode = request()->post('delivery_code', ''); if (!$id || empty($deliveryCode)) { return ['code' => 1, 'msg' => '参数错误']; } // 发货方式 $deliveryType = \App\Services\ConfigService::make()->getConfigByCode('delivery_type',1); $order = $this->model->with(['user','orderGoods'])->find($id); $orderGoods = isset($order['orderGoods'])?$order['orderGoods'] : []; $goodsName = isset($orderGoods[0]['goods_name'])?$orderGoods[0]['goods_name']:'订单商品'; $goodsNum = isset($orderGoods[0]['num']) && $orderGoods[0]['num']?$orderGoods[0]['num']: 1; $goodsUnit = isset($orderGoods[0]['unit']) && $orderGoods[0]['unit']?$orderGoods[0]['unit']: '个'; $userInfo = isset($order['user'])?$order['user'] : []; $openid = isset($userInfo['openid'])?$userInfo['openid'] : ''; $mobile = isset($userInfo['mobile'])?$userInfo['mobile'] : ''; if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } if ($order->status != 2) { return ['code' => 1, 'msg' => '订单状态不正确,只有已付款订单可以发货']; } if (!$deliveryNo) { return ['code' => 1, 'msg' => '请填写快递单号']; } $updateData = [ 'status' => 3, // 已发货 'delivery_company' => $deliveryCompany, 'delivery_no' => $deliveryNo, 'delivery_code' => $deliveryCode, 'update_time' => time() ]; if (!$result = $this->model->where('id', $id)->update($updateData)) { return ['code' => 1, 'msg' => '操作失败']; } // 调用小程序发货信息同步接口 $msg = '发货成功'; if($deliveryType == 1 && $openid){ $sendData = [ 'order_key' => [ "order_number_type" => 2, "transaction_id" => isset($order['transaction_id']) ? $order['transaction_id'] : '', "out_trade_no" => isset($order['out_trade_no']) ? $order['out_trade_no'] : '' ], "delivery_mode" => 1, "logistics_type" => 1, "shipping_list" => [ [ "tracking_no" => $deliveryNo, "express_company" => $deliveryCompany, "item_desc" => $goodsName."*".$goodsNum.$goodsUnit, "contact" => [ "receiver_contact" => isset($order['receiver_mobile']) && $order['receiver_mobile'] ? format_mobile($order['receiver_mobile']) : format_mobile($mobile) ] ] ], "upload_time" => date('Y-m-d\TH:i:s.vP'), "payer" => [ "openid" => $openid ] ]; $result = MpService::make()->requestApi('deliverySend',$sendData); $errcode = isset($result['errcode'])?$result['errcode'] : -1; $errmsg = isset($result['errmsg']) && $result['errmsg']?$result['errmsg'] : '请求失败'; if($errcode != 0){ $msg = '发货成功,但上传发货信息到小程序失败:'.$errmsg; }else { $msg = '发货成功,上传发货信息到小程序成功'; } } if ($result) { ActionLogModel::setTitle("订单发货"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => $msg]; } return ['code' => 1, 'msg' => '操作失败']; } /** * 订单完成(管理后台) */ public function completeOrder() { $id = request()->post('id'); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } $order = $this->model->find($id); if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } if ($order->status != 3) { return ['code' => 1, 'msg' => '订单状态不正确,只有已发货订单可以完成']; } // 调用用户端的订单完成方法,触发收益结算等业务逻辑 $apiOrderService = \App\Services\Api\OrderService::make(); $result = $apiOrderService->complete($order->user_id, $id); if ($result) { ActionLogModel::setTitle("订单完成"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => '确认收货成功']; } // 获取错误信息 $error = $apiOrderService->getError(); return ['code' => 1, 'msg' => $error ?: '操作失败', 'error' => $error]; } /** * 取消订单 */ public function cancelOrder() { $id = request()->post('id'); $cancelReason = request()->post('cancel_reason', ''); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } $order = $this->model->find($id); if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } if ($order->status != 1) { return ['code' => 1, 'msg' => '只有待付款订单可以取消']; } $updateData = [ 'mark' => 0, // 标记为删除 'update_time' => time() ]; $result = $this->model->where('id', $id)->update($updateData); if ($result) { ActionLogModel::setTitle("取消订单"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => '订单已取消']; } return ['code' => 1, 'msg' => '操作失败']; } /** * 申请退款 */ public function applyRefund() { $id = request()->post('id'); $afterType = request()->post('after_type', 2); // 默认退款 $afterRealname = request()->post('after_realname', ''); $afterPhone = request()->post('after_phone', ''); $afterRemark = request()->post('after_remark', ''); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } if (!$afterRealname) { return ['code' => 1, 'msg' => '请填写联系人姓名']; } if (!$afterPhone) { return ['code' => 1, 'msg' => '请填写联系电话']; } if (!$afterRemark) { return ['code' => 1, 'msg' => '请填写退款原因']; } $order = $this->model->find($id); if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } // 只有已付款、已发货、已完成的订单可以申请退款 if (!in_array($order->status, [2, 3, 4])) { return ['code' => 1, 'msg' => '该订单状态不允许申请退款']; } if ($order->refund_status != 0) { return ['code' => 1, 'msg' => '该订单已申请过退款']; } $updateData = [ 'refund_status' => 3, // 待审核 'after_type' => $afterType, // 1-售后,2-退款 'after_realname' => $afterRealname, 'after_phone' => $afterPhone, 'after_remark' => $afterRemark, 'update_time' => time() ]; $result = $this->model->where('id', $id)->update($updateData); if ($result) { $typeText = $afterType == 1 ? '售后' : '退款'; ActionLogModel::setTitle("申请{$typeText}"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => "{$typeText}申请已提交"]; } return ['code' => 1, 'msg' => '操作失败']; } /** * 同意退款(审核通过,状态变为已审核) */ public function agreeRefund() { $id = request()->post('id'); $refundRemark = request()->post('refund_remark', ''); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } $order = $this->model->find($id); if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } if ($order->refund_status != 3) { return ['code' => 1, 'msg' => '该订单未申请退款或已处理']; } $updateData = [ 'refund_status' => 2, // 已审核(待确认退款) 'refund_remark' => $refundRemark ?: '退款申请已通过,待确认退款', 'update_time' => time() ]; $result = $this->model->where('id', $id)->update($updateData); if ($result) { ActionLogModel::setTitle("同意退款"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => '已同意退款,请确认退款']; } return ['code' => 1, 'msg' => '操作失败']; } /** * 确认退款(最终完成退款) */ public function confirmRefund() { $id = request()->post('id'); $refundAmount = request()->post('refund_amount', 0); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } if ($refundAmount <= 0) { return ['code' => 1, 'msg' => '请输入退款金额']; } $order = $this->model->find($id); if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } // 允许待审核(3)和已审核(2)状态的订单进行退款 if (!in_array($order->refund_status, [2, 3])) { return ['code' => 1, 'msg' => '该订单状态不允许退款']; } if ($refundAmount > floatval($order->pay_total + $order->delivery_fee)) { return ['code' => 1, 'msg' => '退款金额不能大于订单支付金额']; } // 使用事务 DB::beginTransaction(); try { // 调用支付服务退款 $paymentService = \App\Services\PaymentService::make(); $refundData = [ 'money' => $refundAmount, 'pay_type' => $order->pay_type, 'order_no' => $order->order_no, 'out_trade_no' => $order->out_trade_no, 'transaction_id' => $order->transaction_id, 'remark' => '订单退款' ]; $refundResult = $paymentService->refund($refundData, 'store'); if (!$refundResult) { DB::rollBack(); return ['code' => 1, 'msg' => '退款失败:' . $paymentService->getError() ?: '退款失败']; } // 更新订单状态 $updateData = [ 'refund_status' => 1, // 已退款 'refund_amount' => $refundAmount, 'update_time' => time() ]; $result = $this->model->where('id', $id)->update($updateData); if ($result) { DB::commit(); ActionLogModel::setTitle("确认退款"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => '退款成功']; } DB::rollBack(); return ['code' => 1, 'msg' => '更新订单状态失败']; } catch (\Exception $e) { DB::rollBack(); return ['code' => 1, 'msg' => '退款失败:' . $e->getMessage()]; } } /** * 拒绝退款 */ public function rejectRefund() { $id = request()->post('id'); $refundRemark = request()->post('refund_remark', ''); if (!$id) { return ['code' => 1, 'msg' => '参数错误']; } if (!$refundRemark) { return ['code' => 1, 'msg' => '请填写拒绝原因']; } $order = $this->model->find($id); if (!$order) { return ['code' => 1, 'msg' => '订单不存在']; } if ($order->refund_status != 3) { return ['code' => 1, 'msg' => '该订单未申请退款或已处理']; } $updateData = [ 'refund_status' => 4, // 审核驳回 'refund_remark' => $refundRemark, 'update_time' => time() ]; $result = $this->model->where('id', $id)->update($updateData); if ($result) { ActionLogModel::setTitle("拒绝退款"); ActionLogModel::record(); RedisService::keyDel("caches:orders:*"); return ['code' => 0, 'msg' => '已拒绝退款']; } return ['code' => 1, 'msg' => '操作失败']; } /** * 订单统计 * @param int $storeId 商户ID,0表示平台管理员查看全部数据 */ public function getStatistics($storeId = 0) { $params = request()->all(); $meetingId = isset($params['meeting_id'])?$params['meeting_id']:0; $userId = isset($params['user_id'])?$params['user_id']:0; $sid = isset($params['store_id'])?$params['store_id']:0; $storeId = $storeId?$storeId:$sid; // 总订单数 $total = $this->model->where('mark', 1) ->where(function ($query) use ($storeId,$meetingId,$userId) { if($storeId){ $query->where('store_id', $storeId); } if($meetingId){ $query->where('meeting_id', $meetingId); } if($userId){ $query->where('user_id', $userId); } }) ->count(); // 总交易额(已完成订单) $totalAmount = $this->model->where('mark', 1) ->where('status', 4) ->where(function ($query) use ($storeId,$meetingId,$userId) { if($storeId){ $query->where('store_id', $storeId); } if($meetingId){ $query->where('meeting_id', $meetingId); } if($userId){ $query->where('user_id', $userId); } }) ->sum('pay_total'); // 待处理订单(待付款 + 已付款) $pending = $this->model->where('mark', 1) ->whereIn('status', [1, 2]) ->where(function ($query) use ($storeId,$meetingId,$userId) { if($storeId){ $query->where('store_id', $storeId); } if($meetingId){ $query->where('meeting_id', $meetingId); } if($userId){ $query->where('user_id', $userId); } }) ->count(); // 已完成 $complete = $this->model->where('mark', 1) ->where('status', 4) ->where(function ($query) use ($storeId,$meetingId,$userId) { if($storeId){ $query->where('store_id', $storeId); } if($meetingId){ $query->where('meeting_id', $meetingId); } if($userId){ $query->where('user_id', $userId); } }) ->count(); return [ 'code' => 0, 'msg' => '操作成功', 'data' => [ 'total' => $total, 'totalAmount' => number_format($totalAmount, 2, '.', ''), 'pending' => $pending, 'complete' => $complete ] ]; } }