订餐系统之同步口碑外卖商家菜单与点点送订单

  2015年饿了么、百度外卖、美团外卖、口碑外卖几家几乎分完了外卖这碗羹,让其他外卖网站几乎举步维艰,也让那些蠢蠢欲动想进入外卖领域的人犹豫不决了(这估计是要砸我饭碗的节奏啊,ヾ(@⌒ー⌒@)ノ)。当然了,喝了外卖这碗羹,肯定得有“产物”,不然,还不被撑破了肚皮么。对,这个"产物"就是外卖订单,是大量的外卖订单,商户的配送员能力非常有限,于是第三方的配送公司如雨后春笋般的冒了出来,当然了,市场大,竞争也非常残酷,有些刚冒出头,就被"扼杀"在襁褓里了;估计还有不少的没找好“土壤”,压根就没冒出来;肯定还有好些隔岸观火,跃跃欲试的主儿....反正是你方唱罢我登场,你有张良计我有过墙梯,好不热闹呢!!

  热闹落尽,平淡归真,不少配送公司才发现:指望某一个平台,订单有限,壮大何其难?再则,大部分用户估计也和我一样,没有忠诚度,哪家优惠大,就去哪家。于是,一方面开始发展自己的业务(开发一个自己的app),其次接口多家平台(每个平台一个app)..... 就这样,活下来的配送公司业务稳定了,订单也稳定了,但是问题来了:调度人员得几个平台来回切换,操作还不一样,配送员也得在几个app中切换,你要知道每个配送员身上的订单,还得费不小劲....于是,整合各家订单,统一调度,集中配送,让客服与配送员从其他平台解放出来,重复单一动作,效率自然就高了!但是愿望是美好的,现实是残酷的:除了口碑有完整的对配送商的接口外(之前申请还非常麻烦,不知道现在好些了没),美团外卖只对品牌商家开放了接口外,压根没有对配送商的接口;饿了么找半天也没找着相关接口....虽然现在没有,但是我估计着,不久的将来这几个肯定会有针对配送商的接口。既然现在只有口碑有相关接口,那这一系列文章就以口碑外卖接口为准。以后,如果其他平台有了相关接口,我再给大家分享下。说得不好的地方,也请大家海涵、指出哈!

  之前的文章《订餐系统之自动确认淘点点订单》已经介绍过相关应用的申请,及获取授权账号下的订单,在这里就赘述了,有兴趣的可以了解下。

批量上传与下载口碑商家菜单

  在口碑商家后台添加过菜单的人都知道,商品只能一个个添加,如果只有1、2个商家还好,但是配送商要生存,就得不停的开店,开了店就得上传商品,一个店少说也得有百八十个商品,如此激烈的竞争不开个三、五百家商家生存都难啊....于是,我们会看到这一幕:他们在不停的寻找店铺,到口碑上开设店铺,再一个个添加商品....然后再重复着,重复着,重复着...于是想起了我。下图为批量上传菜单的过程,同时也可以同步口碑商家已经有菜单到本地。这里面有一个注意的地方就是:先上传图片到口碑,返回图片地址,再上传菜单。如果是先上传菜单,再上传图片,特别麻烦。另外,就是接口中有些限制比如:原价不能小于现价,商品介绍不能少于5个字等等之类的,了解就可以了。

  代码方面都是调用TopSdk.dll封装的方法,自己在简单的封装下,方便使用和复用。我的代码结构如下图:

baseTopAPI.cs  主要是初始化 appkey,appsecret,top_session几个必要的参数,方便子类调用接口。

TopSysFoodSort.cs  主要是处理分类相关的接口。

FoodTopAPI.cs  主要是处理商品相关接口的。

FoodSortSync.cs  客户端调用,同步分类

FoodSync.cs   客户端调用,同步商品

详情代码如下,写得不好,有需要的可以看下:

using Hangjing.Model;
using Hangjing.SQLServerDAL;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Top.Api;

/// <summary>
/// 淘点点调用接口基类
/// </summary>
public class baseTopAPI
{
    public SortedList<string, string> parameters = null;

    public string appkey { get; set; }
    public string appsecret { get; set; }
    public string top_session { get; set; }

    /// <summary>
    /// 系统商家编号
    /// </summary>
    public int shopid { get; set; }

    /// <summary>
    /// 淘宝商家编号
    /// </summary>
    public long TaoBaoId { get; set; }

    /// <summary>
    /// 接口地址
    /// </summary>
    public string serverurl = "http://gw.api.taobao.com/router/rest?";

