/// <summary> /// 微信卡券CODE解码 /// 应用场景: /// 1.商家获取choos_card_info后,将card_id和encrypt_code字段通过解码接口,获取真实code。 /// 2.卡券内跳转外链的签名中会对code进行加密处理,通过调用解码接口获取真实code。 /// 注意事项: /// 1.只能解码本公众号卡券获取的加密code。 /// 2.开发者若从url上获取到加密code,请注意先进行urldecode,否则报错。 /// 3.encrypt_code是卡券的code码经过加密处理得到的加密code码,与code一一对应。 /// 4.开发者只能解密本公众号的加密code,否则报错。 /// </summary> /// <param name="encryptCode"></param> /// <returns></returns> public static string DecryptCode(string encryptCode) { string decryptCode = string.Empty; try { JsonData jCardReq = new JsonData(), jDecryptCode; jCardReq["encrypt_code"] = encryptCode; string decryptCodeUrl = DECRYPT_CODE_API + WxJSAPI.GetAccessToken(); string cardInfo = HttpService.Post(jCardReq.ToJson(), decryptCodeUrl, false, Config.WeChatAPITimeout); jDecryptCode = JsonMapper.ToObject(cardInfo); if (jDecryptCode["errcode"].ToString() == "0" && jDecryptCode["errmsg"].ToString() == "ok") { decryptCode = jDecryptCode["code"].ToString(); } else { throw new Exception("errcode:" + jDecryptCode["errcode"].ToString() + ";" + "errmsg:" + jDecryptCode["errmsg"].ToString()); } } catch (Exception ex) { Log.Error("WxCard", ex.Message); } return(decryptCode); }
/// <summary> /// 核销Code,是核销卡券的唯一接口,开发者可以调用当前接口将用户的优惠券进行核销,该过程不可逆。 /// 1.仅支持核销有效状态的卡券,若卡券处于异常状态,均不可核销。(异常状态包括:卡券删除、未生效、过期、转赠中、转赠退回、失效) /// 2.自定义Code码(use_custom_code为true)的优惠券,在code被核销时,必须调用此接口。用于将用户客户端的code状态变更。自定义code的卡券调用接口时, post数据中需包含card_id,否则报invalid serial code,非自定义code不需上报。 /// </summary> /// <param name="code"></param> /// <param name="cardID"></param> /// <returns></returns> public static bool ConsumeCode(string code, string cardID = null) { bool isConsumed = false; try { JsonData jCardReq = new JsonData(), jCardInfo; jCardReq["code"] = code; if (!string.IsNullOrEmpty(cardID)) { jCardReq["card_id"] = cardID; } string getCardUrl = CONSUME_CODE_API + WxJSAPI.GetAccessToken(); string cardInfo = HttpService.Post(jCardReq.ToJson(), getCardUrl, false, Config.WeChatAPITimeout); jCardInfo = JsonMapper.ToObject(cardInfo); if (jCardInfo["errcode"].ToString() == "0" && jCardInfo["errmsg"].ToString() == "ok") { isConsumed = true; } else { isConsumed = false; } } catch (Exception ex) { Log.Error("WxCard", ex.Message); isConsumed = false; } return(isConsumed); }
/// <summary> /// 获取用户已领取卡券,属于该appid下所有可用卡券,包括正常状态和未生效状态。 /// 只能获取普通优惠券,不能获取“朋友的券” /// </summary> /// <param name="openID"></param> /// <param name="cardID"></param> /// <returns></returns> public static List <WxCard> GetCardList(string openID, string cardID = null) { List <WxCard> cardList = new List <WxCard>(); WxCard wxCard; try { JsonData jCard = new JsonData(), jCardInfo; jCard["openid"] = openID; if (!string.IsNullOrEmpty(cardID)) { jCard["card_id"] = cardID; } string getCardListUrl = GET_CARD_LIST_API + WxJSAPI.GetAccessToken(); string recvMsg = HttpService.Post(jCard.ToJson(), getCardListUrl, false, Config.WeChatAPITimeout); jCardInfo = JsonMapper.ToObject(recvMsg); if (jCardInfo.Keys.Contains("errcode") && jCardInfo["errcode"].ToString() == "0" && jCardInfo.Keys.Contains("errmsg") && jCardInfo["errmsg"].ToString() == "ok") { if (jCardInfo.Keys.Contains("card_list") && jCardInfo["card_list"].IsArray) { for (int i = 0; i < jCardInfo["card_list"].Count; i++) { wxCard = GetCard(jCardInfo["card_list"][i]["card_id"].ToString()); if (wxCard != null) { wxCard.Code = jCardInfo["card_list"][i]["code"].ToString(); } cardList.Add(wxCard); } } } else { throw new Exception("errcode:" + jCardInfo["errcode"].ToString() + ";" + "errmsg:" + jCardInfo["errmsg"].ToString()); } } catch (Exception ex) { Log.Error("WxCard", ex.Message); } return(cardList); }
/// <summary> /// 查询Code /// </summary> /// <param name="cardID"></param> /// <param name="code"></param> /// <param name="checkConsume">是否校验code核销状态</param> /// <returns></returns> public static UserCardStatus GetCode(string cardID, string code, bool checkConsume) { UserCardStatus userCardStatus = UserCardStatus.NORMAL; try { JsonData jCardReq = new JsonData(), jCardInfo; jCardReq["card_id"] = cardID; jCardReq["code"] = code; jCardReq["check_consume"] = checkConsume; string getCardUrl = GET_CODE_API + WxJSAPI.GetAccessToken(); string cardInfo = HttpService.Post(jCardReq.ToJson(), getCardUrl, false, Config.WeChatAPITimeout); jCardInfo = JsonMapper.ToObject(cardInfo); if (checkConsume) { if (jCardInfo["errcode"].ToString() == "0" && jCardInfo["errmsg"].ToString() == "ok") { switch (jCardInfo["user_card_status"].ToString().ToUpper()) { case "NORMAL": userCardStatus = UserCardStatus.NORMAL; break; case "CONSUMED": userCardStatus = UserCardStatus.CONSUMED; break; case "EXPIRE": userCardStatus = UserCardStatus.EXPIRE; break; case "GIFTING": userCardStatus = UserCardStatus.GIFTING; break; case "GIFT_TIMEOUT": userCardStatus = UserCardStatus.GIFT_TIMEOUT; break; case "DELETE": userCardStatus = UserCardStatus.DELETE; break; case "UNAVAILABLE": userCardStatus = UserCardStatus.UNAVAILABLE; break; default: userCardStatus = UserCardStatus.INVALID_SERIAL_CODE; break; } } else { userCardStatus = UserCardStatus.INVALID_SERIAL_CODE; } } else { switch (jCardInfo["user_card_status"].ToString().ToUpper()) { case "NORMAL": userCardStatus = UserCardStatus.NORMAL; break; case "CONSUMED": userCardStatus = UserCardStatus.CONSUMED; break; case "EXPIRE": userCardStatus = UserCardStatus.EXPIRE; break; case "GIFTING": userCardStatus = UserCardStatus.GIFTING; break; case "GIFT_TIMEOUT": userCardStatus = UserCardStatus.GIFT_TIMEOUT; break; case "DELETE": userCardStatus = UserCardStatus.DELETE; break; case "UNAVAILABLE": userCardStatus = UserCardStatus.UNAVAILABLE; break; default: userCardStatus = UserCardStatus.INVALID_SERIAL_CODE; break; } } } catch (Exception ex) { Log.Error("WxCard", ex.Message); } return(userCardStatus); }
/// <summary> /// 根据CardID获取微信卡券的详细信息 /// </summary> /// <param name="cardID">微信卡券ID</param> /// <returns></returns> public static WxCard GetCard(string cardID) { WxCard wxCard = null; try { JsonData jCardReq = new JsonData(), jCardInfo, jBaseInfo = null; jCardReq["card_id"] = cardID; string getCardUrl = GET_CARD_API + WxJSAPI.GetAccessToken(); string cardInfo = HttpService.Post(jCardReq.ToJson(), getCardUrl, false, Config.WeChatAPITimeout); jCardInfo = JsonMapper.ToObject(cardInfo); if (jCardInfo["errcode"].ToString() == "0" && jCardInfo["errmsg"].ToString() == "ok") { wxCard = new WxCard(); switch (jCardInfo["card"]["card_type"].ToString().ToUpper()) { //代金券 case "CASH": JsonData jCash = jCardInfo["card"]["cash"]; jBaseInfo = jCash["base_info"]; wxCard.CardType = WxCardType.CASH; decimal leastCost, reduceCost; //代金券减免金额 if (jCash.Keys.Contains("reduce_cost")) { if (decimal.TryParse(jCash["reduce_cost"].ToString(), out reduceCost)) { wxCard.ReduceCost = reduceCost / 100; } else { wxCard.ReduceCost = 0; } } else { wxCard.ReduceCost = 0; } //代金券起用金额 if (jCash.Keys.Contains("advanced_info") && jCash["advanced_info"].Keys.Contains("use_condition") && jCash["advanced_info"]["use_condition"].Keys.Contains("least_cost")) { if (decimal.TryParse(jCash["advanced_info"]["use_condition"]["least_cost"].ToString(), out leastCost)) { wxCard.LeastCost = leastCost / 100; } else { wxCard.LeastCost = 0; } } else { //无门槛代金券没有起用金额字段least_cost wxCard.LeastCost = 0; } break; //折扣券 case "DISCOUNT": JsonData jDiscount = jCardInfo["card"]["discount"]; jBaseInfo = jDiscount["base_info"]; wxCard.CardType = WxCardType.DISCOUNT; int discount; if (int.TryParse(jDiscount["discount"].ToString(), out discount)) { wxCard.Discount = discount; } else { wxCard.Discount = 0; } break; //团购券 case "GROUPON": JsonData jGroupon = jCardInfo["card"]["groupon"]; jBaseInfo = jGroupon["base_info"]; wxCard.CardType = WxCardType.GROUPON; wxCard.DealDetail = jGroupon["deal_detail"].ToString(); break; //礼品券 case "GIFT": JsonData jGift = jCardInfo["card"]["gift"]; jBaseInfo = jGift["base_info"]; wxCard.CardType = WxCardType.GIFT; wxCard.Gift = jGift["gift"].ToString(); break; //通用券 case "GENERAL_COUPON": JsonData jGeneralCoupon = jCardInfo["card"]["general_coupon"]; jBaseInfo = jGeneralCoupon["base_info"]; wxCard.CardType = WxCardType.GENERAL_COUPON; break; //会员卡 case "MEMBER_CARD": JsonData jMemberCard = jCardInfo["card"]["member_card"]; jBaseInfo = jMemberCard["base_info"]; wxCard.CardType = WxCardType.MEMBER_CARD; //wxCard.SupplyBalance = jMemberCard["supply_balance"].ToString() == "true" ? true : false; //wxCard.SupplyBonus = jMemberCard["supply_bonus"].ToString() == "true" ? true : false; //wxCard.BonusCleared = jMemberCard["bonus_cleared"].ToString(); //wxCard.BonusRules = jMemberCard["bonus_rules"].ToString(); //wxCard.BalanceRules = jMemberCard["balance_rules"].ToString(); //wxCard.Prerogative = jMemberCard["prerogative"].ToString(); //wxCard.BindOldCardUrl = jMemberCard["bind_old_card_url"].ToString(); //wxCard.ActivateUrl = jMemberCard["activate_url"].ToString(); break; //景点门票 case "SCENIC_TICKET": JsonData jScenicTicket = jCardInfo["card"]["scenic_ticket"]; jBaseInfo = jScenicTicket["base_info"]; wxCard.CardType = WxCardType.SCENIC_TICKET; break; //电影票 case "MOVIE_TICKET": JsonData jMovieTicket = jCardInfo["card"]["movie_ticket"]; jBaseInfo = jMovieTicket["base_info"]; wxCard.CardType = WxCardType.MOVIE_TICKET; break; //飞机票 case "BOARDING_PASS": JsonData jBoardingPass = jCardInfo["card"]["boarding_pass"]; jBaseInfo = jBoardingPass["base_info"]; wxCard.CardType = WxCardType.BOARDING_PASS; break; //会议门票 case "MEETING_TICKET": JsonData jMeetingTicket = jCardInfo["card"]["meeting_ticket"]; jBaseInfo = jMeetingTicket["base_info"]; wxCard.CardType = WxCardType.MEETING_TICKET; break; //汽车票 case "BUS_TICKET": JsonData jBusTicket = jCardInfo["card"]["bus_ticket"]; jBaseInfo = jBusTicket["base_info"]; wxCard.CardType = WxCardType.BUS_TICKET; break; default: throw new Exception("未知的微信卡券类型:" + jCardInfo["card"]["card_type"].ToString()); } if (jBaseInfo != null) { wxCard.CardID = cardID; wxCard.LogoUrl = jBaseInfo["logo_url"].ToString(); wxCard.BrandName = jBaseInfo["brand_name"].ToString(); wxCard.Title = jBaseInfo["title"].ToString(); wxCard.SubTitle = jBaseInfo["sub_title"].ToString(); wxCard.CanShare = jBaseInfo["can_share"].ToString() == "true" ? true : false; wxCard.CanGiveFriend = jBaseInfo["can_give_friend"].ToString() == "true" ? true : false; int getLimit, quantity, totalQuantity; if (int.TryParse(jBaseInfo["get_limit"].ToString(), out getLimit)) { wxCard.GetLimit = getLimit; } else { wxCard.GetLimit = 1; } if (int.TryParse(jBaseInfo["sku"]["quantity"].ToString(), out quantity)) { wxCard.Quantity = quantity; } else { wxCard.Quantity = 0; } if (int.TryParse(jBaseInfo["sku"]["total_quantity"].ToString(), out totalQuantity)) { wxCard.TotalQuantity = totalQuantity; } else { wxCard.TotalQuantity = 0; } switch (jBaseInfo["code_type"].ToString().ToUpper()) { case "CODE_TYPE_TEXT": wxCard.CodeType = WxCodeType.CODE_TYPE_TEXT; break; case "CODE_TYPE_BARCODE": wxCard.CodeType = WxCodeType.CODE_TYPE_BARCODE; break; case "CODE_TYPE_QRCODE": wxCard.CodeType = WxCodeType.CODE_TYPE_QRCODE; break; case "CODE_TYPE_ONLY_QRCODE": wxCard.CodeType = WxCodeType.CODE_TYPE_ONLY_QRCODE; break; case "CODE_TYPE_ONLY_BARCODE": wxCard.CodeType = WxCodeType.CODE_TYPE_ONLY_BARCODE; break; case "CODE_TYPE_NONE": wxCard.CodeType = WxCodeType.CODE_TYPE_NONE; break; } switch (jBaseInfo["status"].ToString().ToUpper()) { case "CARD_STATUS_NOT_VERIFY": wxCard.Status = CardStatus.CARD_STATUS_NOT_VERIFY; break; case "CARD_STATUS_VERIFY_FAIL": wxCard.Status = CardStatus.CARD_STATUS_VERIFY_FAIL; break; case "CARD_STATUS_VERIFY_OK": wxCard.Status = CardStatus.CARD_STATUS_VERIFY_OK; break; case "CARD_STATUS_USER_DELETE": wxCard.Status = CardStatus.CARD_STATUS_USER_DELETE; break; case "CARD_STATUS_DISPATCH": wxCard.Status = CardStatus.CARD_STATUS_DISPATCH; break; } switch (jBaseInfo["date_info"]["type"].ToString().ToUpper()) { case "DATE_TYPE_FIX_TIME_RANGE": wxCard.DateType = AvailableDateType.DATE_TYPE_FIX_TIME_RANGE; wxCard.BeginTime = UtilityHelper.TimestampToDateTime(jBaseInfo["date_info"]["begin_timestamp"].ToString()); wxCard.EndTime = UtilityHelper.TimestampToDateTime(jBaseInfo["date_info"]["end_timestamp"].ToString()); break; case "DATE_TYPE_FIX_TERM": wxCard.DateType = AvailableDateType.DATE_TYPE_FIX_TERM; int fixedTerm, fixedBeginTerm; if (int.TryParse(jBaseInfo["date_info"]["fixed_term"].ToString(), out fixedTerm)) { wxCard.FixedTerm = fixedTerm; } else { wxCard.FixedTerm = 0; } if (int.TryParse(jBaseInfo["date_info"]["fixed_begin_term"].ToString(), out fixedBeginTerm)) { wxCard.FixedBeginTerm = fixedBeginTerm; } else { wxCard.FixedBeginTerm = 0; } break; case "DATE_TYPE_PERMANENT": wxCard.DateType = AvailableDateType.DATE_TYPE_PERMANENT; break; } } else { throw new Exception("未能获取微信卡券base_info"); } } else { throw new Exception("errcode:" + jCardInfo["errcode"].ToString() + ";" + "errmsg:" + jCardInfo["errmsg"].ToString()); } } catch (Exception ex) { Log.Error("WxCard", ex.Message); return(null); } return(wxCard); }
/// <summary> /// 获取微信用户基本信息 /// API参考:https://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html /// </summary> /// <param name="wxUsers"></param> public static void RefreshWxUserInfo(List <WeChatUser> wxUsers) { string wxUserInfoAPI = string.Format(@"https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token={0}", WxJSAPI.GetAccessToken()); string recvMsg; JsonData jUserList = new JsonData(), jUserInfoList = new JsonData(), jUser; jUserList["user_list"] = new JsonData(); for (int i = 0; i < wxUsers.Count; i++) { jUser = new JsonData(); jUser["openid"] = wxUsers[i].OpenID; jUserList["user_list"].Add(jUser); //一次最多拉取100个用户的微信信息 if (jUserList["user_list"].Count == 100 || i == (wxUsers.Count - 1)) { recvMsg = HttpService.Post(jUserList.ToJson(), wxUserInfoAPI, false, Config.WeChatAPITimeout); jUserInfoList = JsonMapper.ToObject(recvMsg); //用获取的信息刷新形参 if (jUserInfoList != null && jUserInfoList.Keys.Contains("user_info_list") && jUserInfoList["user_info_list"].IsArray) { //遍历拉取的微信用户JSON消息包,并刷新形参 for (int j = 0; j < jUserInfoList["user_info_list"].Count; j++) { if (jUserInfoList["user_info_list"][j].Keys.Contains("subscribe") && jUserInfoList["user_info_list"][j].Keys.Contains("openid")) { WeChatUser user = wxUsers.Find(wxUser => { if (wxUser.OpenID == jUserInfoList["user_info_list"][j]["openid"].ToString()) { return(true); } return(false); }); if (user != default(WeChatUser)) { //此用户关注公众号,则返回详细信息 if (jUserInfoList["user_info_list"][j]["subscribe"].ToString() == "1") { user.IsSubscribe = true; user.NickName = jUserInfoList["user_info_list"][j].Keys.Contains("nickname") ? jUserInfoList["user_info_list"][j]["nickname"].ToString() : user.NickName; user.Sex = jUserInfoList["user_info_list"][j].Keys.Contains("sex") ? (jUserInfoList["user_info_list"][j]["sex"].ToString() == "1" ? true : false) : user.Sex; user.Country = jUserInfoList["user_info_list"][j].Keys.Contains("country") ? jUserInfoList["user_info_list"][j]["country"].ToString() : user.Country; user.Province = jUserInfoList["user_info_list"][j].Keys.Contains("province") ? jUserInfoList["user_info_list"][j]["province"].ToString() : user.Province; user.City = jUserInfoList["user_info_list"][j].Keys.Contains("city") ? jUserInfoList["user_info_list"][j]["city"].ToString() : user.City; user.HeadImgUrl = jUserInfoList["user_info_list"][j].Keys.Contains("headimgurl") ? jUserInfoList["user_info_list"][j]["headimgurl"].ToString() : user.HeadImgUrl; user.UnionID = jUserInfoList["user_info_list"][j].Keys.Contains("unionid") ? jUserInfoList["user_info_list"][j]["unionid"].ToString() : user.UnionID; } else { user.IsSubscribe = false; user.UnionID = jUserInfoList["user_info_list"][j].Keys.Contains("unionid") ? jUserInfoList["user_info_list"][j]["unionid"].ToString() : user.UnionID; } } } } } jUserList.Clear(); } } }
/// <summary> /// 发送模板消息 /// </summary> /// <param name="listReceiver">消息接收者</param> /// <param name="jTmplMsg">模板消息体</param> /// <returns>微信模板消息返回值</returns> public static JsonData SendTmplMsg(List <string> listReceiver, JsonData jTmplMsg) { string recvMsg; bool isSuccess = false; JsonData jRet = new JsonData(), jRecv; int tryTimes = 0; listReceiver.ForEach(receiver => { jTmplMsg["touser"] = receiver; do { //调用微信模板消息接口,并获取返回报文 Log.Debug("WxTmplMsg", "SendOrderMsg request" + jTmplMsg.ToJson()); recvMsg = HttpService.Post(jTmplMsg.ToJson(), WxTmplMsg.WxTmplMsgUrl + WxJSAPI.GetAccessToken(), false, Config.WeChatAPITimeout); Log.Debug("WxTmplMsg", "SendOrderMsg response" + recvMsg); if (!string.IsNullOrEmpty(recvMsg)) { jRecv = JsonMapper.ToObject(recvMsg); if (jRecv.Keys.Contains("errcode") && jRecv["errcode"] != null) { switch (jRecv["errcode"].ToString()) { case "0": isSuccess = true; break; case "40001": case "40002": isSuccess = false; WxJSAPI.RefreshAccessToken(); break; default: isSuccess = false; break; } } jRet.Add(jRecv); } tryTimes++; } while (!isSuccess && tryTimes < 10); }); return(jRet); }