微信事件推送原理猜想与小程序接口对接经验之谈(即时配送)

小程序即时配送功能开发,引发的猜想。首先即时配送功能是微信小程序刚推出的新功能,接口有很多坑爹的,比如经纬度那些,就要精确到保留到小数点后面10位,文档都没说;如果是小程序第三方开发平台开发的话,调用“替商户开通即时配送权限接口”和”绑定快递功能接口“还要输入第三方的的账号密码,恶心到爆炸,建议有这方面开发需求的开发小伙伴,跳过这2个接口,确实很多坑,我开发遇到过了;比如啥openid未命中,商户不存在,XX的,要开发就一定要使用真实正式数据,不然很头疼的,再说一遍,微信小程序官方文档一定要自己看数据的返回,文档是一堆坑的。

经纬度保留至小数点后10位

'lat'=>sprintf("%1\$.10f",$orderInfo->latitude)

在对接的过程中,发现了一个对接接口的好方式,以后照葫芦画瓢,美滋滋的。数据的处理都写着一个独立的model类中,像这些第三方的接口数据返回对应的中文统一定义成变量,是一个不错的选择。

封装参数,请求接口。

//封装参数:多长都不怕!
 $send_address=[
                'name'=>$send['name'],
                'city'=>$send['address'],  //todo 截取市
                'address'=>$send['address'],
                'address_detail'=>$send['address'],
                'phone'=>$send['phone'],
                'lat'=>sprintf("%1\$.10f",$send['lat']),
                'lng'=>sprintf("%1\$.10f",$send['lng']),
            ];
            //收货人地址
            $receiver=[
                'address'=>$orderInfo->address,
                'address_detail'=>$orderInfo->address,
                'city'=>json_decode($orderInfo->address_data,true)['city'],
                'coordinate_type'=>0,
                'lat'=>sprintf("%1\$.10f",$orderInfo->latitude), //精确到小数点后6位;剩余0补齐到10位
                'lng'=>sprintf("%1\$.10f",$orderInfo->longitude),
                'name'=>$orderInfo->name,
                'phone'=>$orderInfo->mobile];
            //订单信息
            $order_info=[
                'delivery_service_code'=>$config['service_code'],
                'expected_delivery_time'=>time(), //期待时间
                'is_direct_delivery'=> 0,
                'is_finish_code_needed'=> 1,
                'is_insured'=> 0,
                'is_pickup_code_needed'=> 1,
                'note'=> 'test_note',
                'order_time'=> $orderInfo->addtime,
                'order_type'=> 0,
                'poi_seq'=> $poi_seq,
                'tips'=> 0
            ];

            $shop=[
                'goods_count'=>$good_nums,
                'goods_name'=> '默认商品',
                'img_url'=>$pic?:'',
                'wxa_path'=>$page?:'/page/index/index'
            ];
            $cargo=[
                'cargo_first_class'=> '医药健康',
                'cargo_second_class'=> '送药',
                'goods_value'=>$orderInfo->total_price?:0,
                'goods_weight'=> $this->weight,
            ];
            $params = [
                'access_token'=>$token,
                //'shopid'=>$config['appkey'],
                'shopid'=>"test_shop_id",
                'shop_order_id' => $orderInfo->order_no,
                //'shop_no' => $shop_model->encode, //门店编码
                'shop_no' => '11047059', //门店编码
                // 'delivery_sign' => SHA1($config['appkey'].$orderInfo->order_no.$config['secret']),
                'delivery_sign' => SHA1("test_shop_id".$orderInfo->order_no."test_app_secrect"),
                //'delivery_id' => $delivery_arr[$config['name']],
                'delivery_id' =>"TEST",
                'openid' => $open_id->wechat_open_id,
                'sender' => $send_address,
                'receiver'=>$receiver,
                'cargo'=>$cargo,
                'order_info'=>$order_info,
                'shop'=>$shop,
            ];
            //即时配送
            $js=new DcJsForm();
            $res=$js->actionAddDeliveryOrder($params);