    public baseTopAPI(int shopid)
    {
        parameters = new SortedList<string, string>();
        IList<taobaoAPIAcountInfo> apis = SectionProxyData.GettaobaoAPIAcountList();

        TogoInfo shop = new Togo().GetModelByDataId(shopid);
        if (shop.shoptype != 0 && shop.ReveVar1 != "")
        {
            foreach (var key in apis)
            {
                if (shop.shoptype == key.ID)
                {
                    this.appkey = key.classname;
                    this.appsecret = key.pic;
                    this.top_session = key.hovepic;
                    break;
                }
            }
        }
        TaoBaoId = Convert.ToInt64(shop.ReveVar1);
        this.shopid = shopid;
    }

    /// <summary>
    /// 用任意一个api即可
    /// </summary>
    public baseTopAPI()
    {
        parameters = new SortedList<string, string>();
        taobaoAPIAcountInfo apiconfig = SectionProxyData.GettaobaoAPIAcountList().First();

        this.appkey = apiconfig.classname;
        this.appsecret = apiconfig.pic;
        this.top_session = apiconfig.hovepic;

    }

}

baseTopAPI

using Hangjing.Common;
using Hangjing.Model;
using Hangjing.SQLServerDAL;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Top.Api;
using Top.Api.Request;
using Top.Api.Response;

/// <summary>
/// 商品分类
/// </summary>
public class FoodSortTopAPI : baseTopAPI
{
    public FoodSortTopAPI(int shopid)
        : base(shopid)
    {

    }

    public apiResultInfo CallServer(int operate, string data)
    {
        apiResultInfo rs = new apiResultInfo();
        if (TaoBaoId == 0)
        {
            rs.error_info = "top_session,或者淘宝商家编号未设置未设置";
            rs.error_no = "1";
            return rs;
        }

        ITopClient client = new DefaultTopClient(serverurl, appkey, appsecret, "json");
        WaimaiCategoryOperateRequest req = new WaimaiCategoryOperateRequest();
        req.ShopId = TaoBaoId;
        req.Operate = operate;
        if (operate > 0)
        {
            req.Data = data;
        }

        WaimaiCategoryOperateResponse response = client.Execute(req, top_session);

        if (response != null && response.Result != null)
        {
            rs.error_info = "";
            rs.error_no = "0";
            rs.data = response.Result;
        }
        else
        {
            rs.error_info = "接口出错:" + response.ErrMsg;
            rs.error_no = "1";
        }

        return rs;
    }

    public TopFoodSort QueryFoodSort()
    {
        TopFoodSort model = new TopFoodSort();
        apiResultInfo rs = CallServer(0, "");
        if (rs.error_no == "0")
        {
            model = JsonConvert.DeserializeObject<TopFoodSort>(rs.data.ToString());
            if (model == null)
            {
                model = new TopFoodSort();
                model.cates = new List<CatesItem>();
            }
            model.msg = "";
        }
        else
        {
            model.msg = rs.error_info;
        }

        return model;
    }

    /// <summary>
    /// 删除分类
    /// </summary>
    /// <param name="shopid"></param>
    /// <param name="Top_sort_cids">多个用逗号分开</param>
    /// <returns></returns>
    public apiResultInfo DelFoodSort(string Top_sort_cids)
    {
        TopFoodSort add = new TopFoodSort();
        add.cates = new List<CatesItem>();
        foreach (var sortid in Top_sort_cids.Split(‘,‘))
        {
            CatesItem item = new CatesItem();
            item.cid = sortid;
            add.cates.Add(item);
        }

        string data = JsonConvert.SerializeObject(add);
        apiResultInfo rs = CallServer(3, data);

        return rs;
    }

    /// <summary>
    /// 添加一个分类
    /// </summary>
    /// <param name="shopid"></param>
    /// <param name="addsort"></param>
    /// <returns></returns>
    public apiResultInfo CreateOneFoodSort(EFoodSortInfo addsort)
    {
        IList<EFoodSortInfo> addsorts = new List<EFoodSortInfo>();
        addsorts.Add(addsort);

        return CreateFoodSortS(addsorts);
    }

    /// <summary>
    /// 添加一个分类
    /// </summary>
    /// <param name="shopid"></param>
    /// <param name="addsort"></param>
    /// <returns></returns>
    public apiResultInfo CreateFoodSortS(IList<EFoodSortInfo> addsorts)
    {
        TopFoodSort add = new TopFoodSort();
        add.cates = new List<CatesItem>();

        foreach (var addsort in addsorts)
        {
            CatesItem item = new CatesItem();
            item.name = addsort.SortName;
            item.order = 100000 - addsort.Jorder; //这里用10000-排序得到新的排序,是因为系统里是从降序,淘点点是升序
            add.cates.Add(item);
        }

        string data = JsonConvert.SerializeObject(add);
        apiResultInfo rs = CallServer(1, data);

        return rs;
    }

}

