123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- <?php
- namespace app\common\service;
- use think\Cache;
- use think\Db;
- use think\Log;
- use app\common\model\Orders;
- use app\common\traits\ServiceTrait;
- use think\Exception;
- class OrderService
- {
- use ServiceTrait;
- /** @var Orders */
- public static $Model = Orders::class;
- const LOCK_ORDER_PREFIX = 'lock_order_cache:'; //重复创建订单锁
- //订单状态
- const ORDER_STATUS_NO = 0; //关闭
- const ORDER_STATUS_WAIT_PAY = 10; //待付款
- const ORDER_STATUS_WAIT_SHIP = 20; //已支付(待发货)
- const ORDER_STATUS_SHIPPED = 30; //已发货(待收货)
- const ORDER_STATUS_FAILED = 31; //交易失败
- const ORDER_STATUS_TIMEOUT = 33; //订单超时
- const ORDER_STATUS_FINISHED = 40; //已完成
- const ORDER_STATUS_CANCEL = 50; //已取消
- const ORDER_STATUS_REFUNDED = 60; //已退款
- const ORDER_STATUS_MAP = [
- self::ORDER_STATUS_NO => '订单关闭',
- 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, 'order_type' => self::ORDER_TYPE_SOFTWARE])->field('order_status, COUNT(*) as total')
- ->group('order_status')
- ->select();
- foreach ($orderCountList as &$value) {
- if ($value['tabType'] == OrderService::ORDER_STATUS_FINISHED) {
- continue;
- }
- 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);
- });
- }
- }
|