请求接口中间过程,这个过程是主要不想数据入库直接弹出显示,看个人需求使用

 /**
     * 第三方代商户发起绑定配送公司帐号的下配送单接口请求地址
     */
    public function actionAddDeliveryOrder($params)
    {
        $code = 0;
        $msg = '';
        $return_data=[];
        $data = $this->addDelivery($params);
        if ($data['resultcode'] == 0 && $data['resultmsg'] == 'ok') {
            $return_data=$data;
            $errmsg = '下单成功';
            $msg .= '【' . $this->store->name . '】' . $errmsg . '<br/>';
        }
        if (isset($data['resultcode']) && $data['resultcode'] == '1010') {
            $code = 1;
            $errmsg = '收件人信息不正确';
            $msg .= '【' . $this->store->name . '】' . $errmsg . '<br/>';
        }
        if (isset($data['errcode']) && $data['errcode'] != 0 && in_array($data['errcode'],array_keys($this->errArr))) {
            $code = 1;
            $errmsg = $this->errArr[$data['errcode']];
            $msg .= '【' . $this->store->name . '】' . $errmsg . '<br/>';
        }
        if (isset($data['errcode']) && $data['errcode'] != 0 && !in_array($data['errcode'],array_keys($this->errArr))) {
            $code = 1;
            $errmsg =$data['resultmsg'];
            $msg .= '【' . $this->store->name . '】' . $errmsg . '<br/>';
        }
        return [
            'code' => $code,
            'data' => $msg ?: '下单成功',
            'return_data'=>$return_data?:[]
        ];
    }

正式请求:

 /**
     * 第三方代商户发起下即时配送单
     * @param int $type
     * @return mixed
     * @throws \Exception
     */
    public function addDelivery($params)
    {
        $url = self::WX_OPENDELIVERY_URL.'/order/add?access_token='.$params['access_token'];
        $data = $this->curlPost($url, $params);
        return $data;
    }


//封装
private function curlPost($url, $data = null, $isJson = true)
    {
        $curl = $this->getCurl();
        $data = $isJson ? json_encode($data, JSON_UNESCAPED_UNICODE) : $data;
        $curl->post($url, $data);
        if ($curl->error_code) {
            throw new \Exception($curl->error_message);
        }
        return json_decode($curl->response, true);
    }

    private function getCurl()
    {
        $curl = new Curl();
        $curl->setOpt(CURLOPT_SSL_VERIFYPEER, false);
        $curl->setOpt(CURLOPT_SSL_VERIFYHOST, false);
        return $curl;
    }

因为这个即时配送会涉及到微信那边的事件推送,因此推送处理!模板消息发送等等一系列的处理,你懂的。

 //处理微信公众号平台转发的事件通知 (这个是配置的推送接收地址!)
    public function actionSyncEvent()
    {
        $param = \Yii::$app->request->post();
        $check = checkSign();

        if (!$check) {
            return new ApiResponse(1, "非法请求", "");
        }

        $data = json_decode(base64_decode($param['data']),true);
        $data_post = base64_decode($param['data_post']);

        if (!$data['ToUserName']) {
            return new ApiResponse(1, "数据格式错误", "");
        }

        $event = new WechatEvents();
        $event->public_id = $data['ToUserName'];
        $event->event = $data['Event'];
        $event->data = json_encode($data);
        $event->data_post = $data_post;
        $event->status = 0;
        $time = time();
        $event->cTime = $time;
        $event->cTime_format = date ( 'Y-m-d H:i:s',$time);
        $event->save();

        return new ApiResponse(0, "转发成功", "");

    }

想想,数据是推送过来了,但是我们怎么触发处理呢?定时任务啥啥的看个人需求罗。

<?php

namespace app\modules\cli\controllers;