FoodSortTopAPI

using Hangjing.Common;
using Hangjing.Model;
using Hangjing.SQLServerDAL;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Top.Api;
using Top.Api.Request;
using Top.Api.Response;

/// <summary>
/// 淘宝商品接口
/// </summary>
public class FoodTopAPI : baseTopAPI
{
    public FoodTopAPI(int shopid)
        : base(shopid)
    {

    }

    public apiResultInfo AddFood(EFoodInfo food, long syssortid, string shopsortid)
    {
        apiResultInfo rs = new apiResultInfo();
        if (TaoBaoId == 0)
        {
            rs.error_info = "top_session,或者淘宝商家编号未设置未设置";
            rs.error_no = "1";
            return rs;
        }

        ITopClient client = new DefaultTopClient(serverurl, appkey, appsecret);
        WaimaiItemAddRequest req = new WaimaiItemAddRequest();
        req.Title = food.Name;
        req.Price = food.Price.ToString();
        req.Oriprice = food.Price.ToString();
        req.Quantity = 9999L;
        req.Picurl = food.Picture.Length == 0 ? SectionProxyData.GetSetValue(39):food.Picture;
        req.Goodsno = "";
        req.Auctionstatus = 0L;
        req.Limitbuy = 0L;
        req.Categoryid = syssortid;
        req.Auctiondesc = food.Introduce;
        req.Shopids = TaoBaoId.ToString();
        req.Categoryids = shopsortid;

        WaimaiItemAddResponse response = client.Execute(req, top_session);
        if (response != null && response.Result != null)
        {
            rs.error_info = "";
            rs.error_no = "0";
            rs.data = response.Result;
            rs.topFoodID = response.Result.ResultData;

        }
        else
        {
            rs.error_info = "接口出错:" + response.ErrMsg + "(" + response.ErrCode + ")";
            rs.error_no = "1";

            HJlog.toLog("AddFood错误:" + rs.error_info);
        }

        return rs;
    }

    public apiResultInfo AddFood(int foodid, long syssortid, string shopsortid)
    {
        EFoodInfo addfood = new EFood().GetModel(foodid);
        return AddFood(addfood, syssortid, shopsortid);
    }

    /// <summary>
    /// 操作商品
    /// </summary>
    /// <param name="ids">待操作宝贝id,多个以英文逗号分隔</param>
    /// <param name="operate">操作类型(1上架2下架3删除)</param>
    /// <returns></returns>
    public void operateFood(string ids, int operate)
    {
        int maxsize = 20;//淘点点一次能删除20个商品

        string reqids = "";
        string[] foodids = ids.Split(‘,‘);
        if (foodids.Length > maxsize)
        {
            for (int i = 0; i < foodids.Length; i++)
            {
                reqids += foodids[i] + ",";
                if (i % (maxsize -1) == 0 && i > 0)
                {
                    operateFoodCallServer(WebUtility.dellast(reqids),operate);
                    reqids = "";
                }
            }
        }
        if (reqids != "")
        {
            operateFoodCallServer(WebUtility.dellast(reqids), operate);
        }

    }

    /// <summary>
    /// 操作商品
    /// </summary>
    /// <param name="ids">待操作宝贝id,多个以英文逗号分隔</param>
    /// <param name="operate">操作类型(1上架2下架3删除)</param>
    /// <returns></returns>
    public apiResultInfo operateFoodCallServer(string ids, int operate)
    {
        apiResultInfo rs = new apiResultInfo();
        ITopClient client = new DefaultTopClient(serverurl, appkey, appsecret);
        WaimaiItemOperateRequest req = new WaimaiItemOperateRequest();

        req.Ids = ids;
        req.O = operate;
        WaimaiItemOperateResponse response = client.Execute(req, top_session);

        if (response != null && response.BatchOperateResult != null)
        {
            rs.error_info = "";
            rs.error_no = "0";
            rs.data = response.BatchOperateResult;
        }
        else
        {
            rs.error_info = "接口出错:" + response.ErrMsg + "(" + response.ErrCode + ")";
            rs.error_no = "1";

            HJlog.toLog("operateFood错误:" + rs.error_info);
        }

        return rs;
    }

