饿了么订单--快到碗里来

引子   

     坚持了20天,终于还是做了一个艰难的决定--把媳妇和娃送到了丈母娘家。

   前些时间,老妈有事儿回了四川,给了我和媳妇独自抚养娃的机会,我知道这将是一个巨大的挑战。

   因为一些知道的和不知道的原因,娃的湿疹比较严重,晚上老睡不踏实,得整晚拍着,哄着,实在没辙了,就得抱着睡,不然就不停的挠头呀,肚子的。。

   白天除非抱着,根本睡不了一会儿,醒了没人看着,也是有事儿没事儿挠自己。根本离不开人...看着娃身上的湿疹,以及来不及好的挠痕,心里真是奔溃的。

   还得到处寻医问诊,泡中药,涂药膏,抹茶油...官方的,民间的... 都是3个字:然并卵。

   又值搬新家,更是忙得不可开交,与媳妇在杭州奋斗了6-7年,总算是有了自己的家,只是全然没空喜悦一下,反倒时房贷的压力总记在心上。

   媳妇几度落泪,这不是矫情,一则是为自己孕期没管牢嘴,满月又吃了虾而自责;二则吃不好,睡不好,身心都是承受巨大压力,就是上个洗手间都得把娃哄睡了。

   话说回来,也是正是这短短的20天,方才对“当家才知柴米贵,养儿方知父母恩”,有了切身的感受,对父母的嘘寒问暖不再厌烦,而真正心怀感恩。这个认知与媳妇的意见终于空前的一致了 :)。

   跨出了丈母娘家门,挥手告别妻儿时,心头一紧,眼眶微酸,眼泪几乎夺眶而出...是了,这就是离别。也终于理解了,母亲每次送我出远门时,总是忍不住的哭泣。

 

   —————————— 生活感悟,借此叨叨,回归主题——————————

 

背景

  之前写过一篇关于同步饿了么订单的文章《订餐系统之同步饿了么商家订单》,是介绍如何通过 饿了么OpenAPI 同步饿了么商家订单。此版本最大的弊端便是每次要绑定商家都需要发邮件给他们,绑定商家是一个频繁的操作,但是他们邮件处理的速度又较为缓慢,有鉴于此对接人的几乎都是望而却步,像早期的淘点点,及新开美团外卖开放平台,都是以商家登录授权方式绑定,完全是开发商与商家自助就可以完成。前些天,饿了么OpenAPI2.0 总算是千呼万唤始出来了。赶紧注册,认证。于是有了这篇文章。

申请

  先上开放平台网址, https://open.shop.ele.me/openapi《饿了么开放平台》,  首先,你得注册成为开放者,这个过程不用截图了吧。然后 开发者资质认证,这个按要求填写相关信息,上传相关资料等他们审核了。

  

  几个工作日审核通过后,你们会看如下信息,就可开始进入下一步操作了。

  

  

创建应用

   对接了美团后,才知道可以创建应用是多么方便一个功能,不然来一个客户,又得重新注册账号,走申请的流程,漫长而痛苦。饿了么OpenAPI2.0 可以创建多个应用,每个应用独立运行,减少了很多不必要的麻烦。

进入开发都中心,即可开始新建应用,输入几个基本信息,应用就创建好了。

  

 

  

 

  接下来可以配置沙箱环境了,点击查看应用,进入“沙箱环境”选项卡。设置好 回调地址URL(商家授权后回调通知地址),推送URL(新订单,订单状态变化等通知地址),推送消息(选择要接收的通知类型)。配置部分到现在就结束了,接下变是上代码了。

  

 

商户授权

  准备写代码之前,还是习惯性的去找下SDK,有SDK肯定会事半功倍的,只是不看不知道,一看真又感觉被默默的鄙视了一下下。提供了5种语言,都没有.net。好吧,别的咱不敢说,写代码还是会的。

  

 

   初略看了文档知道授权流程采用国际通用的OAuth2.0标准协议作为商户身份验证与授权协议,之前对接QQ登录,微信公从平台,流程几乎类似,轻车熟路,已经有代码修改几个配置与json对应的实体,分分钟就完成了前面4个流程,流程图如下,核心代码也贴上来了

   

 