use app\controllers\Controller;
use app\models\MsOrder;
use app\models\MsOrderRefund;
use app\models\Order;
use app\models\OrderRefund;
use app\models\PtOrder;
use app\models\PtOrderRefund;
use app\models\Store;
use app\models\WechatApp;
use app\models\WechatTplMsgSender;
use app\modules\cli\models\MessageForm;
use app\models\User;
use app\models\Member;
use app\models\UserMember;
use app\models\Register;
use app\models\WechatEvents;
use app\modules\mch\models\DcEnum;
use app\modules\mch\models\MemberListForm;
use luweiss\wechat\Wechat;


class MessageController extends Controller{

    /**
     * 公众号事件:接收 + 处理
     */
    public function actionIndex(){

        $query = WechatEvents::find()
            ->where(['status' => 0])
            ->andWhere(['in', 'event', ['update_waybill_status','user_get_card', 'submit_membercard_user_info', 'update_member_card']])
            ->orderBy('id ASC')
            ->limit(10);

        $messages = $query->all();

        if(empty($messages)){
            return false;
        }

        foreach($messages as $message) {

            $data = json_decode($message->data, true);
            switch ($message->event) {
                case 'update_waybill_status':   //即时配送订单回调
                    $res = $this->getOrderStatus($data, $message->cTime);
                    if ($res) {
                        $message->status = 1;
                    }else{
                        $message->status = 2;
                    }
                    $message->save();
                    usleep(50000);
                    break;
                case 'user_get_card':   // 会员卡领取
                    $res = $this->getUserMember($data, $message->cTime);
                    if ($res) {
                        $message->status = 1;
                    }else{
                        $message->status = 2;
                    }
                    $message->save();
                    usleep(50000);
                    break;
                case 'submit_membercard_user_info':     // 会员卡激活:同步积分、拉取会员信息
                    $res = $this->actUserMember($data, $message->cTime);
                    if ($res) {
                        $message->status = 1;
                    }else{
                        $message->status = 2;
                    }
                    $message->save();
                    break;
                case 'update_member_card':  // 会员信息更新:积分更新
                    $message->status = 1;
                    $message->save();
                    break;
            }
        }
        exit;

    }

    /**
     * 领卡事件处理:
     *
     * 1、查卡券
     * 2、是否同步积分
     * ①已激活:更新usermember,积分同步(user->integral)
     * ②未激活:新增usermember,积分不同步(激活事件处理)
     * 3、设置信息
     *
     */
    public function getUserMember($list = [], $time)
    {
        $member = Member::findOne(['card_id' => $list['CardId']]);
        if (!$member) {
            echo "Card:{$list['CardId']} not found\n";
            return false;
        }

        $form        = new MemberListForm();
        $wechat_card = $form->getWx($member->store_id);
        if (!$wechat_card) {
            return false;
        }

        $user        = User::findOne(['wechat_union_id' => $list['UnionId'],'store_id' => $member->store_id]);
        $user_member = UserMember::findOne(['card_id' => $list['CardId'], 'user_card_code' => $list['UserCardCode']]);

        if ($user) {
            if (!empty($user_member->phone) && empty($user_member->user_id)) {  // 已激活,首次领取:新增usermember,积分同步
                $user->integral       += $member->reward_num;
                $user->total_integral += $member->reward_num;
                $user->binding        = $user_member->phone;
                $user->save();
                $register                = new Register();
                $register->store_id      = $member->store_id;
                $register->user_id       = $user->id;
                $register->register_time = '..';
                $register->addtime       = time();
                $register->continuation  = 0;
                $register->type          = 14;
                $register->integral      = $member->reward_num;
                $register->order_id      = -1;
                $register->save();
            }

            UserMember::setList([
                'store_id'        => $user->store_id,
                'user_id'         => $user->id,
                'wechat_open_id'  => $user->wechat_open_id,
                'wp_open_id'      => $list['FromUserName'],
                'wechat_union_id' => $user->wechat_union_id,
                'card_id'         => $list['CardId'],
                'user_card_code'  => $list['UserCardCode'],
                'addtime'         => $time,
            ], $user->store_id, $list['CardId'], $list['UserCardCode']);

        } else {
            // 公众号领取,没用过小程序
            UserMember::setList([
                'store_id'        => $member->store_id,
                'wechat_union_id' => $list['UnionId'],
                'wp_open_id'      => $list['FromUserName'],
                'card_id'         => $list['CardId'],
                'user_card_code'  => $list['UserCardCode'],
                'addtime'         => $time,
            ], $member->store_id, $list['CardId'], $list['UserCardCode']);
        }

        return true;
    }