    /// <summary>
    /// 查询商品,如果keyword为空,就不加此参数
    /// </summary>
    /// <param name="keyword"></param>
    /// <returns></returns>
    public List<Top.Api.Domain.TopAuction> queryFood(string keyword)
    {
        ITopClient client = new DefaultTopClient(serverurl, appkey, appsecret);
        WaimaiItemlistGetRequest req = new WaimaiItemlistGetRequest();
        req.Shopid = TaoBaoId;
        req.SalesStatus = 0L;
        if (keyword != "")
        {
            req.Keyword = keyword;
        }

        req.PageNo = 1L;
        req.PageSize = 200L;
        req.Fields = "itemid,title,price,oriprice,goods_no,auction_desc,pic_url,category_id";
        WaimaiItemlistGetResponse response = client.Execute(req, top_session);

        if (response != null)
        {
            long total_results = response.TotalResults;
            return response.DataList;
        }
        return null;
    }
}

FoodTopAPI

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using Hangjing.Model;
using Hangjing.SQLServerDAL;
using Hangjing.DBUtility;
using System.Data;
using Hangjing.Common;

/// <summary>
/// 商品分类同步
/// </summary>
public class FoodSortSync
{
    FoodSortTopAPI sortapid = null;
    public FoodSortSync(int shopid)
    {
        sortapid = new FoodSortTopAPI(shopid);
    }

    /// <summary>
    /// 从淘点点同步到系统
    /// </summary>
    /// <returns></returns>
    public apiResultInfo SyncFromTop()
    {
        TopFoodSort Topsorts = sortapid.QueryFoodSort();
        string sql = " DELETE dbo.EFoodSort WHERE TogoNUm =  "+sortapid.shopid;
        WebUtility.excutesql(sql);

        IList<DBEFoodSortInfo> websorts = new List<DBEFoodSortInfo>();

        foreach (var topsort in Topsorts.cates)
        {
            DBEFoodSortInfo websort = new DBEFoodSortInfo();
            websort.SortName = topsort.name;
            websort.JOrder = 10000 - topsort.order;
            websort.TogoNUm = sortapid.shopid;
            websort.topsortid = topsort.cid;
            websorts.Add(websort);

        }

        DataTable dt = CollectionHelper.ConvertTo(websorts, "EFoodSort");

        SQLHelper.SqlBulkCopyData(dt);  

        return null;
    }

    /// <summary>
    /// 上传菜单到口碑
    /// </summary>
    /// <returns></returns>
    public apiResultInfo Upload()
    {
        TopFoodSort Topsorts = sortapid.QueryFoodSort();
        IList<EFoodSortInfo> Sysorts = new EFoodSort().GetListByTogoNum(sortapid.shopid);

        //1,删除系统中没有,而淘宝中有的分类
        string notinsyssortids = "";
        foreach (var topsort in Topsorts.cates)
        {
            if (Sysorts.Where(a => a.SortName == topsort.name).ToList().Count == 0)
            {
                notinsyssortids += topsort.cid + ",";
            }
        }
        notinsyssortids = WebUtility.dellast(notinsyssortids);
        if (notinsyssortids != "")
        {
            sortapid.DelFoodSort(notinsyssortids);
        }

        //添加系统中有,而淘宝中没有的
        IList<EFoodSortInfo> notintopsorts = new List<EFoodSortInfo>();
        foreach (var syssort in Sysorts)
        {
            if (Topsorts.cates.Where(a => a.name == syssort.SortName).ToList().Count == 0)
            {
                notintopsorts.Add(syssort);
            }
        }

        if (notintopsorts.Count > 0)
        {
            sortapid.CreateFoodSortS(notintopsorts);
        }

        return null;
    }
}

FoodSortSync

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using Hangjing.Model;
using Hangjing.SQLServerDAL;
using System.Data;
using Hangjing.DBUtility;
using Hangjing.Common;

/// <summary>
/// 商品同步
/// </summary>
public class FoodSync
{
    FoodTopAPI api = null;
    public FoodSync(int shopid)
    {
        api = new FoodTopAPI(shopid);
    }

    /// <summary>
    /// 从淘点点同步菜单
    /// </summary>
    /// <returns></returns>
    public apiResultInfo SyncFromTop()
    {
        List<Top.Api.Domain.TopAuction> Topfoods = api.queryFood("");

        IList<EFoodSortInfo> websorts = new EFoodSort().GetListByTogoNum(api.shopid);

        string sql = "  DELETE dbo.EFood WHERE TogoNum = " + api.shopid;
        WebUtility.excutesql(sql);

        IList<DBEFoodInfo> webfoods = new List<DBEFoodInfo>();

        foreach (var topfood in Topfoods)
        {
            DBEFoodInfo food = new DBEFoodInfo();
            food.FoodID = 0;
            food.Name = topfood.Title;
            food.Picture = topfood.PicUrl;
            food.FoodType = 0;
            foreach (var websort in websorts)
            {
                if (topfood.CategoryId.ToString() == websort.topsortid)
                {
                    food.FoodType = websort.SortID;
                    break;
                }
            }

            food.Price = Convert.ToDecimal(topfood.Price);
            food.Introduce = topfood.AuctionDesc;
            food.Discount = 10;
            food.TogoNum = api.shopid;
            food.Total = 0;
            food.IsDelete = 0;
            food.WeekDay = "";
            food.istuan = 0;
            food.nprice = food.Price;
            food.allnum = 0;
            food.joinnum = 0;
            food.salecount = 0;
            food.PackageFree = 0;
            food.IstuanInve = 0;

            webfoods.Add(food);
        }

        DataTable dt = CollectionHelper.ConvertTo(webfoods, "EFood");

        SQLHelper.SqlBulkCopyData(dt);

        return null;
    }