/// <summary>
        /// 授权
        /// </summary>
        /// <param name="callbackurl"></param>
        public ELEAuth(HttpContext _context)
        {
            context = _context;
            parameters = new Hashtable();
            singparameters = new Hashtable();
        }

        /// <summary>
        /// 返回授权url
        /// </summary>
        /// <param name="shopid"></param>
        /// <returns></returns>
        public string GetAuthURL(int shopid)
        {
            string callbackurl = appconfig.authcallbackURL;
            string OAuthurl = appconfig.authurl + "?response_type=code&client_id=" + Hangjing.EleAPIV2.appconfig.Key + "&redirect_uri=" + context.Server.UrlEncode(Hangjing.EleAPIV2.appconfig.authcallbackURL) + "&state=" + shopid + "&scope=all";
            return OAuthurl;
        }

        public access_tokenInfo getToken()
        {
            access_tokenInfo token = new access_tokenInfo();

            parameters.Add("grant_type", "authorization_code");
            parameters.Add("code", context.Request["code"]);
            parameters.Add("redirect_uri", appconfig.authcallbackURL);
            parameters.Add("client_id", appconfig.Key);

            string Authorization = appconfig.Key + ":" + appconfig.Secret;
            byte[] bytes = Encoding.UTF8.GetBytes(Authorization);

            HttpItem objHttpItem = new HttpItem()
            {
                Authorization = "Basic " + Convert.ToBase64String(bytes),
                URL = appconfig.tokenurl,
                Encoding = "utf-8",
                Method = "POST",
                Postdata = getPostDatan()
            };

            HttpHelper objhttp = new HttpHelper();
            objhttp.isToLower = false;


            Hangjing.AppLog.AppLog.Info("getToken:" + getPostDatan() + "\r\nurl=" + appconfig.tokenurl + "\r\nAuthorization=" + Convert.ToBase64String(bytes));

            string returnmsg = objhttp.GetHtml(objHttpItem);

            Hangjing.AppLog.AppLog.Info("getToken:" + getPostDatan() + "\r\nmsg=" + returnmsg + "\r\nAuthorization=" + Convert.ToBase64String(bytes));

            token = JsonConvert.DeserializeObject<access_tokenInfo>(returnmsg);
            if (token != null)
            {
                token.shopid = Convert.ToInt32(context.Request["state"]);
            }

            return token;
        }
商户授权部分代码

 

 

  回调地址URL指向的地方 只要如下调用就可以了。

  ELEAuth auth = new EleAPIV2.ELEAuth(Context);
  access_tokenInfo token = auth.getToken();

  

  整个过程就一个地方要注意下:HTTP header中需要携带Authorization请求头,Basic值的算法如下(+号表示字符串连接)  base64_encode(key + ":" + secret),具体的写法在上面的代码已经有了。大伙儿稍微留意下就过了。

  话说回来,为什么是前面4个流程分分钟,独少了第五个呢,是了,第5个里面有一个计算签名的过程,几乎是第一次遇到这样的签名方式,过程较为麻烦,容易出错,之前也有几个园友也问到签名的事儿,所以这里单独拿出来。

 

签名算法

   对接接口,签名总是较为麻烦的一点,相关文档如下点这里,如果想了解流程,可以自行查看。流程很长,这里就不写了,几个地方要注意的如下:

   1,签名的参数,只包含 JSON对像,metas和params 的属性。当然,params可能没有属性,忽略就可以了。

   2,使用"key=json_encode(value)"方式进行字符串拼接,这就得要求 参数的类型 要与文档里匹配,long与string  json_encode后的值是有区别的。比如  json_encode(123) = 123,而 json_encode(“123”) =“ 123”,这就直接导致用于加密的内容都不同了。

  其他的什么排序,action + token  + secret,md5等等按正常流程走就可以了,没有坑了。

  到这里,就只剩代码,签名算法代码如下:

  

//构建签名参数,注意 timestamp 类型是 int64
singparameters.Add("app_key", appconfig.Key);
singparameters.Add("timestamp", Convert.ToInt64(Timestamp));


        /// <summary>
        /// 签名
        /// </summary>
        /// <returns></returns>
        public string createMD5Sign(string action, string token)
        {
            StringBuilder sb = new StringBuilder();
            ArrayList akeys = new ArrayList();

            foreach (var item in singparameters.Keys)
            {
                akeys.Add(item + "=" + JsonConvert.SerializeObject(singparameters[item]) + "");
            }
            akeys.Sort();

            foreach (string k in akeys)
            {
                sb.Append(k);
            }

            string signstep = action + token + sb.ToString() + appconfig.Secret;

            Hangjing.AppLog.AppLog.Info("createMD5Sign:oldsignstep=" + signstep);

            signstep = Utils.MD5(signstep).ToUpper();

            Hangjing.AppLog.AppLog.Info("createMD5Sign:signstep=" + signstep);

            return signstep;
        }
签名实体,调用代码

 

  

  第5个流程的文档在这里,主要是获取商户信息,与系统商家对应好,我是通过state参数传系统商家编号,因为state会原样回传回来。

  计算好签名,这个流程就完成大半了,剩下注意如下:

  1, Content-Type = application/json;charset=utf-8,

  2, id 参数值为 Guid.NewGuid().ToString()

  3,post的参数要是josn 格式。参数在系统里是用 Hashtable 保存的,只要一句话就可以转成Json -- JsonConvert.SerializeObject(parameters); 

  做了以上操作,此流程80%的情况就OK了。最后上几个实际流程图

  

  

   