    /**
     * 激活事件处理:
     * 1、查卡券
     * 2、是否同步积分
     * ①未领取:新增usermember,积分不同步(领取事件处理)
     * ②已领取:更新usermember,积分同步(user->integral)
     * 3、设置信息:拉取会员信息:更新usermember个人信息
     *
     * 注:积分更新通知微信,由Register类afterSave()处理
     */
    public function actUserMember($list = [], $time)
    {
        $member = Member::findOne(['card_id' => $list['CardId']]);
        if (!$member) {
            echo "Card:{$list['CardId']} not found\n";
            return false;
        }

        $form        = new MemberListForm();
        $wechat_card = $form->getWx($member->store_id);
        if (!$wechat_card) {
            echo $msg = "Store {$member->store_id}: get Wechat info failed\n";
            \Yii::error($msg);
            return false;
        }

        $card_get = $form->getCardUser($wechat_card->getAccessToken(),$list['CardId'],$list['UserCardCode']);

        if (!$card_get) {
            echo $msg = "CardCode: {$list['UserCardCode']} not found\n";
            \Yii::error($msg);
            return false;
        } else {
            // 处理用户信息
            $info = $card_get['user_info']['common_field_list'];
            foreach($info as $k => $v){
                if ($v['name'] == 'USER_FORM_INFO_FLAG_MOBILE') {
                    $card_get['phone'] = $v['value'];
                }
                if ($v['name'] == 'USER_FORM_INFO_FLAG_NAME') {
                    $card_get['user_name'] = $v['value'];
                }
                if ($v['name'] == 'USER_FORM_INFO_FLAG_BIRTHDAY') {
                    $card_get['birthday'] = $v['value'];
                }
            }

            $user_member = UserMember::findOne(['card_id' => $list['CardId'], 'user_card_code' => $list['UserCardCode']]);
            if (!empty($user_member->wechat_union_id)) {    // 已领取:更新usermember,积分同步
                $user = User::findOne(['wechat_union_id' => $user_member->wechat_union_id, 'store_id' => $member->store_id]);
                if ($user) {    // 用户已注册:同步user->integral
                    $user->integral       += $member->reward_num;
                    $user->total_integral += $member->reward_num;
                    $user->binding        = $card_get['phone'];
                    $user->save();
                    $register                = new Register();
                    $register->store_id      = $member->store_id;
                    $register->user_id       = $user->id;
                    $register->register_time = '..';
                    $register->addtime       = time();
                    $register->continuation  = 0;
                    $register->type          = 14;
                    $register->integral      = $member->reward_num;
                    $register->order_id      = -1;
                    $register->save();
                }
            }else{
                echo $msg = "User_member - CardCode: {$list['UserCardCode']} not found\n";
                \Yii::error($msg);
                return false;
            }

            $res = UserMember::setList([
                'store_id'          => $member->store_id,
                'card_id'           => $list['CardId'],
                'user_card_code'    => $list['UserCardCode'],
                'nickname'          => preg_replace('/[\xf0-\xf7].{3}/', '', $card_get['nickname']),
                'membership_number' => $card_get['membership_number'],
                'sex'               => $card_get['sex'],
                'user_name'         => preg_replace('/[\xf0-\xf7].{3}/', '', $card_get['user_name']),
                'phone'             => $card_get['phone'],
                'birthday'          => $card_get['birthday'],
                'user_card_status'  => $card_get['user_card_status'],
                'has_active'        => ($card_get['has_active'] == true ? 1 : 0),
                'addtime'           => $time,
            ], $member->store_id, $list['CardId'], $list['UserCardCode']);
        }

        return true;

    }