    /// <summary>
    /// 上传菜单
    /// </summary>
    /// <returns></returns>
    public apiResultInfo Upload()
    {
        List<Top.Api.Domain.TopAuction> Topfoods = api.queryFood("");
        IList<EFoodInfo> Sysorts = new EFood().GetList(1000, 1, " IsDelete = 0 and TogoNum=" + api.shopid, "Total", 1);

        //1,删除系统中没有,而淘宝中有的分类
        string notinsyids = "";
        foreach (var topsort in Topfoods)
        {
            if (Sysorts.Where(a => a.Name == topsort.Title).ToList().Count == 0)
            {
                notinsyids += topsort.ItemId + ",";
            }
        }
        notinsyids = WebUtility.dellast(notinsyids);
        if (notinsyids != "")
        {
            api.operateFood(notinsyids, 3);
        }

        FoodSortTopAPI sortapi = new FoodSortTopAPI(api.shopid);
        TopFoodSort Topsorts = sortapi.QueryFoodSort();

        //添加系统中有,而淘宝中没有的
        foreach (var syssort in Sysorts)
        {
            if (Topfoods.Where(a => a.Title == syssort.Name).ToList().Count == 0)
            {
                foreach (var tsort in Topsorts.cates)
                {
                    if (tsort.name == syssort.SortName)
                    {
                        apiResultInfo rs = api.AddFood(syssort, Convert.ToInt64(syssort.Weekday), tsort.cid);
                        if (rs.error_no == "0")
                        {
                            WebUtility.excutesql("UPDATE dbo.EFood SET topFoodID = ‘"+rs.topFoodID+"‘ WHERE FoodID = "+ syssort.FoodID);
                        }
                        break;
                    }
                }
            }
        }

        return null;
    }
}

FoodSync

批量营业与歇业口碑商家

  口碑的商家有这样的一个算是要求吧:如果商家在营业中,一天内多次拒单,或者超时不接单,会让你停业整改一天;再则,口碑的商家后台没有批量营业与歇业店铺的功能(想不通是为什么....)天气晴朗,配送高效,订单自然是多多益善,少数实在不能配送的,与用户友好协商,让他取消,多数还是非常理解的;但遇到打雷、刮风、下雨....等恶劣天气时,订单肯定是一增再增,配送效率一降再降,这时,不能配送的订单可能占了很大的比重,再一个个去沟通,这个成本就非常高了,关掉部分店铺是唯一有效的方法,但等你一个个去口碑商家后台关店时,订单已经堆积成山了,投诉也一个接一个的....不生在其中 不知其中苦,还是看代码吧,主要就是调用接口,没有太多可说的!

 /// <summary>
    /// 商户营业 返回:成功:0,失败:1
    /// </summary>
    public string shopOpen(string shopid, string sessionkey)
    {
        string appkey = "";
        string appsecret = "";
        string top_session = "";
        IList<taobaoAPIAcountInfo> apis = SectionProxyData.GettaobaoAPIAcountList();
        foreach (var item in apis)
        {
            if (item.hovepic == sessionkey)
            {
                top_session = item.hovepic;
                appsecret = item.pic;
                appkey = item.classname;
                break;
            }
        }

        //3.生成url
        string url = "http://gw.api.taobao.com/router/rest?";//线上环境: http://gw.api.taobao.com/router/rest  测试环境: http://gw.sandbox.taobao.com/router/rest

        ITopClient client = new DefaultTopClient(url, appkey, appsecret, "json");
        WaimaiShopOpenRequest req = new WaimaiShopOpenRequest();
        req.Shopid = Convert.ToInt64(shopid);
        WaimaiShopOpenResponse response = client.Execute(req, top_session);

        string rs = "1";

        if (response != null)
        {
            rs = response.RetCode; ;
        }

        return rs;
    }

shopOpen

客户端调用如下,使用 BackgroundWorker 响应操作是否完成。