接收订单参数,查询订单信息

  设置好接收推送的url,根据通知类型和内容进行相应的逻辑操作,比如收到商家确认订单通知,就把订单加入系统,订单取消通知就把系统中订单相应取消。

  完成了签名算法,其他的接口对接就是水到渠成的事儿了,根据json生成实体,替换参数,很快就可以完成其他接口了。

  接收通知代码如下,特别注意就是消息体是以流形式推送过来的。另外还有一个情况可能大家都会遇到:创建应用后,会生成测试商家,商家的商品全是1毛的,你测试几单后,饿了么会认为商家在刷单,以后提交订单就直接取消了,无法测试,后来咨询的了客服,说是商品要大于1元才不会自动取消,这样就可以测试新订单推送,商家接单推送,然后再把订单取消,支付的金额就自动退回来了,

  

 HJlog.toLog("\r\nele2.0推送");


        System.IO.Stream stream = Request.InputStream;//这是你获得的流
        if (stream != null && stream.Length > 10)
        {

            Hangjing.AppLog.AppLog.Info("stream.Length :" + stream.Length);
            string jsondata = "";
            using (StreamReader reader = new StreamReader(stream))
            {
                jsondata = reader.ReadToEnd(); ;
            }

            pushMessageInfo notice = JsonConvert.DeserializeObject<pushMessageInfo>(jsondata);

            switch (notice.type)
            {
                case 14:
                case 15:
                case 17:
                case 23:
                case 25:
                case 35:
                    ////订单取消
                    {
                        ordermessageinfo pushorder = JsonConvert.DeserializeObject<ordermessageinfo>(notice.message);
                        string sys_orderid = "e" + pushorder.orderId;
                        new Custorder().AddOrderRecord("e" + sys_orderid, 5, "ele", "饿了么取消了订单");

                        string sql = "update Custorder set OrderStatus=5 where OrderID='" + sys_orderid + "';update shopeleCustorder set OrderStatus=5 where OrderID='" + sys_orderid + "'";
                        WebUtility.excutesql(sql);

                    }
                    break;
                case 12: //接收订单

                    {
                        ordermessageinfo pushorder = JsonConvert.DeserializeObject<ordermessageinfo>(notice.message);
                        //获取token
                        taobaoAPIAcountInfo token = new taobaoAPIAcount().GetList(1, 1, "linkurl='"+notice.shopId+"'", "id", 1).FirstOrDefault();
                        if (token == null)
                        {
                            Hangjing.AppLog.AppLog.Info("商家:" + notice.shopId + "未找到授权信息,orderid=" + pushorder.orderId);
                        }
                        else
                        {
                            ELEShopV2 eleshop = new ELEShopV2(Context);
                            OrderResult rs = eleshop.getOrder(pushorder.orderId,token.pic);



                        }

                    }

                    break;


                default:
                    break;
            }





        }
接收推送代码

 

  

上线

  对接完成后,在 设置好 正式环境 的相关参数,提交审核,至此对接就基本完成了。订单同步进入系统后,就是我们的调度系统派上用场了。通过自动调度规则,让配送员自己抢单,几乎都不用客服调度了,大家还抢的不亦乐乎。以下是某客户实时效果图。

  

  

  到此,终于实现了几个平台订单同步,总算是了了一件心事儿,还少百度外卖?直接忽略了,听商家说百度外卖半个月都不来个订单,连业务员都联系不上了。

  对接流程就完结了,希望对那些想要对接的人能有些帮助,所有流程都是亲测,绝对童叟无欺。

结语

  又到夏天了,猛然发现大学4年,每天6点起来练出来的腹肌早已紧密的团结在了一块儿,确实做我们一行的,每天上班,加班加起的得坐10几个小时,如疏于锻炼,不出3年,基本都得长肉肉的。于是,趁着媳妇回娘家,我开始了找回腹肌计划,希望她回来时,看到一个不一样的我。【她一直想看我有8块腹肌的样子 :)】

  一,早上6:30起床,做好中午的饭,带去公司(外卖太贵了,也不是特别好吃),顺道在工商大学打30分钟篮球。去上班刚好。

  二,晚上22:30-23:00之间 从公司跑回家,全程4公里,绕一下可以有5-6公里。(再晚点,就只能骑车了)

  计划之初,内心也会抵触,反倒是执行2个月后,一切都变得自然而然,成了生活的一部分了。顺带还学会炒菜,当然了,我通常只放油盐,最多加点豆油,味道就那样了 :)。

  到现在跑5公里基本不费多少力,有时还故意再绕一圈小区。唯一麻烦的就是要背着早上带的两个饭盒,权当负重吧。下面是一张最近的跑步记录,下一步就是挑战10KM了,我的终极目前是全马(哈哈)。另外,如果你也要想跑起来,一定注意跑前热身,跑后拉伸。

  

  

  之前听别人的小密圈挺火,也下载玩了下把,创建了一个同步饿么订单的圈子,设置了付费50元加入(付费圈子最低50),抱着玩玩的心态,分享给了之前咨询饿了么接口微信好友,万万没想到,还真有几个人加入了,说是“作为支持你的分享”这也算是意外的惊喜吧,钱不多,背信任的感觉满好的。在此,也谢过几位了哈。

  

  

 

   成为一名优秀的程序员!

 

posted @ 2017-05-22 08:42  2J  阅读(3005)  评论(18编辑  收藏  举报