订餐系统之同步美团商家订单
Posted 左正
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了订餐系统之同步美团商家订单相关的知识,希望对你有一定的参考价值。
背景
之前写过一篇关于同步饿了么订单的文章《订餐系统之同步饿了么商家订单》,有不少人加我咨询,感觉有这方面需求的人还是满多的,毕竟现在2家几乎瓜分了市场,再做平台已然机会渺茫了,但是商户毕竟需要服务,订单还得配送出去。然后饿了
么,美团外卖都提供了面向供应商的api的权限的申请,这对我们做配送系统的说,真是一大利好。以前都是让商户手动录入其他平台的订单,费力还容易出错。还得在多个app之间来回切换,商户也是抱怨满天。有了这些接口,商户可以选择自动接单,
自动同步订单,再也不用几个app来回切换了。饿了么同步订单,在上面的文章中已经介绍了,虽然接口现在变成2.0了。有了一些变化,总的来说还是 万变不离其宗。本篇就来详细接受下同步美团订单的相关步奏。写得不对地方,欢迎指正 :)
具体流程,下图中写得比较详细。
申请
去年过年,因娃太小,没能回家,闲在杭州,发现可以申请美团外卖相关接口,欣喜若狂,撸起袖子就动了起了,登录申请网站地址《美团点评 | 聚宝盆餐饮开放平台》,填写相关信息。记得,当时是2月5号,再2天就过年了,想着如果能年前审核好...,当然,后来是想多了,过了一个月都没有审核通过,也不能进行下一步。到时那个心呀,难过,没有还好,现在是看得见,不让用。经过漫长的煎熬,终于在一个不起眼的地方,发现一个邮箱,怀着死马当活马医的想法,发过去了,想不到,还真给回复了,说是过年漏掉了申请。好嘛,审核通过了总是好的,过程是复杂了些。
这里通过了,他们会加你QQ,确认相关信息,还会快递一份文件,签字盖章,按说明快递回去就OK了。
审核通过,开放平台里有相关信息了。关键的东西就是 developerId,与SignKey 。调用接口会用到
开入平台文档地址:《文档中心》,也许你看了文档,都不用看下面的:)。
回调接口设置
开始开发前,先要设置好回调,通知接口。美团外卖会根据在开放平台设置的通知地址,发送相关信息,比如新订单通知,商家确认订单通知,及绑定,解绑商家通知等。这里每个通知一个接口,这样程序蛮方便的,可以一个通知,一个url。不用去判断到底是什么通知。
在下图中设置
门店映射
所谓映射,就是把你系统的商家编号,与美团商家绑定起来,以后推送都是自己系统的商家编号推送过来。方便操作
对接第一步,还是绑定商家,并保存Token(后面的操作都会用到)。
输入商家账号,密码选择商家授权即可完成映射
具体参数可以参考文档, 其中 ePoiId 为自己系统的商家编号,像我就直接用自动编号,这个方便记录,后台绑定也方便,订单通知过来也方便。比如,我们最后的效果就是在商家详情中增加相关设置。
在回调接口设置中,设置了url后,会收到通知,处理通知的代码如下。
Response.Clear();
Response.Write("{\\"data\\":\\"success\\"}");
Hangjing.AppLog.AppLog.Info("美团门店与ERP绑定接收token回调URL");
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(); ;
}
//保存 appAuthToken
Hangjing.AppLog.AppLog.Info("回调URL信息:" + jsondata);
}
Response.Clear(); Response.Write("{\\"data\\":\\"success\\"}"); Hangjing.AppLog.AppLog.Info("美团门店与ERP绑定接收token回调URL"); 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(); ; } //保存 appAuthToken Hangjing.AppLog.AppLog.Info("回调URL信息:" + jsondata); }
既然有映射商家,就是有解除绑定的操作,同样,在回调接口设置中,设置了url后,会收到通知,处理通知的代码如下。 这里记录,主要是为了方便后台操作,知道当前商家是否绑定。
Response.Clear();
Response.Write("{\\"data\\":\\"success\\"}");
Hangjing.AppLog.AppLog.Info("美团门店与ERP解除绑定token回调URL");
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(); ;
}
Hangjing.AppLog.AppLog.Info("解除绑定回调URL信息:" + jsondata);
}
Response.Clear(); Response.Write("{\\"data\\":\\"success\\"}"); Hangjing.AppLog.AppLog.Info("美团门店与ERP解除绑定token回调URL"); 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(); ; } Hangjing.AppLog.AppLog.Info("解除绑定回调URL信息:" + jsondata); }
新订单推送
要推送订单,首先得要设置接收通知的url
要推送订单,其次得有商家,所以美团为我们设置了测试商家。还可以添加多个。要特别注意的就是:测试门店为一个坐标位于南极洲、配送范围为西藏昌都的线上测试门店,开发者可使用美团外卖APP定位到西藏昌都气象局,根据测试门店名称搜索到测试门店进行下单。
一定要App定位在西藏昌都气象局方可下订单。
因为推送的数据格式是json,所以我的做法是:先创建好订单对应的体,收到通知后,转成实体,再做逻辑处理。接收通知,所上面的类似。
Response.Clear();
string order = Server.UrlDecode(Request["order"]);
Hangjing.AppLog.AppLog.Info("美团订单来了.美团订单内容:" + order);
apiResultInfo rs = new apiResultInfo();
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(); ;
}
Hangjing.AppLog.AppLog.Info("美团订单信息:" + jsondata);
mtorderInfo model = JsonConvert.DeserializeObject<mtorderInfo>(order);
if (model.ePoiId == "1015")
{
mthelper mt = new mthelper(Context);
apiResultInfo retuls = mt.confirmOrder(model.orderId, Convert.ToInt32(model.ePoiId));
}
}
else
{
rs.state = 0;
rs.msg = "参数错误";
}
Response.Write("{\\"data\\":\\"OK\\"}");
Response.End();
Response.Clear(); string order = Server.UrlDecode(Request["order"]); Hangjing.AppLog.AppLog.Info("美团订单来了.美团订单内容:" + order); apiResultInfo rs = new apiResultInfo(); 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(); ; } Hangjing.AppLog.AppLog.Info("美团订单信息:" + jsondata); mtorderInfo model = JsonConvert.DeserializeObject<mtorderInfo>(order); if (model.ePoiId == "1015") { mthelper mt = new mthelper(Context); apiResultInfo retuls = mt.confirmOrder(model.orderId, Convert.ToInt32(model.ePoiId)); } } else { rs.state = 0; rs.msg = "参数错误"; } Response.Write("{\\"data\\":\\"OK\\"}"); Response.End();
确认订单
我们收到新订单通知时,可以调用api直接确认订单,也就是商户接单。到这里,我们才正式去调用api,前面都是美团来调用我们,要调用api,首先要做的就是实现签名。这是我对接这么多系统,签名算法最简单的。直接上代码。
签名:首先将GET
、POST
参数除去sign本身以及值为空的参数以及=号和&号,按参数自然排序,(例如a=&c=3&b=1,变为b1c3)然后按参数1值1参数2值2...参数n值n的方式拼接成新字符串,再跟字符串前面加上signKey,做sha1散列,最后将得出字符串转成小写即为sign。
签名代码
/// <summary>
/// sha1签名
/// </summary>
/// <returns></returns>
public string createSHA1Sign()
{
StringBuilder sb = new StringBuilder();
ArrayList akeys = new ArrayList(parameters.Keys);
akeys.Sort();
foreach (string k in akeys)
{
string v = HttpUtility.UrlEncode((string)parameters[k], Encoding.UTF8);
if (null != v && "".CompareTo(v) != 0
&& "sign".CompareTo(k) != 0)
{
sb.Append(k+ v);
}
}
string signstep2 = Constant.mt_SignKey + sb.ToString();
string sig = Utils.SHA1_Hash(signstep2).ToLower();
AppLog.AppLog.Info("美团签名=" + "signstep1=" + sb.ToString() + "\\r\\nsignstep2=" + signstep2 + "\\r\\n => sign:" + sig);
return sig;
}
/// <summary> /// sha1签名 /// </summary> /// <returns></returns> public string createSHA1Sign() { StringBuilder sb = new StringBuilder(); ArrayList akeys = new ArrayList(parameters.Keys); akeys.Sort(); foreach (string k in akeys) { string v = HttpUtility.UrlEncode((string)parameters[k], Encoding.UTF8); if (null != v && "".CompareTo(v) != 0 && "sign".CompareTo(k) != 0) { sb.Append(k+ v); } } string signstep2 = Constant.mt_SignKey + sb.ToString(); string sig = Utils.SHA1_Hash(signstep2).ToLower(); AppLog.AppLog.Info("美团签名=" + "signstep1=" + sb.ToString() + "\\r\\nsignstep2=" + signstep2 + "\\r\\n => sign:" + sig); return sig; }
录入所有参数,得到签名,初始化post参数,调用指定api,即可完成确认。大概代码如下,代码都比较文明,大家一看变懂了。
public apiResultInfo confirmOrder(string orderId, int shopid)
{
apiResultInfo rs = new apiResultInfo();
meituanbindlogInfo record = new meituanbindlog().GetList(1, 1, "ePoiId=" + shopid + " and mtype=1", "mid", 1).FirstOrDefault();
if (record == null)
{
OperationLog.Warn("商家:" + shopid + "未找到绑定token");
rs.msg = "商家:" + shopid + "未找到绑定token";
return rs;
}
parameters = new Hashtable();
parameters.Add("charset", "UTF-8");
parameters.Add("version", "1");
parameters.Add("timestamp", Utils.getTimestamp());
parameters.Add("appAuthToken", record.appAuthToken);
parameters.Add("orderId", orderId.Replace("m", ""));
createSHA1Sign();
HttpItem objHttpItem = new HttpItem()
{
Encoding = "utf-8",
Method = "POST"
};
string url = "http://api.open.cater.meituan.com/waimai/order/confirm";
string returnmsg = queryData(objHttpItem, url);
mtresult result = Newtonsoft.Json.JsonConvert.DeserializeObject<mtresult>(returnmsg);
if (result.data != null && result.data.ToLower() == "ok")
{
rs.state = 1;
}
else
{
rs.msg = "确认订单失败";
}
return rs;
}
public string queryData(HttpItem objHttpItem, string url)
{
string sig = createSHA1Sign();
parameters.Add("sign", sig);
serverurl = url;
ArrayList akeys = new ArrayList(parameters.Keys);
StringBuilder sb = new StringBuilder();
foreach (string k in akeys)
{
string v = context.Server.UrlEncode((string)parameters[k]);
v = HttpUtility.UrlEncode(v, Encoding.UTF8);
if (null != v && "".CompareTo(v) != 0)
{
if (sb.Length == 0)
{
sb.Append(k + "=" + v);
}
else
{
sb.Append("&" + k + "=" + v);
}
}
}
if (objHttpItem.Method.ToLower() == "get")
{
serverurl += "?" + sb.ToString();
}
else
{
objHttpItem.Postdata = sb.ToString();
}
HttpHelper objhttp = new HttpHelper();
objHttpItem.URL = serverurl;
objhttp.isToLower = false;
string returnmsg = objhttp.Gethtml(objHttpItem);
Hangjing.Common.HJlog.toLog("returnmsg=" + returnmsg + "\\r\\n url=" + serverurl);
// HJlog.toLog(this.getDebugInfo());
return returnmsg;
}
public apiResultInfo confirmOrder(string orderId, int shopid) { apiResultInfo rs = new apiResultInfo(); meituanbindlogInfo record = new meituanbindlog().GetList(1, 1, "ePoiId=" + shopid + " and mtype=1", "mid", 1).FirstOrDefault(); if (record == null) { OperationLog.Warn("商家:" + shopid + "未找到绑定token"); rs.msg = "商家:" + shopid + "未找到绑定token"; return rs; } parameters = new Hashtable(); parameters.Add("charset", "UTF-8"); parameters.Add("version", "1"); parameters.Add("timestamp", Utils.getTimestamp()); parameters.Add("appAuthToken", record.appAuthToken); parameters.Add("orderId", orderId.Replace("m", "")); createSHA1Sign(); HttpItem objHttpItem = new HttpItem() { Encoding = "utf-8", Method = "POST" }; string url = "http://api.open.cater.meituan.com/waimai/order/confirm"; string returnmsg = queryData(objHttpItem, url); mtresult result = Newtonsoft.Json.JsonConvert.DeserializeObject<mtresult>(returnmsg); if (result.data != null && result.data.ToLower() == "ok") { rs.state = 1; } else { rs.msg = "确认订单失败"; } return rs; } public string queryData(HttpItem objHttpItem, string url) { string sig = createSHA1Sign(); parameters.Add("sign", sig); serverurl = url; ArrayList akeys = new ArrayList(parameters.Keys); StringBuilder sb = new StringBuilder(); foreach (string k in akeys) { string v = context.Server.UrlEncode((string)parameters[k]); v = HttpUtility.UrlEncode(v, Encoding.UTF8); if (null != v && "".CompareTo(v) != 0) { if (sb.Length == 0) { sb.Append(k + "=" + v); } else { sb.Append("&" + k + "=" + v); } } } if (objHttpItem.Method.ToLower() == "get") { serverurl += "?" + sb.ToString(); } else { objHttpItem.Postdata = sb.ToString(); } HttpHelper objhttp = new HttpHelper(); objHttpItem.URL = serverurl; objhttp.isToLower = false; string returnmsg = objhttp.GetHtml(objHttpItem); Hangjing.Common.HJlog.toLog("returnmsg=" + returnmsg + "\\r\\n url=" + serverurl); // HJlog.toLog(this.getDebugInfo()); return returnmsg; }
确认订单后,我们设置的订单确认通知接口,也有收到相应的通知,具体代码与新订单通知是一样的,只是你可以根据自己业务处理,比如,商家确认订单后,订单直接进入系统,自动调度,或者人工派单。
设置商家营业状态
这个接口也是经常用到的,因为测试账号,不能登录美团外卖商户后台,如果商家有一个订单没接,商家就会自动休息,影响我们测试。所以实现这个接口后,可方便修改商家状态。
这个接口与确认订单接口都是类似的,只是参数不同,url不同而已。由于调用api,我们都是封装在方法:queryData了,我们只用设置好参数即可。代码如下:
public apiResultInfo shopOnline(int shopid)
{
apiResultInfo rs = new apiResultInfo();
meituanbindlogInfo record = new meituanbindlog().GetList(1, 1, "ePoiId=" + shopid + " and mtype=1", "mid", 1).FirstOrDefault();
if (record == null)
{
OperationLog.Warn("商家:" + shopid + "未找到绑定token");
rs.msg = "商家:" + shopid + "未找到绑定token";
return rs;
}
parameters.Add("appAuthToken", record.appAuthToken);
createSHA1Sign();
HttpItem objHttpItem = new HttpItem()
{
Encoding = "utf-8",
Method = "POST"
};
string url = "http://api.open.cater.meituan.com/waimai/poi/open";
string returnmsg = queryData(objHttpItem, url);
mtresult result = Newtonsoft.Json.JsonConvert.DeserializeObject<mtresult>(returnmsg);
if (result.data != null && result.data.ToLower() == "ok")
{
rs.state = 1;
}
else
{
rs.msg = "商家上线失败";
}
return rs;
}
设置商家上线
public apiResultInfo shopOnline(int shopid) { apiResultInfo rs = new apiResultInfo(); meituanbindlogInfo record = new meituanbindlog().GetList(1, 1, "ePoiId=" + shopid + " and mtype=1", "mid", 1).FirstOrDefault(); if (record == null) { OperationLog.Warn("商家:" + shopid + "未找到绑定token"); rs.msg = "商家:" + shopid + "未找到绑定token"; return rs; } parameters.Add("appAuthToken", record.appAuthToken); createSHA1Sign(); HttpItem objHttpItem = new HttpItem() { Encoding = "utf-8", Method = "POST" }; string url = "http://api.open.cater.meituan.com/waimai/poi/open"; string returnmsg = queryData(objHttpItem, url); mtresult result = Newtonsoft.Json.JsonConvert.DeserializeObject<mtresult>(returnmsg); if (result.data != null && result.data.ToLower() == "ok") { rs.state = 1; } else { rs.msg = "商家上线失败"; } return rs; }
上线
其他还有很多接口可以按需对接,比如商口数据,评论数据。目前我们用不上,暂未对接。最后一步就上线操作了。
未上线之前,最多能接5个商家,上线后就没有限制了。
目前上线要先写一个《上线申请》,然后在开放平台,里点击上线,会有美团人员联系你,确认相关信息就OK了。
最后效果图如下:
结语
对接美团外卖,除了提交审核时间不好,导致审核时间长了些外,其他还是蛮顺利的,他们也蛮配合的,根据接口文档几乎可以完整大部分操作。
就代码上而言,确定没有太多可以说的,对接过程还是有些曲折的。希望这个文章能给那个正在对接的,想对接的人提供一些帮助,如果真有帮助了,有个赞最好了。
转:
http://www.cnblogs.com/jijunjian/p/6875909.html
以上是关于订餐系统之同步美团商家订单的主要内容,如果未能解决你的问题,请参考以下文章