C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试

在上篇《C#开发微信门户及应用(22)-微信小店的开发和使用》里面介绍了一些微信小店的基础知识,以及对应的对象模型,本篇继续微信小店的主题,介绍其中API接口的封装和测试使用。微信小店的相关对象模型,基本上包括了常规的商品、商品分组、货架、库存、订单这些模型,还有商品分类,商品分类属性、商品分类SKU、快递邮寄模板、图片管理等功能。本文介绍的接口封装也就是基于这些内容进行的,并针对接口的实现进行测试和使用。

1、商品管理接口的定义

前面文章介绍了微信小店的对象模型,如下所示。



这个图形基本上覆盖了微信小店的相关对象,并介绍了它们之间的关系了。
我们从基础的商品信息管理入手,我们知道,商品接口包含了增加、修改、查询、删除等接口,如下所示。



商品信息是所有微店的基础,因此对它的管理操作,我们需要更加清晰和完善。
综上所述的功能,我们可以定义好微信商品的接口如下所示。
#region 商品信息
/// <summary>
/// 创建商品
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="merchantJson">商品对象</param>
/// <returns></returns>
AddMerchantResult AddMerchant(string accessToken, MerchantJson merchantJson);

/// <summary>
/// 删除商品
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="productId">商品ID</param>
/// <returns></returns>
CommonResult DeleteMerchant(string accessToken, string productId);

/// <summary>
/// 修改商品
/// product_id表示要更新的商品的ID,其他字段说明请参考增加商品接口。
/// 从未上架的商品所有信息均可修改,否则商品的名称(name)、商品分类(category)、商品属性(property)这三个字段不可修改。
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="merchantJson">修改商品的信息</param>
/// <returns></returns>
CommonResult UpdateMerchant(string accessToken, MerchantJson merchantJson);

/// <summary>
/// 根据ID查询商品信息,如果成功返回MerchantJson信息,否则返回null
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="productId">商品的Id</param>
/// <returns></returns>
MerchantJson GetMerchant(string accessToken, string productId);

/// <summary>
/// 获取指定状态的所有商品
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="status">商品状态(0-全部, 1-上架, 2-下架)</param>
/// <returns></returns>
List<MerchantJson> GetMerchantByStatus(string accessToken, int status);

/// <summary>
/// 商品上下架
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="status">商品上下架标识(0-下架, 1-上架)</param>
/// <returns></returns>
CommonResult UpdateMerchantStatus(string accessToken, string productId, int status); 

#endregion

当然,微信的商品还包含了分类、分类属性、分类SKU的基础管理,因此商品管理还需要增加这个内容



它们的功能接口定义如下所示。通过下面的接口,我们就很容易实现商品分类(不是商品分组)、SKU信息、和分类属性等信息的获取操作了。

#region 商品分类及属性
/// <summary>
/// 获取指定分类的所有子分类
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="cateId">大分类ID(根节点分类id为1)</param>
/// <returns></returns>
List<SubCategory> GetSub(string accessToken, int cate_id);

/// <summary>
/// 获取指定子分类的所有SKU
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="cateId">商品子分类ID</param>
/// <returns></returns>
List<SubCategorySku> GetSku(string accessToken, int cate_id);

/// <summary>
/// 获取指定分类的所有属性
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="cateId">分类ID</param>
/// <returns></returns>
List<SubCategoryProperty> GetProperty(string accessToken, int cate_id); 

#endregion

2、商品管理接口的实现

上面的接口定义了对应商品的接口。

对于接口的实现,我们一般都是根据官方网站的接口说明,提交到那个URL,并且是POST那些数据,然后整理成一个常规的处理方式,获得结果并转换为对应的对象即可,如添加商品操作的实现代码如下所示。

