WeChatController.php 8 KB
<?php

namespace App\Http\Controllers\Api\Customers;

use App\Common\Enums\HtTab;
use App\Exceptions\Api\ApiException;
use App\Http\Controllers\Controller;

use App\Modules\Enums\WebsocketType;
use App\Modules\Onenet\Facades\Onenet;
use App\Modules\Util\PushUtil;
use App\Repositories\Customers\MachineRepository;
use App\Repositories\Customers\PowerRepository;
use App\Repositories\Customers\RentRepository;
use App\Repositories\Customers\WeChatRepository;
use App\Repositories\Customers\WeGuideRepository;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Yansongda\LaravelPay\Facades\Pay;
use Yansongda\Pay\Exceptions\GatewayException;
use Yansongda\Pay\Exceptions\InvalidSignException;
use App\Repositories\Customers\ProductionRepository;
/**
 * Class RentController
 * @package App\Http\Controllers\Api
 */
class WeChatController extends Controller
{
    /**
     * @var RentRepository
     */
    protected $weChat;

    protected $weGuide;
    protected $rent;
    protected $machine;
    protected $production;
//    protected $power;
    public function __construct(WeChatRepository $weChat, WeGuideRepository $weGuide, RentRepository $rent, PowerRepository $power, MachineRepository $machine, ProductionRepository $production)
    {
        $this->weChat = $weChat;
        $this->weGuide = $weGuide;
        $this->rent = $rent;
        $this->power = $power;
        $this->machine = $machine;
        $this->production = $production;
    }

    function wePayCallBack(Request $request)
    {
        Log::info("[wePayCallBack]params:" . file_get_contents("php://input"));
        $weChat = Pay::wechat();
        try {
            $data = $weChat->verify(); // 是的,验签就这么简单!
            Log::info("[wePayCallBack]params:" . json_encode($data->all()));
        } catch (GatewayException $e) {
            Log::info("[wePayCallBack]Exception:" . $e->getMessage());
            exit;
            // $e->getMessage();
        } catch (InvalidSignException $e) {
            Log::info("[wePayCallBack]Exception:" . $e->getMessage());
            exit;
        }
        //处理业务
        $attach = json_decode($data->get('attach'), true);
        $out_trade_no = $data->get('out_trade_no');

        switch ($attach['type']) {
            case 1:
                try {
                    $this->rentShipment($out_trade_no);
                } catch (ApiException $e) {
                    Log::info("[wechatGuidePayCallBack]Exception:" . $e->getMessage());
                }
                break;
            case 2:
                try {
                    $this->weGuide->paySuccess($out_trade_no);
                } catch (ApiException $e) {
                    Log::info("[wechatGuidePayCallBack]Exception:" . $e->getMessage());
                }
                break;
            default:
                break;
        }
        echo $weChat->success()->getContent();
        exit;
    }

    public function testPayCallBack(Request $request)
    {
        $rent_no = $request->get('rent_no');
        $this->rentShipment($rent_no);
    }