    /**
     * 即时配送订单回调处理
     * @return string
     */
    public function getOrderStatus($data=[], $time){
        if (empty($data)) {
            return false;
        }
        $type = substr($data['shop_order_id'], 0, 1);
        $order_type = 0;
        if ($type == 'M') {//秒杀
            $info = MsOrder::find()->where(['order_no' => $data['shop_order_id']])->one();
            $orderRefund = MsOrderRefund::findOne($info->id);
            $order_type = 1;
        }elseif ($type == 'P'){//拼团
            $info = PtOrder::find()->where(['order_no' => $data['shop_order_id']])->one();
            $orderRefund = PtOrderRefund::findOne($info->id);
            $order_type = 2;
        }else{//普通与砍价
            $info = Order::find()->where(['order_no' => $data['shop_order_id']])->one();
            $orderRefund = OrderRefund::findOne($info->id);
            $order_type = 0;
        }
        if (empty($info)) {
            return false;
        }

        $statusArr = DcEnum::JS_PS_ORDER_CODE[$data['order_status']]; //配送单状态
        $status = $statusArr['status'];
        //$this->addLog($info, $data, $status);
        $shipment_status = $info->shipment_status;
        $info->shipment_status = $status;
        //已接单、已取货
        if ($status == 1 || $status == 2) {
            $info->courier_name = isset($data['agent']['name'])?:''; //沙盒无返回
            $info->courier_phone = isset($data['agent']['phone'])?:'';
        }
        //已取消
        if ($status == 4) {
            //不在售后,取消配送订单后为未发货
            if (!$orderRefund) {
                $info->is_send = 0;
            }
            //$info->cancel_reason_id = $data['cancel_reason_id'];
            //$info->cancel_reason = DcEnum::MT_SYSTEM_CANCEL_CODE[$data['cancel_reason_id']] ? $data['cancel_reason']. '(系统取消)' : $data['cancel_reason'];
        }
        //已送达(已收货)
        if ($status == 3) {
            $info->is_confirm = 1;
            $info->confirm_time = time();
            if ($info->pay_type == 2) {
                $info->is_pay = 1;
                $info->pay_time = time();
            }
        }
        if ($status != $shipment_status) {
            $content = json_decode($info->cancel_content, true);
            $content[count($content)] = [
                'code' => 0,
                'msg' => $statusArr['msg'],
                'time' => date('Y-m-d H:i:s')
            ];
            $info->cancel_content = json_encode($content, JSON_UNESCAPED_UNICODE);
        }
        $result = $info->save();
        if ($result) {
            $this->sendStatusTpl($info->store_id, $info->user_id, $statusArr['msg'], $info->id, $order_type);
            return true;
        }

    }

    //发送状态模版消息
    private function sendStatusTpl($store_id, $user_id, $statusMsg, $order_id, $order_type = 1)
    {
        $store = Store::findOne($store_id);
        $wechat_app = WechatApp::findOne(['id' => $store->wechat_app_id]);
        $wechat = new Wechat([
            'subMchId' => $wechat_app->mch_id,
            'appId' => $wechat_app->app_id,
            'appSecret' => $wechat_app->app_secret,
            'appBrandUserName' => $wechat_app->app_brand_user_name
        ]);
        //发送处方审核通知
        $wechat_tpl_meg_sender = new WechatTplMsgSender($store_id, '', $wechat, $user_id);
        $wechat_tpl_meg_sender->DcStatusMsg($statusMsg, $order_type, $order_id);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值