'订单关闭', self::ORDER_STATUS_WAIT_PAY => '待支付', self::ORDER_STATUS_WAIT_SHIP => '待发货', self::ORDER_STATUS_SHIPPED => '已发货', self::ORDER_STATUS_FAILED => '交易失败', self::ORDER_STATUS_TIMEOUT => '订单超时', self::ORDER_STATUS_CANCEL => '用户取消订单', self::ORDER_STATUS_FINISHED => '交易完成', self::ORDER_STATUS_REFUNDED => '已退款', ]; // 订单操作按钮 const BUTTON_PAY = 1; // 付款 const BUTTON_CANCEL = 2; // 取消订单 const BUTTON_CONFIRM = 3; // 确认收货 const BUTTON_APPLY_REFUND = 4; // 申请售后 const BUTTON_VIEW_REFUND = 5; // 查看退款 const BUTTON_COMMENT = 6; // 评价 const BUTTON_DELETE = 7; // 删除订单 const BUTTON_DELIVERY = 8; // 查看物流 const BUTTON_REBUY = 9; // 再次购买 const BUTTON_INVITE_GROUPON = 11; //邀请好友拼团 const BUTTON_MAP = [ self::BUTTON_PAY => '付款', // 付款 self::BUTTON_CANCEL => '取消订单', // 取消订单 self::BUTTON_CONFIRM => '确认收货', // 确认收货 self::BUTTON_APPLY_REFUND => '申请售后', // 申请售后 self::BUTTON_VIEW_REFUND => '查看退款', // 查看退款 self::BUTTON_COMMENT => '评价', // 评价 self::BUTTON_DELETE => '删除订单', // 删除订单 self::BUTTON_DELIVERY => '查看物流', // 查看物流 self::BUTTON_REBUY => '再次购买', // 再次购买 self::BUTTON_INVITE_GROUPON => '邀请好友拼团', //邀请好友拼团 ]; const ORDER_TYPE_SOFTWARE = 0;//软件产品; const ORDER_TYPE_FIRST_PAYMENT = 1;//首付款款订单; const ORDER_TYPE_FINAL_PAYMENT = 2; //尾款订单; const ORDER_TYPE_MAP = [ self::ORDER_TYPE_SOFTWARE => '软件产品', self::ORDER_TYPE_FIRST_PAYMENT => '需求首付款', self::ORDER_TYPE_FINAL_PAYMENT => '需求尾款', ]; /** * 生成订单 * @param $requestData * @return array * @throws \Exception */ public static function createOrder($requestData) { try { $user = $requestData['userInfo'] ?? []; $userId = $user['id'] ?? 0; $openid = $user['openid'] ?? ''; Log::info('创建订单数据-request:' . json_encode($requestData, JSON_UNESCAPED_UNICODE)); if (empty($requestData['goodsRequestList'])) { throw new \Exception('订单数据错误'); } //如果30秒内有重复数据,直接返回缓存订单,不再创建 $lockOrderKey = self::getLockOrderKey($userId, $requestData); if ($lockOrderRes = Cache::get($lockOrderKey)) { return json_decode($lockOrderRes, true); } $goodsRequestList = $requestData['goodsRequestList']; $count = count($goodsRequestList); if ($count == 0) { Log::error('订单创建失败:商品数量不能为0'); throw new \Exception('订单创建失败:商品数量不能为0'); } $total_amount = 0; $total_quantity = 0; $goodsDataList = []; foreach ($goodsRequestList as $item) { $quantity = max(1, $item['quantity']); $total_quantity += $quantity; $total_amount += $quantity * $item['price']; $goodsDataList[] = [ 'spu_id' => $item['spuId'], 'sku_id' => $item['sku_id'] ?? '', 'goods_name' => $item['goodsName'], 'goods_picture_url' => $item['primaryImage'], 'origin_price' => $item['price'], 'actual_price' => $item['price'], 'buy_quantity' => $quantity, 'item_total_amount' => $item['price'] * $quantity, 'item_discount_amount' => 0, 'item_payment_amount' => $item['price'] * $quantity, 'goods_payment_price' => $item['price'], ]; } $orderData = [ 'user_id' => $userId, 'store_id' => 1, 'order_no' => generate_order_sn(), 'order_status' => OrderService::ORDER_STATUS_WAIT_PAY, 'order_type' => 0, 'total_amount' => $total_amount, 'payment_amount' => $total_amount, 'goods_amount' => $total_quantity, 'discount_amount' => 0, 'remark' => $requestData['storeInfoList'][0]['remark'] ?? '', ]; $existed = OrderService::getOne(['order_no' => $orderData['order_no']]); if (!$existed) { //创建订单及订单商品 $orderRes = self::$Model::create($orderData); Log::info('创建订单数据:' . json_encode($orderData, JSON_UNESCAPED_UNICODE)); if (!$orderRes) { Log::error('创建订单创建失败:' . json_encode($orderData, JSON_UNESCAPED_UNICODE)); throw new \Exception('订单创建失败'); } $goodsRes = $orderRes->orderGoods()->saveAll($goodsDataList); if (!$goodsRes) { Log::error('创建订单产品失败:' . json_encode($orderData, JSON_UNESCAPED_UNICODE)); throw new \Exception('订单创建数据失败'); } } $orderData += [ 'channel' => 'wechat', 'tradeNo' => $orderData['order_no'], 'interactId' => 0, 'transactionId' => 0, 'payInfo' => self::pay($orderData['order_no'], $total_amount, $openid), //统一下单接口 ]; //存入缓存 Cache::set($lockOrderKey, json_encode($orderData), 30); return $orderData; } catch (Exception $e) { throw new \Exception('订单数据保存失败:' . $e->getMessage()); } } /** * 生成需求订单 * @param $requestData * @throws \Exception */ public static function createDemandOrder($requestData) { try { $demandId = $requestData['demandId'] ?? 0; $formData = $requestData['formData'] ?? []; $totalCost = $formData['totalCost'] ?? 0; Log::info('创建需求订单数据-request:' . json_encode($requestData, JSON_UNESCAPED_UNICODE)); $demand = DemandService::getOne(['id' => $demandId]); if (!$demand) { throw new \Exception('该需求不存在'); } $winBid = DemandBiddingService::getOne(['demand_id' => $demandId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN]); $orderInfo = self::where(['parent_order_no' => $demand->parent_order_no])->find(); $ratio = 0.5; //分期比率50% if (!$orderInfo) { $installments = 2;//分期数 for ($i = 1; $i <= $installments; $i++) { $total_amount = $i == 1 ? $totalCost * $ratio : $totalCost * (1 - $ratio); $goodsDataList = [[ 'spu_id' => 0, 'sku_id' => 0, 'goods_name' => '需求签约-' . ($i == 1 ? '首付款' : '尾款') . $demand->parent_order_no, 'goods_picture_url' => 'https://soft-market.oss-cn-shenzhen.aliyuncs.com/images/contract.png', 'origin_price' => $total_amount, 'actual_price' => $total_amount, 'buy_quantity' => 1, 'item_total_amount' => $total_amount, 'item_discount_amount' => 0, 'item_payment_amount' => $total_amount, 'goods_payment_price' => $total_amount, ]]; $orderData = [ 'user_id' => $demand->user_id, 'store_id' => 1, 'parent_order_no' => $demand->parent_order_no, 'order_no' => generate_order_sn(), 'order_status' => OrderService::ORDER_STATUS_WAIT_PAY, 'order_type' => $i, 'total_amount' => $total_amount, 'payment_amount' => $total_amount, 'goods_amount' => $total_amount, 'discount_amount' => 0, 'remark' => '', ]; $existed = OrderService::getOne(['order_no' => $orderData['order_no']]); if (!$existed) { //创建订单及订单商品 $orderRes = self::$Model::create($orderData); Log::info('创建需求订单数据:' . json_encode($orderData, JSON_UNESCAPED_UNICODE)); if (!$orderRes) { Log::error('创建需求订单创建失败:' . json_encode($orderData, JSON_UNESCAPED_UNICODE)); throw new \Exception('需求订单创建失败'); } $goodsRes = $orderRes->orderGoods()->saveAll($goodsDataList); if (!$goodsRes) { Log::error('创建需求订单产品失败:' . json_encode($orderData, JSON_UNESCAPED_UNICODE)); throw new \Exception('需求订单创建数据失败'); } } } } //查找签约记录,没有则创建 $contractInfo = ContractService::getOne(['demand_id' => $demand, 'bidding_id' => $winBid->id ?? 0]); if (!$contractInfo) { //创建合同数据 $firstContract = ContractService::getFirstContract($demandId); $depositAmount = $firstContract ? $firstContract->deposit_amount : $formData['totalCost'] * $ratio; ContractService::createData($demandId, $winBid->id ?? 0, $depositAmount, $formData); } return $contractInfo; } catch (Exception $e) { throw new \Exception('需求订单数据保存失败:' . $e->getMessage()); } } public static function getDemandOrder($parentOrderNo, $contractType) { $res = self::getOne(['parent_order_no' => $parentOrderNo, 'order_type' => $contractType], ['orderGoods', 'orderPayment']); return $res; } public static function orderPay($requestData) { try { $user = $requestData['userInfo'] ?? []; $userId = $user['id'] ?? 0; $openid = $user['openid'] ?? ''; $orderNo = $requestData['orderNo'] ?? ''; if (!$orderNo) { throw new \Exception('订单号不存在'); } $fields = 'user_id,store_id,order_no,order_status,order_type,total_amount,payment_amount,goods_amount,discount_amount,remark'; $orderInfo = OrderService::where(['order_no' => $orderNo, 'user_id' => $userId])->field($fields)->find(); if (!$orderInfo) { throw new \Exception('该订单不存在'); } $orderData = $orderInfo->toArray(); $orderData += [ 'channel' => 'wechat', 'tradeNo' => $orderData['order_no'], 'interactId' => 1, 'transactionId' => 0, 'payInfo' => self::pay($orderInfo->order_no, $orderInfo->total_amount, $openid), //统一下单接口 ]; return $orderData; } catch (Exception $e) { throw new \Exception('订单支付异常:' . $e->getMessage()); } } /** * 订单操作 * @param $request * @return mixed * @throws \Exception */ public static function orderOperate($requestData, $userId) { $goodsInfo = $requestData['goodsInfo'] ?? []; $type = $requestData['type'] ?? ''; switch ($type) { case self::BUTTON_CONFIRM: $res = self::confirmOrder($goodsInfo['id'] ?? 0, $userId); break; case self::BUTTON_CANCEL: $res = self::cancelOrder($goodsInfo['id'] ?? 0, $userId); break; default: throw new \Exception('非法操作'); } return $res; } /** * 取消订单 * @param $order_id * @param $userId * @return mixed * @throws \Exception */ public static function cancelOrder($orderId, $userId = 0) { try { $where = ['id' => $orderId, 'user_id' => $userId]; $order = self::getOne($where); if (!$order) { throw new \Exception('该订单不存在'); } Db::startTrans(); if (!in_array($order->order_status, [OrderService::ORDER_STATUS_WAIT_PAY, OrderService::ORDER_STATUS_WAIT_SHIP])) { throw new \Exception('该订单为' . OrderService::ORDER_STATUS_MAP[$order->order_status] . ',不能取消'); } //修改订单状态 $upRes = self::where($where)->update(['order_status' => OrderService::ORDER_STATUS_CANCEL]); if (!$upRes) { throw new \Exception('更新订单状态失败'); } //退款原路返回 // OrderRefund::dispatch(['order_sn' => $order->order_sn, 'actual_amount' => $order->actual_amount]); //给用户发送出票失败结果通知 // SendMsg::dispatch(['order_id' => $order->id, 'user_id' => $order->user_id, 'template_id' => SubscribeMessageService::MSG_TEMP_ORDER_FAILED, 'desc' => SubscribeMessageService::ORDER_MSG_MAP['failed'], 'desc2' => SubscribeMessageService::ORDER_MSG_MAP['refund']]); Db::commit(); $info = OrderService::getOne(['id' => $orderId]); return $info; } catch (\Exception $e) { Db::rollback(); throw $e; } } /** * 确认收货 * @param $orderId * @param $userId * @return mixed * @throws \Exception */ public static function confirmOrder($orderId, $userId = 0) { try { $where = ['id' => $orderId, 'user_id' => $userId]; $order = self::getOne($where); if (!$order) { throw new \Exception('该订单不存在'); } Db::startTrans(); if (!in_array($order->order_status, [OrderService::ORDER_STATUS_SHIPPED])) { throw new \Exception('该订单为' . OrderService::ORDER_STATUS_MAP[$order->order_status] . ',不能确认收货'); } //修改订单状态 $upRes = self::where($where)->update(['order_status' => OrderService::ORDER_STATUS_FINISHED]); if (!$upRes) { throw new \Exception('更新订单状态失败'); } Db::commit(); $info = OrderService::getOne(['id' => $orderId]); return $info; } catch (\Exception $e) { Db::rollback(); throw $e; } } /** * 微信支付回调 * @param * @return string * @throws \Exception */ public static function payNotify() { $xmlData = file_get_contents('php://input'); $data = ToolService::FromXml($xmlData); Log::info('微信回调信息_request_xml:' . json_encode(['data' => $data, 'xml' => $xmlData])); $order_no = $data['out_trade_no'] ?? ''; //更新订单状态 $orderInfo = OrderService::getOne(['order_no' => $order_no]); self::checkPaySuccess($data, $orderInfo); $res = [ 'return_code' => 'SUCCESS', 'return_msg' => 'OK' ]; $xml = ToolService::ToXml($res); Log::info('微信回调信息信息_result:' . json_encode(['res' => $res, 'xml' => $xml])); //如果为待支付,才可更新为已支付。防止重复更新状态,导致重复发货。 if ($orderInfo->order_status == self::ORDER_STATUS_WAIT_PAY) { $paymentData = [ 'order_no' => $order_no, 'pay_status' => $data['result_code'], 'amount' => $data['total_fee'] / 100, 'currency' => $data['fee_type'], 'pay_type' => '1', // 1微信 2支付宝 'pay_way' => $data['trade_type'], 'trace_no' => $data['transaction_id'], 'pay_time' => time(), 'pay_success_time' => strtotime($data['time_end']), ]; Db::transaction(function () use ($order_no, $paymentData, $orderInfo) { self::where('order_no', $order_no)->update(['order_status' => self::ORDER_STATUS_WAIT_SHIP]); OrderPaymentService::create($paymentData); if ($orderInfo->order_type == 1) { DemandService::customerContractFinishedDeal($orderInfo->parent_order_no); } elseif ($orderInfo->order_type == 2) { DemandService::customerWorkAcceptFinishedDeal($orderInfo->parent_order_no); } }); } return $xml; } /** * @param $data * @param $info * @return void * @throws \Exception */ public static function checkPaySuccess($data, $info) { if ($info) { $checkSign = ToolService::CheckSign($data, $data['sign']); $checkMoney = sprintf("%.1f", $data['total_fee'] / 100) == sprintf("%.1f", $info->payment_amount); //分 $checkResult = $data['result_code'] == 'SUCCESS'; if (!$checkSign) { throw new \Exception('签名错误'); } if (!$checkMoney) { throw new \Exception('金额错误:' . sprintf("%.2f", $data['total_fee'] / 100) . '----' . sprintf("%.2f", $info->payment_amount)); } if (!$checkResult) { throw new \Exception('支付失败'); } } else { throw new \Exception('获取订单数据失败'); } } /** * 获取缓存 * @param $userId * @param $data array * @return mixed */ public static function getLockOrderKey($userId, $data) { $key = self::LOCK_ORDER_PREFIX . md5($userId . json_encode($data)); return $key; } /** * @param $order_sn * @param $total_fee * @param $openid * @param string $body * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string * @throws \Exception */ public static function pay($order_sn, $total_fee, $openid, string $body = '软件产品服务') { if (!($body && $order_sn && $total_fee && $openid)) { throw new \Exception('支付参数错误2'); } $EasyWeChatService = new EasyWeChatService(); $payRes = $EasyWeChatService->unify($body, $order_sn, $total_fee, $openid); if (!($payRes && $payRes['return_code'] == 'SUCCESS' && $payRes['return_msg'] == 'OK')) { throw new \Exception('统一下单接口调用失败'); } $payData = $EasyWeChatService->sdkConfig($payRes['prepay_id']); return $payData; } /** * 获取订单操作按钮 * @param $orderStatus * @return array */ public static function getOrderButtons($orderStatus): array { $buttons = []; if ($orderStatus == self::ORDER_STATUS_WAIT_PAY) { $buttons[] = ['name' => self::BUTTON_MAP[OrderService::BUTTON_CANCEL], 'primary' => false, 'type' => OrderService::BUTTON_CANCEL]; $buttons[] = ['name' => self::BUTTON_MAP[OrderService::BUTTON_PAY], 'primary' => true, 'type' => OrderService::BUTTON_PAY]; } if ($orderStatus == self::ORDER_STATUS_SHIPPED) { $buttons[] = ['name' => self::BUTTON_MAP[OrderService::BUTTON_CONFIRM], 'primary' => true, 'type' => OrderService::BUTTON_CONFIRM]; } return $buttons; } /** * 获取订单统计 * @param $userId * @return array[] */ public static function getOrderCount($userId): array { $orderCountList = [ ['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_WAIT_PAY], ['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_WAIT_SHIP], ['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_SHIPPED], ['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_FINISHED], ['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_REFUNDED], ]; $countList = self::where('user_id', $userId)->field('order_status, COUNT(*) as total') ->group('order_status') ->select(); foreach ($orderCountList as &$value) { foreach ($countList as $item) { if ($item->order_status == $value['tabType']) { $value['orderNum'] = $item->total; } } } return $orderCountList; } /** * 订单发货 * @param $id * @return void * @throws \Exception */ public static function orderShip($id) { Db::transaction(function () use ($id) { $order = OrderService::getOne(['id' => $id], ['orderGoods']); if ($order->order_status != OrderService::ORDER_STATUS_WAIT_SHIP) { exception('订单状态异常,不能发货'); } //查询激活码 $code = SoftCodeService::getAvailableCode(); //生成发货单 OrderShipService::createData($order->order_no, $order->orderGoods[0]->spu_id, $code); $order->order_status = OrderService::ORDER_STATUS_SHIPPED; //修改发货状态 $saveRes = $order->save(); if (!$saveRes) { exception('更新发货状态失败'); } //发送订单发货通知 $msgData = [ 'values' => [ $order->order_no, mb_substr($order->orderGoods[0]->goods_name, 0, 20), '已发货', SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_ORDER_SHIPPED]['remark'], ] ]; (new EasyWeChatService())->sendMsg($order->user_id, SubscribeMessageService::MSG_TEMP_ORDER_SHIPPED, $msgData); }); } }