/// <summary>
    /// 歇业
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void offline_Click(object sender, EventArgs e)
    {

        BackgroundWorker bgw;
        bgw = new BackgroundWorker();
        bgw.WorkerSupportsCancellation = true;
        bgw.WorkerReportsProgress = true;

        bgw.DoWork += new DoWorkEventHandler(offline);
        bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);

        bgw.RunWorkerAsync();

    }

    /// <summary>
    /// 歇业
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void offline(object sender, DoWorkEventArgs e)
    {
        try
        {
            string IdList = this.hidDels.Value;
            IList<shopserverInfo> shops = dal.GetList(100, 1, "id in (" + IdList + ")", "id", 0);
            foreach (var item in shops)
            {
                if (new TaoBaoAPI().shopClose(item.Status.ToString(), item.Parentid) == "0")
                {
                    string sql = "UPDATE dbo.shopserver SET Depth = 0 WHERE id = "+ item.ID;
                    WebUtility.excutesql(sql);
                }
            }

        }
        catch (Exception ee)
        {
            HJlog.toLog(ee.ToString());
        }

    }

客户端调用

接收点点送推送订单

  点点送,其实是口碑官方配送的名称,后台也是对接多个配送商,商家选择某个配送商配送后,订单就自动通知到相应配送商,也就配送家的管理系统,可以看订单,管理人员,及相关报表,和配送员app。如果直接用他们提供的,也就没有下文了,具体原因前文已有说明,这里就不多说了。

  对接主要有发下几个步骤:

1,申请应用

2,申请点点送权限包

  3,订阅相关消息

  4,消息授权接口调用

5,代码实现接收消息

6,订单操作相关接口调用

具体可参考如下网址 http://open.taobao.com/doc2/detail.htm?articleId=101663&docType=1&treeId=2

代码方面,也是简单的封装了下,接收消息程序以windows service为宿主,随服务启动。

MainService.cs 创建,启动服务, 监听订单消息,

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.ServiceProcess;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Threading;
using System.ServiceModel;
using Hangjing.Commond;

namespace Hangjing.JobServer
{
    partial class MainService : ServiceBase
    {
        MessageListener Listener = new MessageListener();

        public MainService()
        {
            InitializeComponent();

        }

        protected override void OnStart(string[] args)
        {
            try
            {
                Listener.Listen();
            }
            catch (Exception ex)
            {
                Hangjing.AppLog.AppLog.Info("启动失败:" + ex);
                throw;
            }

            Hangjing.AppLog.AppLog.Info("启动成功");
        }

        protected override void OnStop()
        {
            base.OnStop();
        }

        protected override void OnShutdown()
        {
            base.OnShutdown();
        }

    }

}

MainService.cs

MessageListener.cs 监听订单消息

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Top.Tmc;

namespace Hangjing.Commond
{
    /// <summary>
    /// 淘宝消息监听器
    /// </summary>
    public class MessageListener
    {
        public MessageListener()
        {

        }

        public void Listen()
        {
            TmcClient client = new TmcClient(CacheHelper.appkey, CacheHelper.secret, "default");
            client.OnMessage += (s, e) =>
            {
                try
                {
                    Hangjing.AppLog.AppLog.Info("msg:\r\n" + e.Message.Content + "\r\n" + e.Message.Topic);

                    MessageHandler hanlder = new MessageHandler(e.Message.Topic, e.Message.Content);

                }
                catch (Exception exp)
                {
                    Hangjing.AppLog.AppLog.Info("error:\r\n" + exp);
                    e.Fail(); // 消息处理失败回滚,服务端需要重发
                }
            };
            client.Connect("ws://mc.api.taobao.com/");
        }
    }
}

MessageListener.cs

MessageHandler.cs 反射机制处理消息报文。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

using Newtonsoft.Json;
using System.Text.RegularExpressions;
using Hangjing.SQLServerDAL;
using Hangjing.Model;
using Hangjing.Common;
using Top.Tmc;
using Top.Api;
using Top.Api.Response;
using Top.Api.Request;

namespace Hangjing.Commond
{
    /// <summary>
    /// 消息处理类
    /// </summary>
    public class MessageHandler
    {
        /// <summary>
        /// 消息名称
        /// </summary>
        public string Topic
        {
            set;
            get;
        }

        /// <summary>
        /// 消息内容
        /// </summary>
        public string Content
        {
            set;
            get;
        }

        /// <summary>
        /// 返回信息
        /// </summary>
        public string replaymsg
        {
            set;
            get;
        }

        public MessageHandler(string _Topic, string _Content)
        {
            Topic = _Topic;
            Content = _Content;

            DynamicMethod();
        }