/// <summary>
/// 创建商品
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="merchantJson">商品对象</param>
/// <returns></returns>
public AddMerchantResult AddMerchant(string accessToken, MerchantJson merchantJson)
{
    var url = string.Format("https://api.weixin.qq.com/merchant/create?access_token={0}", accessToken);
    string postData = merchantJson.ToJson();

    return JsonHelper<AddMerchantResult>.ConvertJson(url, postData);

而返回结果,这是定义一个对象来获得添加商品的ID等内容,如下所示。

/// <summary>
/// 创建商品信息的返回结果
/// </summary>
public class AddMerchantResult : ErrorJsonResult
{
    /// <summary>
    /// 商品ID
    /// </summary>
    public string product_id { get; set; }
}

而基类这是常规的响应内容

/// <summary>
/// 微信返回Json结果的错误数据
/// </summary>
public class ErrorJsonResult 
{
    /// <summary>
    /// 返回代码
    /// </summary>
    public ReturnCode errcode { get; set; }

    /// <summary>
    /// 错误消息
    /// </summary>
    public string errmsg { get; set; }
}

通过这些对象的定义,添加商品后,我们就知道操作是否成功,如果添加成功,返回了一个刚刚创建的ID给我们使用,我们可以进行查询具体的商品信息或者进行修改、删除等操作的。

而对商品信息的修改或者删除的操作,都是返回一个是否成功的记录就可以了,因此我们定义了一个统一的回应对象CommonResult。商品修改、删除的接口实现代码如下所示。

由于代码我都进行高度的完善和整理,对于各种处理的代码都相对比较容易理解的了。

/// <summary>
/// 删除商品
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="productId">商品ID</param>
/// <returns></returns>
public CommonResult DeleteMerchant(string accessToken, string productId)
{
    var url = string.Format("https://api.weixin.qq.com/merchant/del?access_token={0}", accessToken);
    var data = new
    {
        product_id = productId
    };
    string postData = data.ToJson();

    return Helper.GetExecuteResult(url, postData);
}

/// <summary>
/// 修改商品
/// product_id表示要更新的商品的ID,其他字段说明请参考增加商品接口。
/// 从未上架的商品所有信息均可修改,否则商品的名称(name)、商品分类(category)、商品属性(property)这三个字段不可修改。
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="merchantJson">修改商品的信息</param>
/// <returns></returns>
public CommonResult UpdateMerchant(string accessToken, MerchantJson merchantJson)
{
    var url = string.Format("https://api.weixin.qq.com/merchant/update?access_token={0}", accessToken);
    string postData = merchantJson.ToJson();

    return Helper.GetExecuteResult(url, postData);
}

为了获取商品的详细信息,我们需要定义一个商品的实体对象,以便我们把获取到的信息转换为实体类信息,方便使用和处理。
商品的信息,包含了不少细小定义的类,他们构成了商品的各个部分的内容,主体的实体类信息如下所示。



定义好相对比较复杂的商品信息实体后,我们就可以通过对象进行处理了。
获取商品详细信息的实现代码如下所示。

/// <summary>
/// 根据ID查询商品信息,如果成功返回MerchantJson信息,否则返回null
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="productId">商品的Id</param>
/// <returns></returns>
public MerchantJson GetMerchant(string accessToken, string productId)
{
    var url = string.Format("https://api.weixin.qq.com/merchant/get?access_token={0}", accessToken);
    var data = new
    {
        product_id = productId
    };
    string postData = data.ToJson();

    MerchantJson merchant = null;
    GetMerchantResult result = JsonHelper<GetMerchantResult>.ConvertJson(url, postData);
    if (result != null)
    {
        merchant = result.product_info;
    }
    return merchant;
}

虽然商品的实体信息很复杂,但是一旦我们定义好,我们就很容易对结果进行转换并处理了,上面的代码并不是很难理解,主要就是提交数据后,对数据进行转换而已。

当然,我们还可以获取不同状态的商品列表内容,如下代码所示。

/// <summary>
/// 获取指定状态的所有商品
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="status">商品状态(0-全部, 1-上架, 2-下架)</param>
/// <returns></returns>
public List<MerchantJson> GetMerchantByStatus(string accessToken, int status)
{
    var url = string.Format("https://api.weixin.qq.com/merchant/getbystatus?access_token={0}", accessToken);
    var data = new
    {
        status = status
    };
    string postData = data.ToJson();

    List<MerchantJson> list = new List<MerchantJson>();
    GetMerchantByStatus result = JsonHelper<GetMerchantByStatus>.ConvertJson(url, postData);
    if (result != null)
    {
        list = result.products_info;
    }
    return list;
}

我们添加商品的时候,商品的分类信息、分类属性、分类SKU信息也都是很重要的内容,我们需要指定对应商品分类才能添加到微信小店里面。

获取商品分类的操作实现代码如下所示。

/// <summary>
/// 获取指定分类的所有子分类
/// </summary>
/// <param name="accessToken">调用接口凭证</param>
/// <param name="cateId">大分类ID(根节点分类id为1)</param>
/// <returns></returns>
public List<SubCategory> GetSub(string accessToken, int cate_id)
{
    var url = string.Format("https://api.weixin.qq.com/merchant/category/getsub?access_token={0}", accessToken);
    var data = new
    {
        cate_id = cate_id
    };
    string postData = data.ToJson();

    List<SubCategory> list = new List<SubCategory>();
    GetSubResult result = JsonHelper<GetSubResult>.ConvertJson(url, postData);
    if(result != null)
    {
        list = result.cate_list;
    }
    return list;
}

3、商品管理接口的测试

为了验证我们开发的接口,我们需要增加一个测试项目,方便对我们编写的API进行测试,测试完全成功后,我们才能正式在项目中使用。
我为了方便,创建了一个Winform项目,分别对各个接口进行测试。



本篇主要介绍商品管理方面的接口,因此下面主要介绍其中商品管理部分的接口测试代码,以及对应的结果。
其中商品常规管理的接口测试代码如下所示。

private void btnMerchant_Click(object sender, EventArgs e)
{
    //商品管理
    IMerchantApi api = new MerchantApi();

    //获取所有商品信息
    Console.WriteLine("获取所有商品信息");
    List<MerchantJson> list = api.GetMerchantByStatus(token, 0);
    foreach(MerchantJson json in list)
    {
        Console.WriteLine(json.ToJson());
        Console.WriteLine();
    }

    //更新商品状态
    Console.WriteLine("更新商品状态");
    foreach (MerchantJson json in list)
    {
        CommonResult result = api.UpdateMerchantStatus(token, json.product_id, 1);
        Console.WriteLine("商品ID:{0},商品名称:{1}, 操作:{2}", 
            json.product_id, json.product_base.name, result.Success ? "成功" : "失败");
    }

    Thread.Sleep(1000);
    //根据商品ID获取商品信息
    Console.WriteLine("根据商品ID获取商品信息");
    foreach (MerchantJson json in list)
    {
        MerchantJson getJson = api.GetMerchant(token, json.product_id);
        if(json != null)
        {
            Console.WriteLine("商品ID:{0},商品名称:{1}", getJson.product_id, getJson.product_base.name);
        }
    }
}

测试后结果如下所示(就是返回我微店铺里面的商品信息),一切正常。

返回的商品Json数据如下所示:

{
  "product_id": "pSiLnt6FYDuFtrRRPMlkdKbye-rE",
  "product_base": {
    "category_id": [
      "537103312"
    ],
    "property": [
      {
        "id": "类型",
        "vid": "软件产品设计"
      }
    ],
    "name": "代码生成工具Database2Sharp",
    "sku_info": [],
    "main_img": "http://mmbiz.qpic.cn/mmbiz/mLqH9gr11Gyb2sgiaelcsxYtQENGePp0Rb3AZKbjkicnKTUNBrEdo7Dyic97ar46SoAfKRB5x2R94bDUdNpgqiaZzA/0",
    "img": [
      "http://mmbiz.qpic.cn/mmbiz/mLqH9gr11Gyb2sgiaelcsxYtQENGePp0RiaheJmVXm7tbvTYUQV7OF3DgfGiaQVMh3WbeEcGDOQQiajQXGKK9tfoeA/0"
    ],
    "detail": [],
    "buy_limit": 0,
    "detail_html": ""
  },
  "sku_list": [
    {
      "sku_id": "",
      "ori_price": 100000,
      "price": 50000,
      "icon_url": "",
      "quantity": 1100,
      "product_code": ""
    }
  ],
  "attrext": {
    "location": {
      "country": "中国",
      "province": "广东",
      "city": "广州",
      "address": ""
    },
    "isPostFree": 1,
    "isHasReceipt": 0,
    "isUnderGuaranty": 0,
    "isSupportReplace": 0
  },
  "delivery_info": {
    "delivery_type": 0,
    "template_id": 175807970,
    "express": [
      {
        "id": 10000027,
        "price": 0
      },
      {
        "id": 10000028,
        "price": 0
      },
      {
        "id": 10000029,
        "price": 0
      }
    ]
  },
  "status": 1
}

测试的部分结果输出如下所示。



另外,“商品维护管理”的功能测试主要就是测试商品的增加、修改、删除操作,具体代码如下所示。

private void btnMerchantEdit_Click(object sender, EventArgs e)
{
    IMerchantApi api = new MerchantApi();
    string img1 = "http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjD3ulEKogfsiaua49pvLfUS8Ym0GSYjViaLic0FD3vN0V8PILcibEGb2fPfEOmw/0";
    string img2 = "http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjD3ul1UcLcwxrFdwTKYhH9Q5YZoCfX4Ncx655ZK6ibnlibCCErbKQtReySaVA/0";
    string img3 = "http://mmbiz.qpic.cn/mmbiz/4whpV1VZl28bJj62XgfHPibY3ORKicN1oJ4CcoIr4BMbfA8LqyyjzOZzqrOGz3f5KWq1QGP3fo6TOTSYD3TBQjuw/0";

    //商品增删改处理
    MerchantJson merchant = new MerchantJson();
    merchant.product_base = new Merchant_base();
    merchant.product_base.name = "测试产品";
    merchant.product_base.category_id.Add("537074298");
    merchant.product_base.img = new List<string>() { img1, img2, img3 };
    merchant.product_base.main_img = img1;
    merchant.product_base.detail.AddRange(new List<MerchantDetail>() {
            new MerchantDetail()
            {
                text = "test first"
            },
            new MerchantDetail()
            {
                img = img2
            }, new MerchantDetail()
            {
                text = "test again"
            }
    });
    merchant.product_base.property.AddRange(new List<MerchantProperty>(){
        new MerchantProperty
        {
            id= "1075741879",
            vid="1079749967"
        },
        new MerchantProperty{
            id= "1075754127",
            vid= "1079795198"
        },
        new MerchantProperty(){
            id= "1075777334",
            vid= "1079837440"
        }
    });
    merchant.product_base.sku_info.AddRange(new List<MerchantSku>(){
        new MerchantSku{
            id=  "1075741873",
            vid = new List<string>() {
                "1079742386",
                "1079742363"
            }
        }
    });
    merchant.product_base.buy_limit = 10;
    //merchant.product_base.detail_html = "<div class=\"item_pic_wrp\" style=\"margin-bottom:8px;font-size:0;\"><img class=\"item_pic\" style=\"width:100%;\" alt=\"\" src=\"http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjD3ulEKogfsiaua49pvLfUS8Ym0GSYjViaLic0FD3vN0V8PILcibEGb2fPfEOmw/0\" ></div><p style=\"margin-bottom:11px;margin-top:11px;\">test</p><div class=\"item_pic_wrp\" style=\"margin-bottom:8px;font-size:0;\"><img class=\"item_pic\" style=\"width:100%;\" alt=\"\" src=\"http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjD3ul1UcLcwxrFdwTKYhH9Q5YZoCfX4Ncx655ZK6ibnlibCCErbKQtReySaVA/0\" ></div><p style=\"margin-bottom:11px;margin-top:11px;\">test again</p>";
    merchant.sku_list.AddRange(new List<MerchantSku_list>()
    {
        new MerchantSku_list(){
        sku_id="1075741873:1079742386",
        price=30,
        icon_url="http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjD3ulEKogfsiaua49pvLfUS8Ym0GSYjViaLic0FD3vN0V8PILcibEGb2fPfEOmw/0",
        quantity=800,
        product_code="testing",
        ori_price=9000000
        },
        new MerchantSku_list(){
            sku_id="1075741873:1079742363",
            price=30,
            icon_url="http://mmbiz.qpic.cn/mmbiz/4whpV1VZl28bJj62XgfHPibY3ORKicN1oJ4CcoIr4BMbfA8LqyyjzOZzqrOGz3f5KWq1QGP3fo6TOTSYD3TBQjuw/0",
            quantity=800,
            product_code="testingtesting",
            ori_price=9000000
        }
    });
    merchant.attrext = new MerchantAttrext()
    {
        location = new MerchantLocation()
        {
            country = "中国",
            province = "广东省",
            city = "广州市",
            address = "T.I.T创意园"
        },
        isPostFree = 0,
        isHasReceipt = 1,
        isUnderGuaranty = 0,
        isSupportReplace = 0
    };
    merchant.delivery_info = new MerchantDelivery()
    {
        delivery_type = 0,
        template_id = 0,
        express = new List<MerchantExpress>(){
        new MerchantExpress() {
            id=10000027, 
            price=100
        }, 
        new MerchantExpress(){
            id=10000028, 
            price=100
        }, 
        new MerchantExpress(){
            id=10000029, 
            price=100
        }}
    };

    Console.WriteLine(merchant.ToJson());

    AddMerchantResult result = api.AddMerchant(token, merchant);
    Console.WriteLine("添加商品:{0}", result.product_id);
    if (!string.IsNullOrEmpty(result.product_id))
    {
        //更新商品
        merchant.product_id = result.product_id;
        merchant.product_base.name = "测试产品22";
        CommonResult updateResult = api.UpdateMerchant(token, merchant);
        Console.WriteLine("更新商品:{0}", updateResult.Success ? "成功" : "失败");


        CommonResult deleteResult = api.DeleteMerchant(token, merchant.product_id);
        Console.WriteLine("删除商品:{0}", deleteResult.Success ? "成功" : "失败");
    }
}

测试的输出结果如下所示(一切成功)。



以上就是我对商品管理接口的API定义和实现,以及对接口进行测试的阐述,基本上把所有相关的内容都贴出来了,希望大家能够对微店开发部分,有更深入的了解和认识。

如果对这个《C#开发微信门户及应用》系列感兴趣,可以关注我的其他文章.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,069评论 4 358
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,212评论 1 287
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,912评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,424评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,741评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,194评论 1 206
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,553评论 2 307
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,289评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,923评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,251评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,775评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,144评论 2 249
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,698评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,936评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,658评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,214评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,159评论 2 258

推荐阅读更多精彩内容