WeChatFunction.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. using System;
  2. using System.Collections.Generic;
  3. using Library;
  4. using LitJson;
  5. using System.Linq;
  6. using System.Security.Cryptography.X509Certificates;
  7. using System.Security.Cryptography;
  8. using System.Text;
  9. using System.IO;
  10. using System.Net;
  11. using MySystem.Models;
  12. using Org.BouncyCastle.Crypto.Modes;
  13. using Org.BouncyCastle.Crypto.Parameters;
  14. using Org.BouncyCastle.Crypto.Engines;
  15. namespace MySystem
  16. {
  17. public class WeChatFunction
  18. {
  19. public readonly static WeChatFunction Instance = new WeChatFunction();
  20. private WeChatFunction()
  21. { }
  22. public string AppId = "wx6e074b8e07b6577e";
  23. public string AppSecret = "883f9ef7831d8ca82168c3fd6dcfb750";
  24. public string MchId = "1613112281";
  25. public string MchName = "四川省润观米科技有限公司";
  26. public string plateMchId = "1647817950";
  27. public string serialNo = "14E9FD7F0981BEA23F94137607521CB51C4F76EF";
  28. public string getSerialNo = "61D99F7218B487788E35D6C4E3ED398E0979D3F6";
  29. #region 服务商平台商户进件提交申请单API
  30. public string MerchantCreate(MerchantAddInfo info, MerchantInfo merchant)
  31. {
  32. // pubkey = GetPublicKey();
  33. Dictionary<string, object> result = new Dictionary<string, object>();
  34. result.Add("business_code", info.BusinessCode); //业务申请编号
  35. WebCMSEntities dbpxc = new WebCMSEntities();
  36. //超级管理员信息
  37. Dictionary<string, object> contact_info = new Dictionary<string, object>();
  38. contact_info.Add("contact_type", "LEGAL"); //超级管理员姓名
  39. contact_info.Add("contact_name", RSAEncrypt(info.ContactName)); //超级管理员姓名
  40. contact_info.Add("contact_id_number", RSAEncrypt(info.ContactIdNumber)); //超级管理员身份证件号码
  41. // contact_info.Add("openid", info.OpenId); //超级管理员微信openid
  42. contact_info.Add("mobile_phone", RSAEncrypt(info.MobilePhone)); //联系手机
  43. contact_info.Add("contact_email", RSAEncrypt(info.ContactEmail)); //联系邮箱
  44. result.Add("contact_info", contact_info);
  45. //主体资料
  46. Dictionary<string, object> subject_info = new Dictionary<string, object>();
  47. subject_info.Add("subject_type", info.SubjectType); //主体类型
  48. Dictionary<string, object> business_license_info = new Dictionary<string, object>();
  49. business_license_info.Add("license_copy", GetMediaId("/" + info.LicenseCopy)); //营业执照照片
  50. business_license_info.Add("license_number", info.LicenseNumber); //注册号/统一社会信用代码
  51. business_license_info.Add("merchant_name", merchant.Name); //商户名称
  52. business_license_info.Add("legal_person", info.LegalPerson); //个体户经营者/法人姓名
  53. subject_info.Add("business_license_info", business_license_info); //营业执照
  54. // Dictionary<string, object> certificate_info = new Dictionary<string, object>();
  55. // certificate_info.Add("cert_copy", GetMediaId("/" + info.CertCopy)); //登记证书照片
  56. // certificate_info.Add("cert_type", info.CertType); //登记证书类型
  57. // certificate_info.Add("cert_number", info.CertNumber); //证书号
  58. // certificate_info.Add("merchant_name", info.CertMerchantName); //商户名称
  59. // certificate_info.Add("company_address", info.CompanyAddress); //注册地址
  60. // certificate_info.Add("legal_person", info.CertLegalPerson); //法人姓名
  61. // certificate_info.Add("period_begin", CheckForever(info.PeriodBegin)); //有效期限开始日期
  62. // certificate_info.Add("period_end", CheckForever(info.PeriodEnd)); //有效期限结束日期
  63. // subject_info.Add("certificate_info", certificate_info); //登记证书
  64. // Dictionary<string, object> organization_info = new Dictionary<string, object>();
  65. // organization_info.Add("organization_copy", GetMediaId("/" + info.OrganizationCopy)); //组织机构代码证照片
  66. // organization_info.Add("organization_code", info.OrganizationCode); //组织机构代码
  67. // organization_info.Add("org_period_begin", CheckForever(info.OrgPeriodBegin)); //组织机构代码证有效期开始日期
  68. // organization_info.Add("org_period_end", CheckForever(info.OrgPeriodEnd)); //组织机构代码证有效期结束日期
  69. // subject_info.Add("organization_info", organization_info); //组织机构代码证
  70. // subject_info.Add("certificate_letter_copy", GetMediaId("/" + info.CertificateLetterCopy)); //单位证明函照片
  71. Dictionary<string, object> identity_info = new Dictionary<string, object>();
  72. info.IdDocType = "IDENTIFICATION_TYPE_IDCARD";
  73. identity_info.Add("id_holder_type", "LEGAL"); //证件持有人类型
  74. identity_info.Add("id_doc_type", info.IdDocType); //证件类型
  75. Dictionary<string, object> id_card_info = new Dictionary<string, object>();
  76. id_card_info.Add("id_card_copy", GetMediaId("/" + info.IdCardCopy)); //身份证人像面照片
  77. id_card_info.Add("id_card_national", GetMediaId("/" + info.IdCardNational)); //身份证人像面照片
  78. id_card_info.Add("id_card_name", RSAEncrypt(info.IdCardName)); //身份证姓名
  79. id_card_info.Add("id_card_number", RSAEncrypt(info.IdCardNumber)); //身份证号码
  80. id_card_info.Add("id_card_address", RSAEncrypt(info.IdCardAddress)); //身份证居住地址
  81. id_card_info.Add("card_period_begin", CheckForever(info.CardPeriodBegin)); //身份证有效期开始时间
  82. id_card_info.Add("card_period_end", CheckForever(info.CardPeriodEnd)); //身份证有效期结束时间
  83. identity_info.Add("id_card_info", id_card_info); //身份证信息
  84. // identity_info.Add("owner", info.Owner == 1 ? true : false); //经营者/法人是否为受益人
  85. if(info.SubjectType == "SUBJECT_TYPE_ENTERPRISE")
  86. {
  87. identity_info.Add("owner", true);
  88. }
  89. // else
  90. // {
  91. // identity_info.Add("owner", null);
  92. // }
  93. subject_info.Add("identity_info", identity_info); //经营者/法人身份证件
  94. // if (info.Owner == 0)
  95. // {
  96. // Dictionary<string, object> ubo_info = new Dictionary<string, object>();
  97. // ubo_info.Add("id_type", info.UboInfoIdType); //证件类型
  98. // ubo_info.Add("id_card_copy", GetMediaId("/" + info.UboInfoIdCardCopy)); //身份证人像面照片
  99. // ubo_info.Add("id_card_national", GetMediaId("/" + info.UboInfoIdCardNational)); //身份证国徽面照片
  100. // ubo_info.Add("id_doc_copy", GetMediaId("/" + info.UboInfoIdDocCopy)); //证件照片
  101. // ubo_info.Add("name", RSAEncrypt(info.UboInfoName)); //受益人姓名
  102. // ubo_info.Add("id_number", RSAEncrypt(info.UboInfoIdNumber)); //证件号码
  103. // ubo_info.Add("id_period_begin", CheckForever(info.UboInfoIdPeriodBegin)); //证件有效期开始时间
  104. // ubo_info.Add("id_period_end", CheckForever(info.UboInfoIdPeriodEnd)); //证件有效期结束时间
  105. // subject_info.Add("ubo_info", ubo_info); //最终受益人信息(UBO)
  106. // }
  107. result.Add("subject_info", subject_info);
  108. //经营资料
  109. Dictionary<string, object> business_info = new Dictionary<string, object>();
  110. business_info.Add("merchant_shortname", info.MerchantShortname); //商户简称
  111. business_info.Add("service_phone", info.ServicePhone); //客服电话
  112. Dictionary<string, object> sales_info = new Dictionary<string, object>();
  113. info.SalesScenesType = "SALES_SCENES_STORE";
  114. sales_info.Add("sales_scenes_type", info.SalesScenesType.Split(',').ToList()); //经营场景类型
  115. Dictionary<string, object> biz_store_info = new Dictionary<string, object>();
  116. biz_store_info.Add("biz_store_name", info.BizStoreName); //门店名称
  117. OpenBankCityTable BizAddress = dbpxc.OpenBankCityTable.FirstOrDefault(m => m.CityName.EndsWith(info.BizAddressCode)) ?? new OpenBankCityTable();
  118. biz_store_info.Add("biz_address_code", BizAddress.Code); //门店省市编码
  119. biz_store_info.Add("biz_store_address", info.BizStoreAddress); //门店地址
  120. List<string> store_entrance_pic = new List<string>();
  121. if(!string.IsNullOrEmpty(info.StoreEntrancePic))
  122. {
  123. string[] piclist = info.StoreEntrancePic.Split(',');
  124. foreach(string sub in piclist)
  125. {
  126. store_entrance_pic.Add(GetMediaId("/" + sub));
  127. }
  128. }
  129. biz_store_info.Add("store_entrance_pic", store_entrance_pic); //门店门头照片
  130. List<string> indoor_pic = new List<string>();
  131. if(!string.IsNullOrEmpty(info.IndoorPic))
  132. {
  133. string[] piclist = info.IndoorPic.Split(',');
  134. foreach(string sub in piclist)
  135. {
  136. indoor_pic.Add(GetMediaId("/" + sub));
  137. }
  138. }
  139. biz_store_info.Add("indoor_pic", indoor_pic); //店内环境照片
  140. biz_store_info.Add("biz_sub_appid", info.BizSubAppid); //线下场所对应的商家APPID
  141. sales_info.Add("biz_store_info", biz_store_info); //线下门店场景
  142. // Dictionary<string, object> mp_info = new Dictionary<string, object>();
  143. // mp_info.Add("mp_appid", info.MpAppid); //服务商公众号APPID
  144. // mp_info.Add("mp_sub_appid", info.MpSubAppid); //商家公众号APPID
  145. // mp_info.Add("mp_pics", GetMediaId("/" + info.MpPics)); //公众号页面截图
  146. // sales_info.Add("mp_info", mp_info); //公众号场景
  147. // Dictionary<string, object> mini_program_info = new Dictionary<string, object>();
  148. // mini_program_info.Add("mini_program_appid", info.MiniProgramAppid); //服务商小程序APPID
  149. // mini_program_info.Add("mini_program_sub_appid", info.MiniProgramSubAppid); //商家小程序APPID
  150. // mini_program_info.Add("mini_program_pics", GetMediaId("/" + info.MiniProgramPics)); //小程序截图
  151. // sales_info.Add("mini_program_info", mini_program_info); //小程序场景
  152. // Dictionary<string, object> app_info = new Dictionary<string, object>();
  153. // app_info.Add("app_appid", info.AppAppid); //服务商应用APPID
  154. // app_info.Add("app_sub_appid", info.AppSubAppid); //商家应用APPID
  155. // app_info.Add("app_pics", GetMediaId("/" + info.AppPics)); //商家应用APPID
  156. // sales_info.Add("app_info", app_info); //APP场景
  157. // Dictionary<string, object> web_info = new Dictionary<string, object>();
  158. // web_info.Add("domain", info.WebDomain); //互联网网站域名
  159. // web_info.Add("web_authorisation", GetMediaId("/" + info.WebAuthorisation)); //网站授权函
  160. // web_info.Add("web_appid", info.WebAppId); //互联网网站对应的商家APPID
  161. // sales_info.Add("web_info", web_info); //互联网网站场景
  162. // Dictionary<string, object> wework_info = new Dictionary<string, object>();
  163. // wework_info.Add("sub_corp_id", info.SubCorpId); //商家企业微信CorpID
  164. // wework_info.Add("wework_pics", GetMediaId("/" + info.WeworkPics)); //企业微信页面截图
  165. // sales_info.Add("wework_info", wework_info); //企业微信场景
  166. business_info.Add("sales_info", sales_info); //经营场景
  167. result.Add("business_info", business_info);
  168. //结算规则
  169. Dictionary<string, object> settlement_info = new Dictionary<string, object>();
  170. settlement_info.Add("settlement_id", info.SettlementId); //入驻结算规则ID
  171. string QualificationType = function.CheckNull(info.QualificationType);
  172. if (QualificationType.Contains(","))
  173. {
  174. QualificationType = QualificationType.Split(',')[0];
  175. }
  176. settlement_info.Add("qualification_type", QualificationType); //所属行业
  177. if (!string.IsNullOrEmpty(info.Qualifications))
  178. {
  179. List<string> Qualifications = new List<string>();
  180. Qualifications.Add(GetMediaId("/" + info.Qualifications));
  181. settlement_info.Add("qualifications", Qualifications); //特殊资质图片
  182. }
  183. settlement_info.Add("activities_id", info.ActivitiesId); //优惠费率活动ID
  184. settlement_info.Add("activities_rate", info.ActivitiesRate); //优惠费率活动值
  185. result.Add("settlement_info", settlement_info);
  186. //结算银行账户
  187. Dictionary<string, object> bank_account_info = new Dictionary<string, object>();
  188. bank_account_info.Add("bank_account_type", info.BankAccountType); //账户类型
  189. bank_account_info.Add("account_name", RSAEncrypt(info.AccountName)); //开户名称
  190. bank_account_info.Add("account_bank", info.AccountBank); //开户银行
  191. OpenBankCityTable BankAddress = dbpxc.OpenBankCityTable.FirstOrDefault(m => m.CityName.EndsWith(info.BankAddressCode)) ?? new OpenBankCityTable();
  192. bank_account_info.Add("bank_address_code", BankAddress.Code); //开户银行省市编码
  193. OpenBankTable BankBranch = dbpxc.OpenBankTable.FirstOrDefault(m => m.BankName == info.BankName) ?? new OpenBankTable();
  194. bank_account_info.Add("bank_branch_id", BankBranch.BankCode); //开户银行联行号
  195. bank_account_info.Add("bank_name", info.BankName); //开户银行全称(含支行)
  196. bank_account_info.Add("account_number", RSAEncrypt(info.AccountNumber)); //银行账号
  197. result.Add("bank_account_info", bank_account_info);
  198. dbpxc.Dispose();
  199. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  200. Dictionary<string, string> header = new Dictionary<string, string>();
  201. // 如何查看证书序列号?
  202. // 登陆商户平台【API安全】->【API证书】->【查看证书】,可查看商户API证书序列号。
  203. // 商户API证书和微信支付平台证书均可以使用第三方的证书解析工具,查看证书内容。或者使用openssl命令行工具查看证书序列号。
  204. // $ openssl x509 -in 1900009191_20180326_cert.pem -noout -serial
  205. // serial=1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C
  206. LogHelper.Instance.WriteLog(req, "服务商平台商户进件提交申请单API");
  207. string resp = postJson("https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/", req);
  208. LogHelper.Instance.WriteLog(resp + "\n\n", "服务商平台商户进件提交申请单API");
  209. return resp;
  210. }
  211. #endregion
  212. #region 服务商平台查询申请单状态API
  213. public Dictionary<string, object> QueryMerchant(string BusinessCode)
  214. {
  215. Dictionary<string, object> return_result = new Dictionary<string, object>();
  216. try
  217. {
  218. string result = postJson("https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/business_code/" + BusinessCode, "", "GET");
  219. //{\"applyment_id\":2000002247709762,\"applyment_state\":\"APPLYMENT_STATE_FINISHED\",\"applyment_state_msg\":\"商户入驻申请已完成\",\"audit_detail\":[],\"business_code\":\"0123456789\",\"sign_url\":\"https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQFv7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyUXE1czkzb3JlUjIxZHpXbTF5Y2YAAgRjbe9hAwQAjScA\",\"sub_mchid\":\"1619775262\"}
  220. JsonData jsonObj = JsonMapper.ToObject(result);
  221. bool logFlag = true;
  222. if (jsonObj["applyment_state"].ToString() == "APPLYMENT_STATE_AUDITING" || jsonObj["applyment_state"].ToString() == "APPLYMENT_STATE_TO_BE_SIGNED" || jsonObj["applyment_state"].ToString() == "APPLYMENT_STATE_TO_BE_CONFIRMED")
  223. {
  224. string check = RedisDbconn.Instance.Get<string>("WeChatQueryMerchant:" + BusinessCode + ":" + jsonObj["applyment_state"].ToString());
  225. if(!string.IsNullOrEmpty(check))
  226. {
  227. logFlag = false;
  228. }
  229. else
  230. {
  231. RedisDbconn.Instance.Set("WeChatQueryMerchant:" + BusinessCode + ":" + jsonObj["applyment_state"].ToString(), result);
  232. RedisDbconn.Instance.SetExpire("WeChatQueryMerchant:" + BusinessCode + ":" + jsonObj["applyment_state"].ToString(), 7200);
  233. }
  234. }
  235. if(logFlag)
  236. {
  237. LogHelper.Instance.WriteLog(BusinessCode, "服务商平台查询申请单状态API");
  238. LogHelper.Instance.WriteLog(result + "\n\n", "服务商平台查询申请单状态API");
  239. }
  240. return_result.Add("applyment_id", jsonObj["applyment_id"].ToString()); //微信支付申请单号
  241. return_result.Add("applyment_state", jsonObj["applyment_state"].ToString()); //申请单状态
  242. return_result.Add("applyment_state_msg", jsonObj["applyment_state_msg"].ToString()); //申请状态描述
  243. if (jsonObj["applyment_state"].ToString() == "APPLYMENT_STATE_TO_BE_SIGNED" || jsonObj["applyment_state"].ToString() == "APPLYMENT_STATE_FINISHED")
  244. {
  245. return_result.Add("sub_mchid", jsonObj["sub_mchid"].ToString());
  246. }
  247. if (jsonObj["applyment_state"].ToString() == "APPLYMENT_STATE_REJECTED")
  248. {
  249. List<Dictionary<string, string>> audit_detail = new List<Dictionary<string, string>>();
  250. JsonData auditObj = jsonObj["audit_detail"]; //驳回原因详情
  251. // for (int i = 0; i < auditObj.Count; i++)
  252. // {
  253. // Dictionary<string, string> row = new Dictionary<string, string>();
  254. // // row.Add("field", auditObj[i]["field"].ToString()); //字段名
  255. // // row.Add("field_name", auditObj[i]["field_name"].ToString()); //字段名称
  256. // row.Add("reject_reason", auditObj[i]["reject_reason"].ToString()); //驳回原因
  257. // audit_detail.Add(row);
  258. // }
  259. return_result.Add("reject_reason", auditObj[0]["reject_reason"].ToString());
  260. return_result.Add("audit_detail", audit_detail); //申请状态描述
  261. }
  262. if (result.Contains("\"sign_url\":"))
  263. {
  264. return_result.Add("sign_url", jsonObj["sign_url"].ToString()); //进件通过申请,待商家签约的地址
  265. }
  266. }
  267. catch (Exception ex)
  268. {
  269. LogHelper.Instance.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商平台查询申请单状态API异常");
  270. }
  271. return return_result;
  272. }
  273. #endregion
  274. #region 服务商平台申请退款API
  275. public Dictionary<string, string> Refund(string SubMchId, decimal RefundMoney, decimal TotalMoney, string OrderNo, string RefundNo, string Reason = "")
  276. {
  277. Dictionary<string, string> return_result = new Dictionary<string, string>();
  278. int refund = (int)(RefundMoney * 100);
  279. int amount = (int)(TotalMoney * 100);
  280. //具体请求参数
  281. SortedList<string, object> par = new SortedList<string, object>();
  282. par.Add("sub_mchid", SubMchId); //子商户号
  283. par.Add("out_trade_no", OrderNo); //商户订单号
  284. par.Add("out_refund_no", RefundNo); //商户退款单号
  285. par.Add("reason", Reason); //退款原因
  286. Dictionary<string, object> amountDic = new Dictionary<string, object>();
  287. amountDic.Add("refund", refund); //退款金额
  288. amountDic.Add("total", amount); //原订单金额
  289. amountDic.Add("currency", "CNY"); //退款币种
  290. par.Add("amount", amountDic); //金额信息
  291. string req = Newtonsoft.Json.JsonConvert.SerializeObject(par);
  292. try
  293. {
  294. LogHelper.Instance.WriteLog(req, "服务商平台申请退款API");
  295. string result = postJson("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds", req);
  296. LogHelper.Instance.WriteLog(result + "\n\n", "服务商平台申请退款API");
  297. JsonData jsonObj = JsonMapper.ToObject(result);
  298. return_result.Add("refund_id", jsonObj["refund_id"].ToString()); //微信支付退款单号
  299. return_result.Add("channel", jsonObj["channel"].ToString()); //退款渠道
  300. return_result.Add("user_received_account", jsonObj["user_received_account"].ToString()); //退款入账账户
  301. return_result.Add("status", jsonObj["status"].ToString()); //退款状态
  302. return_result.Add("payer_total", jsonObj["amount"]["payer_total"].ToString()); //用户支付金额
  303. return_result.Add("payer_refund", jsonObj["amount"]["payer_refund"].ToString()); //用户退款金额
  304. return_result.Add("settlement_refund", jsonObj["amount"]["settlement_refund"].ToString()); //应结退款金额
  305. return_result.Add("settlement_total", jsonObj["amount"]["settlement_total"].ToString()); //应结订单金额
  306. return_result.Add("discount_refund", jsonObj["amount"]["discount_refund"].ToString()); //优惠退款金额
  307. }
  308. catch (Exception ex)
  309. {
  310. LogHelper.Instance.WriteLog(DateTime.Now.ToString() + "\r\n" + ex.ToString(), "服务商平台申请退款API异常");
  311. }
  312. return return_result;
  313. }
  314. #endregion
  315. #region 服务商平台请求分账API
  316. public string ProfitShare(string SubMchId, string TradeNo, string OrderNo, List<ReceiverList> Receivers) //有活动分0.62%,没活动不分账
  317. {
  318. Dictionary<string, object> result = new Dictionary<string, object>();
  319. result.Add("sub_mchid", SubMchId); //子商户号
  320. result.Add("appid", AppId); //应用ID
  321. result.Add("transaction_id", TradeNo); //微信订单号
  322. result.Add("out_order_no", OrderNo); //商户分账单号
  323. result.Add("receivers", Receivers); //分账接收方列表
  324. result.Add("unfreeze_unsplit", true); //是否解冻剩余未分资金
  325. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  326. LogHelper.Instance.WriteLog(req, "服务商平台请求分账API");
  327. string resp = postJson("https://api.mch.weixin.qq.com/v3/profitsharing/orders", req);
  328. LogHelper.Instance.WriteLog(resp + "\n\n", "服务商平台请求分账API");
  329. return resp;
  330. //{"order_id":"30000104462023060249559178531","out_order_no":"2023060210583730173782834","receivers":[{"account":"1611167423","amount":3,"create_time":"2023-06-02T11:34:10+08:00","description":"服务费","detail_id":"36000104462023060269999025889","finish_time":"1970-01-01T08:00:00+08:00","result":"PENDING","type":"MERCHANT_ID"},{"account":"1645266943","amount":7,"create_time":"2023-06-02T11:34:10+08:00","description":"解冻给分账方","detail_id":"36000104462023060269999025890","finish_time":"1970-01-01T08:00:00+08:00","result":"PENDING","type":"MERCHANT_ID"}],"state":"PROCESSING","sub_mchid":"1645266943","transaction_id":"4200001833202306025522158377"}
  331. }
  332. #endregion
  333. #region 服务商平台添加分账接收方API
  334. public string AddReceive(string SubMchId, string TypeName, string Account, string Name, string Relation)
  335. {
  336. Dictionary<string, object> result = new Dictionary<string, object>();
  337. result.Add("sub_mchid", SubMchId); //子商户号
  338. result.Add("appid", AppId); //应用ID
  339. result.Add("type", TypeName); //分账接收方类型 MERCHANT_ID:商户ID PERSONAL_OPENID:个人openid(由父商户APPID转换得到) PERSONAL_SUB_OPENID:个人sub_openid(由子商户APPID转换得到)
  340. result.Add("account", Account); //分账接收方账号
  341. if(!string.IsNullOrEmpty(Name))
  342. {
  343. result.Add("name", RSAEncrypt(Name)); //分账个人接收方姓名
  344. }
  345. result.Add("relation_type", Relation); //与分账方的关系类型 STORE:门店 STAFF:员工 STORE_OWNER:店主 PARTNER:合作伙伴 HEADQUARTER:总部 BRAND:品牌方 DISTRIBUTOR:分销商 USER:用户 SUPPLIER: 供应商 CUSTOM:自定义
  346. string req = Newtonsoft.Json.JsonConvert.SerializeObject(result);
  347. LogHelper.Instance.WriteLog(req, "服务商平台添加分账接收方API");
  348. string resp = postJson("https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add", req);
  349. LogHelper.Instance.WriteLog(resp + "\n\n", "服务商平台添加分账接收方API");
  350. return resp;
  351. //{"account":"1611167423","name":"x+8m5jM4x2jSZLDOpN46Js9JyeNgUXkFSmGjCBN45QcSYUNPN86TOheRF64WlwDeO45E/walWPeZSksNN/LfJiB2fZRVun1CJuJ7zxePma8L7iDbKS92i+d38rvOmNTjLhKX64O8oJR4HMtFw1HryxJlUFgM5/ickJ79WGrX3GaVArWisgEzwOyxGBfGSL3ofJhi5TdTnrxHMzqYWv43DRvI9Ja5eMgFbgrGcn+JiJVKQcYj1L8tZ6xQeQCXkY6ubyDiV9wQps2nQA1Oh+UdFcS13Ex4FUSYLCczGFAl4EV8TBJQleZeC1p4ZJquJjje0uMjI2xB6S41yUBoN86gkA==","relation_type":"PARTNER","sub_mchid":"1645266943","type":"MERCHANT_ID"}
  352. }
  353. #endregion
  354. #region 服务商平台查询分账结果API
  355. public string QueryProfitShare(string SubMchId, string TradeNo, string OrderNo)
  356. {
  357. string req = "";
  358. req += "sub_mchid=" + SubMchId + "&"; //子商户号
  359. req += "transaction_id=" + TradeNo + "&"; //微信订单号
  360. LogHelper.Instance.WriteLog(req, "服务商平台查询分账结果API");
  361. string resp = postJson("https://api.mch.weixin.qq.com/v3/profitsharing/orders/" + OrderNo + "?" + req, "", "GET");
  362. LogHelper.Instance.WriteLog(resp + "\n\n", "服务商平台查询分账结果API");
  363. return resp;
  364. //{"order_id":"30000404702023060849818491190","out_order_no":"2023060816062365164446474","receivers":[{"account":"1611167423","amount":3,"create_time":"2023-06-08T17:55:45+08:00","description":"服务费","detail_id":"36000404702023060870422622364","finish_time":"2023-06-08T17:56:16+08:00","result":"SUCCESS","type":"MERCHANT_ID"},{"account":"1646405429","amount":151,"create_time":"2023-06-08T17:55:45+08:00","description":"解冻给分账方","detail_id":"36000404702023060870422622365","finish_time":"2023-06-08T17:56:16+08:00","result":"SUCCESS","type":"MERCHANT_ID"}],"state":"FINISHED","sub_mchid":"1646405429","transaction_id":"4200001821202306083551994076"}
  365. }
  366. #endregion
  367. #region 查询支行列表
  368. public string QueryBranchBankList(string offset)
  369. {
  370. string resp = postJson("https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/1000009548/branches?city_code=898&offset=" + offset + "&limit=200", "", "GET");
  371. return resp;
  372. }
  373. public string QueryBankList(string offset)
  374. {
  375. string resp = postJson("https://api.mch.weixin.qq.com/v3/capital/capitallhh/banks/corporate-banking?offset=" + offset + "&limit=200", "", "GET");
  376. return resp;
  377. }
  378. public string QueryProvince()
  379. {
  380. string resp = postJson("https://api.mch.weixin.qq.com/v3/capital/capitallhh/areas/provinces", "", "GET");
  381. return resp;
  382. }
  383. public string QueryCity(string code)
  384. {
  385. string resp = postJson("https://api.mch.weixin.qq.com/v3/capital/capitallhh/areas/provinces/" + code + "/cities", "", "GET");
  386. return resp;
  387. }
  388. #endregion
  389. #region 敏感信息加密
  390. string pubkey = "MIID3DCCAsSgAwIBAgIUYdmfchi0h3iONdbE4+05jgl50/YwDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsTFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3QgQ0EwHhcNMjIwMTIzMDYwMjA4WhcNMjcwMTIyMDYwMjA4WjBuMRgwFgYDVQQDDA9UZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRlbnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpoZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSFtwof74G5sJuQya6OJKhfjMcVZ3PZk+uG0RWULyDwOZezvYjLp9jkkfTCWuWDkshRmrDhVj89eOPwy60QDYKaKQ1Mq48BqoQrOikSK5bxAMGHg1a/0UcPM3yL3T84nlZkFlySeXN8cqWkZnPIXeO/blYCyBxNizmUwIIJUlI1Fbhy4lQRsoLoRbeh+YUQ2AI9D2plzVDY5jkG9/FQWhyZr5K3rgjblb/pMZngmzSYCNBWfJP9EZfRuQvZokMEddytC3JoSPgvqA25RMAPvj1cnAiOypgm7BHhx+a1mpmz79ifWlDF9rglo6WDGAxQ4JDuPJTVOiQ9EsfS8OHjxmfAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBcMFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJKoZIhvcNAQELBQADggEBABrLvDmhYbFtIbKZE+up87zfYcx/HvaxIrHNRju7e6Kn62fmxhNRFuOBjMwshBt247lN4w02peBDmAOTRTs8jwamRwqTv6WtO2bbrKT3QkyEDieNnO2kfEIsSAXGp0FUcmkgzZv7tOekGUx8H6yp/3mtpFy1UqE86s5GdQGDVmhOTG2naqidi1X10XnTNWrw3siuc5pSm02lfpwEMl2zyWvQrC/42s/DO8/VfnmIVGy1QIzIpTfUYC6mfTiGuARLIgUwv/wRxrCwSOBKLLbaxXPB2HOaUJ1BpAOyVjxx46Y7yEpfpzkHbm5gNnhICUjQwDT1V2tpslclqjwP0Ju97Mw=";
  391. string prikey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDKoogD+DYRwiWCIWY9LksBI3tRo8MFBRDktYK/2NP6C1oBS3WLVcPO2QPatTzZX1pjc3pJzFeNpJJw6MYiSDpQKzH7zLexq/UAMVopalODe0N7TRWc2yyaZ+hppIEu+uAZQOuL5GizJGv/0Q2mlgGyCU2mcbBxQMHX7H+xHb0iUaZ9PcJsjxDQydgy+fbEPIOI2ccoVwrWVR8Czgb7sHI08oaW6AmX5zrPo/TE2ymy3DO1ojspyIje0AsP5ydHPBDaA5pUvnruP8vCVkbrPZ90PxRmxWlWg1pc/+Rpa5whzcHRaP63ahUvzPKGJ8ieVt5Cad3HmgAET3KfQM7RFUBpAgMBAAECggEAKm72xL4JtJZPfHy6CD3VfxuLC4GbqUVyUDKiesJRQZ927aZ7qv3+zyYq5HXnlC2fpAveo+2iuAqqj/Ju62bsrzUcdnpcTVyRJcUv+FRHwNTjQMLXr81F/d+cj+LfGpN2slMiAF2If1s1MpD4ptXq7Pl9xUkxhcXl0e24n8J2hOTs6OT5y+j/bQusptfM0tlWsgGvTlhyTrCLv5gTDmO2Qm7GDKmYGVC2vxtS9oNvfIp2+3VU9LmFZntNcE9fq8m50VJOQ2qkbfI/PT4FPa/+Ot9sNKU4KYGnUw/3uGv9ueUBs8jbroCDlqJDTmF3HjkBVpbA/wqWX9Mp36o0hYhhMQKBgQDpc8dZP3RDgweavrlWWG08KSQBRX0ysNDVzQz1eKES4Azt3CUOB7NraW/k+fzBBNtdEqmYHCBLd3F1MDfB61BAEykGNe1ny05ISAeQHANbpHmLXDRT5gqEpxEjhUkaMNma0Eqyi1v4x+Hu7jLvV1R6m0UUAHi0Lvrv63tO1v5bdwKBgQDeNMcq22zQn41hvnwZnoG56xThkTph5lcZYUHghPLIf0Ib1ibNP5qzklYMBwmSsA5aODFpCkDcLpNDqBUrZldN2Oh26gw/ErPJLTU5drZsf06eOvbqooEG3imlgChcrHtcMHNK6mQtIqRRjZIbUQFaVXCag4mnkDWDnpRmidp7HwKBgQCtAZhik5vdzGT+UQmY679ILlT4fD7kKhUZ3PQVlmgITPJH9DWhyCM3HtRFpN2jTa4js4jrqSxlwQbcCffIRlMaqRhl+eEOYqSI/JheO+RhLerFVHeTFZAF7qnM4SHjvwAEswgoeQ6Xt8m//9bPeLCqjBcNU6wgHBDrbF/ddYba0QKBgH4lLjA5U0P4YBXuQpt0raazOy52+NLdJfMlkHV6ZC3IeOo+n9aDVjq9R5YaZKfexLcZEYvVI08cLcQJ5sK1nbh2/DmN0xf3cRMzU/TkXNmpSCNxy/0V9fPFKZVn9QHvdTS32Kvd9rLc6LXXjetuCDuVJ5DAPeRfbNHks9CmT973AoGBAK400faHTcodLHR/MXEmfI6BZlsTh2Cbm5q+k8Of095xKB/sfTWPprMQW+/U5OEQrKDbt+FI+psJFixmSNFuZdt4JU9P5/bp4SGIQpCfsp1p7GP/irc1yikrHXeGes9HPeUn7yGmvz4QC+sFO32haYr1SaAzZvMhf3RQVuAiFOnw"; //私钥
  392. string plate_pubkey = "MIIEKDCCAxCgAwIBAgIUMc+JGN0sSNjmrGRSM9zlon+kc0QwDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsTFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3QgQ0EwHhcNMjMwNjI3MDIwNTE1WhcNMjgwNjI1MDIwNTE1WjCBgTETMBEGA1UEAwwKMTY0NzgxNzk1MDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMS0wKwYDVQQLDCTlm5vlt53nnIHmtqbop4LnsbPnp5HmioDmnInpmZDlhazlj7gxCzAJBgNVBAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMg5fBkqxpI4calKX0MYkJ3R186UIZGxWpEQhiResHqRFiEYWSXE1nM/8q+MoNJV0hJyuwcnhIlvflzOOpjyEWLnPpj1H0Fh14UVboD+BJ014zwFNNk915v90u8syROQWW6jZmugwZ11fuj6aZ0K5jGdgEf8AIhQukHyOW/IWmU93JxRzvTilfZgBr0IBGZk2LT4/KcTs3NsOQIqd3AzkcYbsDQv7k4yzdNBXewjXHkpjTRSHw+SydV/aGnpmoxStIL0gVR0yLCKB/297xCtdy7k/GVLivDcoT9M6N/gSPbzhD3jSKXcjO1H0JUhrXJTS5VZmtQOJ/P/BV0p7FPTmLMCAwEAAaOBuTCBtjAJBgNVHRMEAjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQB5mAFzdpDi1UK8PK/qAOQEvgTNhZTtLAW1y5mnZ6tetdo6ZIuX+S44m6sdtVkNsgoe+ljvwNtwXGfyf9wd7jEe9lIn6Y3I2FFoSvwmNS97MDuBXj/WL61GlNjDZJewApS0gVCvrYzuiyuKpaREsY9gTh1Tncw3rjiZwIkb2i0yjzmcBkrDnggYiK3hxryDy9PvdmjiaT0CcVsup/3G6LlscP7zuxfdEAFbOi14zNz2EuYLTzUB1BKzGZPpUYWeER/meCsGyNuukpR7GgngA3X4lEaqm7fJlCdLNOFroMrcyv+FMbP8QO1TA23yLAo+suk56r6R4pwpnZl9yIDw4907";
  393. string plate_prikey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDIOXwZKsaSOHGpSl9DGJCd0dfOlCGRsVqREIYkXrB6kRYhGFklxNZzP/KvjKDSVdIScrsHJ4SJb35czjqY8hFi5z6Y9R9BYdeFFW6A/gSdNeM8BTTZPdeb/dLvLMkTkFluo2ZroMGddX7o+mmdCuYxnYBH/ACIULpB8jlvyFplPdycUc704pX2YAa9CARmZNi0+PynE7NzbDkCKndwM5HGG7A0L+5OMs3TQV3sI1x5KY00Uh8PksnVf2hp6ZqMUrSC9IFUdMiwigf9ve8QrXcu5PxlS4rw3KE/TOjf4Ej284Q940il3IztR9CVIa1yU0uVWZrUDifz/wVdKexT05izAgMBAAECggEABESdbZfo1bMYUSiBsVdztbmEZSXpNUbXjGISyfGux14SX7A6LkDs5VYGoVFZGEK2EKibbgKco6VZxzaqLxpx3m7Zeb835FfmlTKowV0o0gUVC/F8d+kGkI+vkGOfAajBD0eyZjbuCaI4i1TTLYLO913JHz+y7zTxU3iLWuOlcaT/R6kMRUAh8okqNxUscaTM709PddFskL2HMuq7v4hXJo4k3VDVnWP/De8Lie3HHRjsrES6qvAudijn+8PU6Zo28q45vHgoP3dWz6/pjIErjdAAqRRBifip9C3ppylJNVMG/2YV8i6NUrCq5CVgVpSOUkDU4m5N5B1YPoVU4qpEOQKBgQDpw0rMR2uAmACCohO34lIzBIxGYhJ4d7iiMlnL3HMGlTn55YqNVUUfP0i7opRN74Sj2mtW62JaiGtTmJDnc/KQGDkQdVakoaSY6YN0DEBedub6wN2XvU7oMAuzjmXkknDfNkLkfmWia0Fh4YnVabytwoo3diyBDi6hrWkAhSllhQKBgQDbRXOBzFxK8Dgpt76xhSCmxLhvseBbwTpJ8tQHs/zkFhK/BNn79eJsEjZNcox7xwagMvqVoBf9QdUzTChheDEhIzujsArEp2+NrUruBZPAZT6bX7niqs/jyRgw6B7h/XsSiPxRx7eCvn/SDp6JD5I8jYN/WxkeHdhi+mn8e87e1wKBgFRg0db60KsSMtz0c/mkD9eqhJfDPreNP3AMjK0xXbO6mbrCSEjLxq+IwFA6Vx3qnw4mASjWviG/rD34jBV/nMa2d6KhOC0ky60GXRS+d12hva41f8cN5jWZYh/l/pGK6oMnqu2fUkBWRrt2FbKbACgYWJu8ZEQRQnPJjGVLq62hAoGAAt0tXQymR/RLR4A25Wqvun3nSs4v+ALWGBEr483eB7yiEgymLDxR8MdsHibY3uUCmSURUNL+fThW6IyeGmfPfHdRWBn8igUF1/vjdqhr/Z9U6gKeEu/YN0lxH3JotNryuJNBeG/7XaHPWZcHSxMA/fl7NjaiZVpOcTyEFeAoG5ECgYBimNzthVzVAK5oN8ChIV23iou7wMVaPQ3eWdKhec0GAH+Jv5V8GHGlbZeBiUiBMo62fwtTru+j3zJgMum+PlZSHz903J2bSzo6x0N2/6/TYUjVsXFLlpS7zbMvJnh//9B8wGhnhzSfW38MA523CIw7sU+VUQQHx6/2vLwT84SfsQ=="; //私钥
  394. public string RSAEncrypt(string text)
  395. {
  396. byte[] publicKey = Convert.FromBase64String(pubkey);
  397. // var rsa = RSA.Create();
  398. // rsa.ImportRSAPublicKey(publicKey, out _);
  399. // var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  400. // return Convert.ToBase64String(buff);
  401. using (var x509 = new X509Certificate2(publicKey))
  402. {
  403. using (var rsa = x509.GetRSAPublicKey())
  404. {
  405. var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  406. return Convert.ToBase64String(buff);
  407. }
  408. }
  409. }
  410. // public string RSADecrypt(string text)
  411. // {
  412. // // byte[] key = Encoding.UTF8.GetBytes(AppConfig.WeChatParam.AesGemKey);
  413. // // byte[] nonce = Encoding.UTF8.GetBytes("1234567890ab");
  414. // // byte[] ciphertext = Convert.FromBase64String(text);
  415. // // AesGcm aes = new AesGcm(key);
  416. // // byte[] plaintext = new byte[ciphertext.Length];
  417. // // aes.Decrypt(nonce, ciphertext, plaintext, null);
  418. // // return Encoding.UTF8.GetString(plaintext);
  419. // }
  420. public string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
  421. {
  422. // GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
  423. // AeadParameters aeadParameters = new AeadParameters(
  424. // new KeyParameter(Encoding.UTF8.GetBytes(AppConfig.WeChatParam.AesGemKey)),
  425. // 128,
  426. // Encoding.UTF8.GetBytes(nonce),
  427. // Encoding.UTF8.GetBytes(associatedData));
  428. // gcmBlockCipher.Init(false, aeadParameters);
  429. // byte[] data = Convert.FromBase64String(ciphertext);
  430. // byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
  431. // int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
  432. // gcmBlockCipher.DoFinal(plaintext, length);
  433. // return Encoding.UTF8.GetString(plaintext);
  434. byte[] key = Encoding.UTF8.GetBytes(AppConfig.WeChatParam.AesGemKey); // 256-bit key
  435. byte[] nonceByte = Encoding.UTF8.GetBytes(nonce); // 96-bit nonce
  436. byte[] cipherByte = Convert.FromBase64String(ciphertext);
  437. byte[] associatedByte = Encoding.UTF8.GetBytes(associatedData);
  438. GcmBlockCipher cipher = new GcmBlockCipher(new AesEngine());
  439. AeadParameters parameters = new AeadParameters(new KeyParameter(key), 128, nonceByte, associatedByte);
  440. cipher.Init(false, parameters);
  441. byte[] plaintext = new byte[cipher.GetOutputSize(cipherByte.Length)];
  442. int len = cipher.ProcessBytes(cipherByte, 0, cipherByte.Length, plaintext, 0);
  443. cipher.DoFinal(plaintext, len);
  444. return Encoding.UTF8.GetString(plaintext);
  445. }
  446. public string postJson(string url, string postData, string method = "POST")
  447. {
  448. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  449. request.Method = method;
  450. request.ContentType = "application/json;charset=UTF-8";
  451. request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
  452. request.Accept = "application/json";
  453. string Authorization = GetAuthorization(url, method, postData, prikey, MchId, serialNo);
  454. request.Headers.Add("Authorization", Authorization);
  455. request.Headers.Add("Wechatpay-Serial", getSerialNo);
  456. if (!string.IsNullOrEmpty(postData))
  457. {
  458. byte[] paramJsonBytes;
  459. paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
  460. request.ContentLength = paramJsonBytes.Length;
  461. Stream writer;
  462. try
  463. {
  464. writer = request.GetRequestStream();
  465. }
  466. catch (Exception ex)
  467. {
  468. writer = null;
  469. LogHelper.Instance.WriteLog(DateTime.Now.ToString() + "\n" + ex.ToString(), "http请求异常");
  470. }
  471. writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
  472. writer.Close();
  473. }
  474. HttpWebResponse response;
  475. try
  476. {
  477. response = (HttpWebResponse)request.GetResponse();
  478. }
  479. catch (WebException ex)
  480. {
  481. response = ex.Response as HttpWebResponse;
  482. }
  483. Stream resStream = response.GetResponseStream();
  484. StreamReader reader = new StreamReader(resStream);
  485. string text = reader.ReadToEnd();
  486. return text;
  487. //{\"code\":\"PARAM_ERROR\",\"message\":\"请确认待处理的消息是否为加密后的密文\"}
  488. //{\"applyment_id\":2000002247709762}
  489. }
  490. #endregion
  491. #region 图片上传
  492. public string GetMediaId(string imgPath)
  493. {
  494. if (string.IsNullOrEmpty(imgPath))
  495. {
  496. return "";
  497. }
  498. if (imgPath.Contains(","))
  499. {
  500. imgPath = imgPath.Split(',')[0];
  501. }
  502. string key = "wechatpic:" + function.MD5_16(imgPath);
  503. string media_id = RedisDbconn.Instance.Get<string>(key);
  504. if (!string.IsNullOrEmpty(media_id))
  505. {
  506. return media_id;
  507. }
  508. string filePath = function.getPath(imgPath);
  509. var filename = Path.GetFileName(filePath);
  510. // FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
  511. // Byte[] imgBytesIn = new Byte[fs.Length];
  512. // fs.Read(imgBytesIn, 0, imgBytesIn.Length);
  513. // fs.Close();
  514. byte[] imgBytesIn = PublicFunction.GetNetFileData(AppConfig.Base.OssHost + imgPath);
  515. byte[] hash = SHA256Managed.Create().ComputeHash(imgBytesIn);
  516. StringBuilder builder = new StringBuilder();
  517. for (int i = 0; i < hash.Length; i++)
  518. {
  519. builder.Append(hash[i].ToString("x2"));
  520. }
  521. var sha256 = builder.ToString();
  522. string metaStr = "{\"filename\":\""+ filename + "\",\"sha256\":\"" + sha256 + "\"}";
  523. media_id = UploadImgApi(metaStr, imgBytesIn, filename);
  524. RedisDbconn.Instance.Set(key, media_id);
  525. return media_id;
  526. }
  527. public string UploadImgApi(string metaStr, Byte[] imgBytesIn,string filename)
  528. {
  529. string url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
  530. string merchantId = MchId; //商户号
  531. string privateKey = prikey;
  532. #region 定义请求体中的内容 并转成二进制
  533. string boundary = "lc199aecd61b4653ef";
  534. string Enter = "\r\n";
  535. string campaignIDStr1
  536. = "--" + boundary
  537. + Enter
  538. + "Content-Disposition: form-data; name=\"meta\";"
  539. + Enter
  540. + "Content-Type:application/json;"
  541. + Enter
  542. + Enter
  543. + metaStr
  544. + Enter
  545. + "--" + boundary
  546. + Enter
  547. + "Content-Disposition:form-data;name=\"file\";filename=\""+ filename + "\";"
  548. + Enter
  549. + "Content-Type:image/jpeg"
  550. + Enter
  551. + Enter;
  552. byte[] byteData2
  553. = imgBytesIn;
  554. string campaignIDStr3
  555. = Enter
  556. + "--" + boundary
  557. + Enter;
  558. var byteData1 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr1);
  559. var byteData3 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr3);
  560. #endregion
  561. string transactionsResponse = UploadImg_postJson(url, byteData1, byteData2, byteData3, metaStr, privateKey, merchantId, serialNo, boundary, "POST");
  562. var result=JsonMapper.ToObject(transactionsResponse);
  563. return result["media_id"].ToString();
  564. }
  565. public string UploadImg_postJson(string url, byte[] b1, byte[] b2, byte[] b3, string metaStr, string privateKey, string merchantId, string serialNo, string boundary, string method = "POST")
  566. {
  567. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  568. request.Method = method;
  569. //request.ContentType = "application/json;charset=UTF-8";
  570. request.ContentType = "multipart/form-data;boundary=" + boundary;
  571. request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
  572. request.Accept = "application/json";
  573. string Authorization = GetAuthorization(url, method, metaStr, privateKey, merchantId, serialNo);
  574. request.Headers.Add("Authorization", Authorization);
  575. Stream writer;
  576. try
  577. {
  578. writer = request.GetRequestStream();
  579. }
  580. catch (Exception)
  581. {
  582. writer = null;
  583. }
  584. writer.Write(b1, 0, b1.Length);
  585. writer.Write(b2, 0, b2.Length);
  586. writer.Write(b3, 0, b3.Length);
  587. writer.Close();
  588. HttpWebResponse response;
  589. try
  590. {
  591. response = (HttpWebResponse)request.GetResponse();
  592. }
  593. catch (WebException ex)
  594. {
  595. response = ex.Response as HttpWebResponse;
  596. }
  597. Stream resStream = response.GetResponseStream();
  598. StreamReader reader = new StreamReader(resStream);
  599. string text = reader.ReadToEnd();
  600. return text;
  601. }
  602. protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, string merchantId, string serialNo)
  603. {
  604. var uri = new Uri(url);
  605. string urlPath = uri.PathAndQuery;
  606. string nonce = Guid.NewGuid().ToString();
  607. var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
  608. //数据签名 HTTP请求方法\n接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n
  609. method = string.IsNullOrEmpty(method) ? "" : method;
  610. string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, jsonParame);
  611. string signTxt = Sign(message, privateKey);
  612. //Authorization和格式
  613. string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
  614. merchantId,
  615. nonce,
  616. timestamp,
  617. serialNo,
  618. signTxt
  619. );
  620. return authorzationTxt;
  621. }
  622. protected string Sign(string message, string privateKey)
  623. {
  624. byte[] keyData = Convert.FromBase64String(privateKey);
  625. byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
  626. var rsa = RSA.Create();
  627. rsa.ImportPkcs8PrivateKey(keyData, out _);
  628. return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  629. // using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
  630. // using (RSACng rsa = new RSACng(cngKey))
  631. // {
  632. // return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  633. // }
  634. }
  635. #endregion
  636. #region 获取文件sha256
  637. public string GetSha256(FileStream stream)
  638. {
  639. using (SHA256 mySHA256 = SHA256.Create())
  640. {
  641. byte[] hashValue = mySHA256.ComputeHash(stream);
  642. return Encoding.UTF8.GetString(hashValue);
  643. }
  644. }
  645. #endregion
  646. #region 判断长期
  647. public string CheckForever(DateTime? time)
  648. {
  649. if (time == null)
  650. {
  651. return "";
  652. }
  653. if (time.Value.Year >= 2050)
  654. {
  655. return "长期";
  656. }
  657. return time.Value.ToString("yyyy-MM-dd");
  658. }
  659. #endregion
  660. }
  661. }