        /// <summary>
        /// 动态调用方法
        /// </summary>
        private void DynamicMethod()
        {
            if (CacheHelper.goodTopics.Contains(Topic))
            {
                //获取方法的实例  非静态 需要Public访问权限 忽略大小写
                MethodInfo methodInfo = this.GetType().GetMethod(Topic, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
                if (methodInfo != null)
                {
                    //调用方法
                    methodInfo.Invoke(this, null);
                }
                else
                {
                    Hangjing.AppLog.AppLog.Error(string.Format("没有找到方法{0}", Topic));
                }
            }
            else
            {
                Hangjing.AppLog.AppLog.Error("未处理的消息:" + Topic);
            }
        }

        /// <summary>
        /// 库存变化
        /// </summary>
        public void taobao_item_ItemStockChanged()
        {

        }

        /// <summary>
        /// 点点送订单通知消息
        /// </summary>
        public void taobao_waimai_OrderDispatch()
        {

               。。。

            }
        }

        /// <summary>
        /// 买家取消订单
        /// </summary>
        public void taobao_waimai_OrderClose()
        {
            。。。
        }
        /// <summary>
        /// 解析返回的坐标信息 [0]经度,[1]纬度
        /// 坐标信息: LngLatAlt{longitude=120.02165, latitude=30.27919, altitude=NaN}
        /// </summary>
        /// <param name="LngLatAlt"></param>
        /// <returns></returns>
        public string[] ParseLatLng(string LngLatAlt)
        {
            string regexstr = @"[a-zA-Z={}]";   //最后的结果:120.02165, 30.27919,
            string content = Regex.Replace(LngLatAlt, regexstr, string.Empty, RegexOptions.IgnoreCase);

            return content.Split(‘,‘);
        }

    }
}

MessageHandler.cs

另外,关于订单操作,如指定配送员取件、妥投、上传坐标等,按文档,调用接口就完成了,基本没什么可说的。

结语

  关于口碑相关接口的介绍就到这里了,基本都是调用封装好的方法,技术上没有太多可说的,他们有很多接口,调用方法基本是一致的,如果应用的好,还是会有不少好处的,这个谁用谁知道!写得不好的地方,或者有误的地方,非常热情的欢迎大家指出,也希望能对大家有所帮助。当然了,写个文章还有一个美好的愿望:希望美团,饿了么可以推出关于团队订单的相关接口(也有可能有接口,只是不给我们申请....)订单还是您们的订单,只是多了一个地方显示,当然,这里多了数据泄露的风险,但是总是有办法降低风险的。还是那句话:大家好,才是真的好!

成为一名优秀的程序员!

时间: 2024-08-06 07:54:14

订餐系统之同步口碑外卖商家菜单与点点送订单的相关文章

订餐系统之同步美团商家订单

引子    早上和往常一样去工商大学打球,除了今天三分比较准外,一切都还是那样的循规蹈矩. 也许股子里还有那么一些不甘平庸,总想着能改变一下如此无趣的按部就班. 转过行政楼,一波一波的学生在谈笑风生.哦,是了,又到拍毕业照片的时间了. 又是一年过去了(也不知从何时起,开始以毕业来计年了),弹指一挥间,已经在这里工作7年半了. 一份工作越是做得久,反到越羞于提起.也许是羞于现状,也是羞于未来的我吧.说不清,道不明,有点乱... 脚步也随着不安的思绪加快了频率,迅速的穿过了人群...未来还需多努力,

订餐系统之同步饿了么商家订单

背景 之前实时获取口碑外卖商家订单,及点点送订单,再使用的我们的调度系统统一调度各个来源的订单,再结合配送员自主抢单,加上配送员队长线上调度,最大限度的让配送员加”顺路单“,提高效率...这套班子不应该因为口碑没了,就变成破铜废铁.暮然回首,原来饿了么也有商户接口,虽然没有淘宝外卖开放平台那么强大,提供好几种语言的示例代码,没有怎么办?自己动手,丰衣足食! 动手之前,还是偷懒的百度了下,以为能找到一些基础代码,或者借鉴之类的,也不知道是没人用呢,还是没人分享... 真没有,有的话,估计也没有这篇

外卖人订餐系统定制建设开发,送外卖订餐系统商业运营版源码

外卖人订餐系统定制开发,外卖人订餐系统商业运营版源码,本人承接搭建,安装,二次开发. 最新外卖人订餐系统8.5运营版源码,支持 PC+WAP+微信订餐开源运营版可二次开发与功能修改. 安装说明: 服务器空间必须支持PHP + MySQL + 伪静态 1.源码包完整上传至服务器空间,并解压 2.将根目录下的 data.sql 导入到你的 MySQL 数据库. 3.修改 config/hopeconfig.php 里面的数据库信息为自己的数据库名称.账号.密码. 4.后台登录地址 :域名/index