    public function rentShipment($rent_no)
    {
        $rent_obj = $this->rent->getNoPayRent($rent_no);

        //并发情况逐个处理 等待3秒,防止数据混乱
        $time = 0;
        while ($time < 3) {
            $lock = Redis::setnx(HtTab::RENT_SALE_LOCK . '_' . $rent_obj->machine_id, date("Y-m-d H:i:s"));
            if ($lock == 1) {
                Redis::expire(HtTab::RENT_SALE_LOCK . '_' . $rent_obj->machine_id, 3);
                break;
            }
            $time++;
            sleep(1);
        }
        $rent_obj = $this->rent->makeRentPayed($rent_obj);
        $powers = $this->rent->getSomePowers($rent_obj->machine_id, $rent_obj->number, $rent_obj->power_type);
        if (!$powers) {
            //退款
            $refund_no = $this->weChat->rentRefund($rent_obj);
            $this->rent->makeOrderRefunded($rent_obj, $refund_no);
            if ($rent_obj->rent_type == 2) {
                //通知客户端预约失败
                $data = [
                    'type' => WebsocketType::SUBSCRIBE_FAIL,
                ];
                PushUtil::pushWebsocketMessage($rent_obj->customer_id, $data);
                $this->weChat->subscribeFailMes($rent_obj);
            }elseif($rent_obj->rent_type == 1){
                $this->weChat->rentFailMes($rent_obj);
            }
            return false;
        }
        //处理账户金额变动
        $this->rent->changeCustomerDeposit(1, $rent_obj->customer_id, $rent_obj->deposit * $rent_obj->number);
        //录入订单情况
        $this->rent->makeOrderDetail($rent_obj, $powers);
        //修改充电宝状态
        $this->power->makePowerStatusSaled($powers);

        //设置同游共听分享
        //发放微导览服务
        $this->weGuide->provideGuideService($rent_obj->customer_id, $rent_obj->spot_id, 1, $rent_obj->rent_no);
        //设置分享权限
        $this->weGuide->provideShareService($rent_obj, 1);
        //设置 onenet 返回值
        $resOnnet = true;
        //通知onenet发货
        if ($rent_obj->rent_type == 1) {
            //标记订单已经取货
            $this->rent->makeRentTaked($rent_obj);

            $machine_obj = $this->machine->get($rent_obj->machine_id);
            Log::info("[onenet_open]:" . json_encode(array_column($powers, 'hatch_no')));

            //---------多租接口-----start------
//            $resOnnet = Onenet::openMultiple($machine_obj, $rent_obj->id, array_column($powers, 'hatch_no'));
            //---------多租接口-----end------

            //---------租借一个接口------start---------
            $arr = array_column($powers, 'hatch_no');
            $resOnnet = Onenet::open($machine_obj, $rent_obj->id, $arr[0]);
            //---------租借一个接口------end---------

            $this->weChat->rentSuccessMes($rent_obj);

        } else {
            $this->weChat->subscribeSuccessMes($rent_obj);

            //通知客户端预约成功
            $data = [
                'type' => WebsocketType::SUBSCRIBE_SUCCESS,
            ];
            PushUtil::pushWebsocketMessage($rent_obj->customer_id, $data);
        }
        //onenet 请求失败
        if(!$resOnnet){
            $this->orderExpire($rent_obj->id);

        }
        //处理完成释放锁
        Redis::del(HtTab::RENT_SALE_LOCK . '_' . $rent_obj->machine_id);


        return true;
    }

    public function orderExpire($order_id)
    {
        Log::info("[onenetFail] params:" . json_encode(['order_id'=>$order_id]));

        $rent_obj = $this->rent->getRentDetail($order_id);

        $success_hatchs = [];
        $fail_hatchs = [];
        foreach ($rent_obj->production as $production) {
            if ($production->is_out) {
                //发货成功
                $success_hatchs[] = $production->rent_hatch_no;
            } else {
                //发货失败
                $fail_hatchs[] = $production->rent_hatch_no;
                $refound_no = $this->production->makeProductionRefund($production);
                $this->weChat->productOutFailRefund($rent_obj, $refound_no);
                $rent_obj->back_money += $rent_obj->deposit;
            }

        }

        if ($rent_obj->back_money) {
            $rent_obj->save();
        }

        //处理账户金额变动
        $this->rent->changeCustomerDeposit(2, $rent_obj->customer_id, $rent_obj->deposit * count($fail_hatchs));
        //通知workman

        if ($fail_hatchs) {
            $data = [
                'type' => WebsocketType::POWER_TAKE_OUT_FAIL,
                'success_hatch_nos' => $success_hatchs,
                'fail_hatch_nos' => $fail_hatchs,
            ];
            PushUtil::pushWebsocketMessage($rent_obj->customer_id, $data);
        }

        //取货结果通知
        $this->weChat->shipmentMes($rent_obj,$success_hatchs);

        //标记订单已处理
        $this->rent->expireHandleStatusChange($rent_obj,$fail_hatchs);

        return $this->responseSuccess();

        //check order status
    }

}