终于等到你---订餐系统之负载均衡(nginx+memcached+ftp上传图片+iis)

又见毕业 对面工商大学的毕业生叕在拍毕业照了,一个个脸上都挂满了笑容,也许是满意自己四年的修行,也许是期待步入繁华的社会... 恰逢其时的连绵细雨与满天柳絮,似乎也是在映衬他们心中那些离别的忧伤,与对未来的憧憬和彷徨. 想起当年毕业时,来去匆匆,只留下一张全班合影照和寝室好友的一句:再见,珍重!有点小遗憾! 又见毕业,又是一年,感慨两句,珍惜时间,好好加油,废话完结,回到主题. 背景 自毕业以来,一直在现在公司做订餐系统的开发,那会儿没有口碑,没有饿了么,更别说美团外卖,百度外卖了...因为规模

轻流订餐系统上线,商家做外卖生意更简单

大家好,我是每周为你们送餐的严阿姨, 为了保障每一位同事一上午辛苦的工作后可以准时吃上香喷喷的午饭, 我们特地更新了后厨的:订餐系统 从今天起,部门负责订餐的同学们,可以轻松提交订餐了- 我们将从以下几个方面重点把关, 做到: 1.不晚单 2.不错单 3.好服务 4.好味道 您有新的午餐订单 请及时处理哦~ 有了这个系统,我们后厨的工作人员都会第一时间收到每位同事下的订餐,不仅是短信收到提醒,邮件.微信都能收到哦- 您的订餐已确认 等着上菜吧~ 收到订单后,我们在后台进行确认,确认后我们的新系统

用微信点单 订餐系统打造属于个人的O2O外卖订餐行业商业平台

首先,我不能说我是一个成功的微信达人,我也不能说我是一个优秀的互联网专家,但我就目前所使用的一套订餐系统来讲,正在逐渐的规划一个餐饮行业的商业圈! 我所使用的系统叫"微铺子订餐系统",所购买的是[豪华旗舰版],最主要的功能就是:不限制店铺个数!就是看到这点才选择的这套系统!下面我详细说一下思路. 1.建立一个独立平台官网,便于宣传平台,增加可信度.官网不用太花哨,简单明了,毕竟咱是做微信平台的,还是尽量把客户引到微信来,所以,我准备在主页只放一个大的微信二维码,提示客户,我们只针对微信

微铺子点单系统详细介绍 - 争做国内最专业的微信商店平台,微信外卖订餐系统!

什么是微铺子? 微铺子是国内专业的微信点单系统,集成了外卖.点餐.订座等众多功能.通过微铺子,店家可以在微信上建立店铺,消费者只需关注店家的帐号,即可浏览商品与店家的信息,消费者关注到商家后,根据提示,进行点击点单,简单三步,15秒内,即可完成订餐.店家可以通过电脑后台.电子邮件.短信或无线打印机多种方式即时查看订单,并提供相应的服务. 微铺子系统适用于:餐饮.酒店.水果店.蛋糕店.花店.零售.超市等. 微铺子从创立到与合作商家的长期测试,再到正式投入商用,期间不断根据客户的需求完善产品,不断开

订餐系统之获取淘宝外卖订单

当时的情况是这样的:我们一个客户用了我们的订餐系统,也在淘宝外卖上开了店,但是订餐系统中的订单都要通过调度系统,根据配送员的位置,把订单发送给合适的配送员,所以要把淘宝外卖的订单加到订餐系统中(据说淘宝外卖也是因为味捷外卖才开发这个接口的). 淘宝外卖提供的接口我知道的有三个,1.获取未确认的订单:2.确认订单:3.拒绝订单.所以订餐系统要做的就是从淘宝外卖获取未确认的订单.确认订单并加入订餐系统. 开放平台地址: http://open.taobao.com/doc/api_cat_detai

微铺子点单系统具体介绍 - 争做国内最专业的微信商店平台,微信外卖订餐系统!

什么是微铺子? 微铺子是国内专业的微信点单系统,集成了外卖.点餐.订座等众多功能.通过微铺子,店家能够在微信上建立店铺,消费者仅仅需关注店家的帐号,就可以浏览商品与店家的信息,消费者关注到商家后,依据提示,进行点击点单,简单三步,15秒内,就可以完毕订餐.店家能够通过电脑后台.电子邮件.短信或无线打印机多种方式即时查看订单,并提供对应的服务. 微铺子系统适用于:餐饮.酒店.水果店.蛋糕店.花店.零售.超市等. 微铺子从创立到与合作商家的长期測试,再到正式投入商用,期间不断依据客户的需求完好产品,