#if UNITY_WEBGL && WEBGL_WX using System; using System.Collections.Generic; using HC.MiniJSON; using JetBrains.Annotations; using WeChatWASM; namespace HC { public class HCWxPurchase : HCSingleton, HCIPurchase { private const string PayTypeH5 = "hc_pay_type_h5"; private const string PayServiceOrderId = "hc_pay_service_order_id"; private static bool IsH5Pay => HCAnalyticsManager.Instance.GetRemoteConfigBool("h5_pay", HCWebGLSDKManager.AppInfo.GetPlatform().ToLower().Contains("ios")); private bool _isOpenCustomerService; private string lastOrderId = ""; private int checkH5ExecutionCount = 0; private HashSet h5callbackOrderStatus = new(); public void Init() { if (HCWebGLSDKManager.Base is HCWXBase hcwxBase) { hcwxBase.OpenCustomerServiceSuccess += OpenCustomerServiceSuccess; hcwxBase.OpenCustomerServiceFail += OpenCustomerServiceFail; } CheckOrderList(); InvokeRepeating("CheckOrderList", 800, 32); } private void OpenCustomerServiceSuccess(CustomerServiceSuccessBean customerServiceSuccessBean) { HCDebugger.LogDebug($"[HCWxPurchase] [OpenCustomerServiceSuccess] lastOrderId = {lastOrderId} _isOpenCustomerService = {_isOpenCustomerService} path = {customerServiceSuccessBean.path} "); if (!_isOpenCustomerService) return; _isOpenCustomerService = false; if (string.IsNullOrEmpty(lastOrderId)) { HCSDKManager.Instance.LogEvent(HCInnerStaticSting.HC_WECHAT_PAY_ERROR, "msg", "客服界面跳转回来lastOrderId为空", "order_no", lastOrderId); HCDebugger.LogError("[HCWxPurchase] [OpenCustomerServiceSuccess] lastOrderId is null"); return; } HCSDKManager.Instance.LogEvent(HCInnerStaticSting.HC_WECHAT_PAY_OPEN_CUSTOMER_SERVICE_SUCCESS, "order_no", lastOrderId); checkH5ExecutionCount = 0; // 打开查询load WX.ShowLoading(new ShowLoadingOption() { title = "查询中...", success = result => { HCDebugger.LogDebug($"[HCWxPurchase] [ShowLoading] success result.errMsg = {result.errMsg}"); }, fail = result => { HCDebugger.LogDebug($"[HCWxPurchase] [ShowLoading] fail result.errMsg = {result.errMsg}"); } }); h5callbackOrderStatus.Add(lastOrderId); H5CheckOrderStatus(); InvokeRepeating("H5CheckOrderStatus", 2, 2); } private void H5CheckOrderStatus() { HCServer.Instance.OrderQuery(lastOrderId, (code, msg, orderQueryResult) => { checkH5ExecutionCount++; if (code == 0 && orderQueryResult != null && orderQueryResult.pay_status != HCServer.OrderQueryResult.PayStatusNotPaid) { HCDebugger.LogDebug( $"[HCWxPurchase] [H5CheckOrderStatus] 校验成功 :code = {code} pay_status = {orderQueryResult.pay_status} transaction_id = {orderQueryResult.transaction_id} pay_success_time = {orderQueryResult.pay_success_time}"); var readPaymentArgsFromOrderId = ReadPaymentArgsFromOrderId(lastOrderId); if (readPaymentArgsFromOrderId == null) { HCSDKManager.Instance.LogEvent(HCInnerStaticSting.HC_WECHAT_PAY_ERROR, "msg", "缓存查询订单不存在", "order_no", lastOrderId); HCDebugger.LogError($"[HCWxPurchase] [H5CheckOrderStatus] orderId查询订单失败 lastOrderId = {lastOrderId}"); // 已经被销毁了,无需给回调了 // CallbackPay(lastOrderId, "", "", -1, ""); // 取消 查询 CheckComplete(); return; } DeleteOrder(lastOrderId); if (h5callbackOrderStatus.Contains(lastOrderId)) { // 标记已经通知 h5callbackOrderStatus.Remove(lastOrderId); CallbackPay(lastOrderId, readPaymentArgsFromOrderId.productName, readPaymentArgsFromOrderId.productId, HCServer.OrderQueryResult.PayStatusPaid == orderQueryResult.pay_status ? 0 : orderQueryResult.pay_status, readPaymentArgsFromOrderId.gameExtraParam, serverGameExtraParam: orderQueryResult.game_extra_param, hcPaymentArgs: readPaymentArgsFromOrderId, msg: $"pay_status = {orderQueryResult.pay_status} transaction_id = {orderQueryResult.transaction_id}"); } else { HCDebugger.LogError($"[HCWxPurchase] [H5CheckOrderStatus] lastOrderId = {lastOrderId} callbacked."); } lastOrderId = ""; // 取消 查询 CheckComplete(); return; } HCDebugger.LogDebug($"[HCWxPurchase] [H5CheckOrderStatus] fail checkH5ExecutionCount = {checkH5ExecutionCount} code = {code} msg = {msg} orderQueryResult = {orderQueryResult?.pay_status}"); // 如果执行次数达到3次,取消重复调用并执行其他方法 if (checkH5ExecutionCount >= 3) { CheckComplete(); var readPaymentArgsFromOrderId = ReadPaymentArgsFromOrderId(lastOrderId); CallbackPay(lastOrderId, readPaymentArgsFromOrderId.productName, readPaymentArgsFromOrderId.productId, 2, readPaymentArgsFromOrderId.gameExtraParam, msg: "查询次数到达3次"); } }); } private void CheckComplete() { WX.HideLoading(new HideLoadingOption() { success = result => { HCDebugger.LogDebug($"[HCWxPurchase] [HideLoading] success result.errMsg = {result.errMsg}"); }, fail = result => { HCDebugger.LogDebug($"[HCWxPurchase] [HideLoading] fail result.errMsg = {result.errMsg}"); } }); // 取消重复调用 CancelInvoke("H5CheckOrderStatus"); // 查询一下历史订单 CheckOrderList(); } private void OpenCustomerServiceFail(string errMsg) { if (!_isOpenCustomerService) return; _isOpenCustomerService = false; HCSDKManager.Instance.LogEvent(HCInnerStaticSting.HC_WECHAT_PAY_OPEN_CUSTOMER_SERVICE_FAIL, "msg", errMsg, "order_no", lastOrderId); var readPaymentArgsFromOrderId = ReadPaymentArgsFromOrderId(lastOrderId); CallbackPay(lastOrderId, readPaymentArgsFromOrderId.productName, readPaymentArgsFromOrderId.productId, 1, readPaymentArgsFromOrderId.gameExtraParam, msg: $"open customer service fail : errMsg = {errMsg}"); DeleteOrder(lastOrderId); // 查询一下历史订单 CheckOrderList(); } private bool CallbackPay(string orderNo, string productName, string productId, int code, string gameExtraParam, bool repeat = false, string serverGameExtraParam = "", HCPaymentArgs hcPaymentArgs = null, int balance = 0, string msg = "") { hcPaymentArgs ??= new HCPaymentArgs(); if (code == 0) { HCAnalyticsManager.Instance.IAPSuccess(productName, productId, orderNo, "CNY", hcPaymentArgs.money, gameExtraParam, balance); } else { HCAnalyticsManager.Instance.IAPFail(productName, productId, orderNo, "CNY", hcPaymentArgs.money, hcPaymentArgs.gameExtraParam, $"code = {code} msg = {msg}"); } HCDebugger.LogDebug($"[HCWxPurchase] [CallbackPay] orderNo = {orderNo} productName = {productName} productId = {productId} code = {code} gameExtraParam = {gameExtraParam} serverGameExtraParam = {serverGameExtraParam}"); HCSDKManager.Instance.OnPurchaseDone?.Invoke(orderNo, productName, productId, code == 0, gameExtraParam, repeat, serverGameExtraParam); return HCSDKManager.Instance.OnPurchaseDone != null; } public void Buy(HCPaymentArgs paymentArgs) { lastOrderId = ""; paymentArgs.ext ??= new Dictionary(); paymentArgs.ext[PayTypeH5] = IsH5Pay; HCSDKManager.Instance.LogEvent(HCInnerStaticSting.HC_WECHAT_PAY_CREATE_ORDER_ID, new Dictionary() { ["money"] = paymentArgs.money, ["productId"] = paymentArgs.productId, ["productName"] = paymentArgs.productName, ["gameExtraParam"] = paymentArgs.gameExtraParam, ["ext"] = paymentArgs.ext, }); // 创建订单号 HCServer.Instance.OrderCreate(paymentArgs.productName, paymentArgs.productId, "" + paymentArgs.money, 1, gameExtraParam: paymentArgs.gameExtraParam, callback: (code, msg, orderCreateInfo) => { if (code != 0 || orderCreateInfo == null || string.IsNullOrEmpty(orderCreateInfo.order_no)) { HCSDKManager.Instance.LogEvent(HCInnerStaticSting.HC_WECHAT_PAY_CREATE_ORDER_ID_FAIL, "msg", msg, "code", code); HCDebugger.LogError($"[HCWxPurchase] [Buy] create order error. code = {code} orderCreateInfo = {orderCreateInfo} msg = {msg}"); CallbackPay(lastOrderId, paymentArgs.productName, paymentArgs.productId, 3, paymentArgs.gameExtraParam, msg: $"create order error. code = {code} orderCreateInfo = {orderCreateInfo} msg = {msg}"); return; } var serverOrderNo = orderCreateInfo.order_no; lastOrderId = serverOrderNo; paymentArgs.ext[PayServiceOrderId] = serverOrderNo; HCDebugger.LogDebug($"[HCWxPurchase] [Buy] sessionFrom = {serverOrderNo} sendMessageTitle = {paymentArgs.productName} IsH5Pay = {IsH5Pay}"); if (IsH5Pay) { WX.ShowModal(new ShowModalOption { title = HCAnalyticsManager.Instance.GetRemoteConfigStr("pay_title", ""), content = HCAnalyticsManager.Instance.GetRemoteConfigStr("pay_content", "即将进入客服会话。在客服会话中点击右下角图片即可开始充值"), confirmText = HCAnalyticsManager.Instance.GetRemoteConfigStr("pay_confirm_text", "去充值"), cancelText = HCAnalyticsManager.Instance.GetRemoteConfigStr("pay_cancel_text", "取消"), success = result => { // 用户点击确定' if (result.confirm) { _isOpenCustomerService = true; // 保存订单 SaveOrder(serverOrderNo, paymentArgs); HCWebGLSDKManager.Base.OpenCustomerService(new Dictionary { ["sessionFrom"] = serverOrderNo, ["showMessageCard"] = true, ["sendMessageTitle"] = $"我要充值{paymentArgs.money * 1.0 / 100}元", ["sendMessagePath"] = serverOrderNo, ["sendMessageImg"] = HCAnalyticsManager.Instance.GetRemoteConfigStr("pay_img", "https://wxres.dgtverse.cn/h5pay/img/20231228-145750.png"), }); } else if (result.cancel) { HCSDKManager.Instance.LogEvent(HCInnerStaticSting.HC_WECHAT_PAY_CANCEL, "order_no", serverOrderNo); CallbackPay(lastOrderId, paymentArgs.productName, paymentArgs.productId, 3, paymentArgs.gameExtraParam, msg: $"cancel : order_no = {serverOrderNo}"); } } }); } else { // Android var requestMidasPaymentOption = new RequestMidasPaymentOption { mode = "game", // 沙箱环境 0正式环境 1 测试环境 env = HCAnalyticsManager.Instance.GetRemoteConfigInt("pay_env", 1), offerId = HCStaticParams.PAY_OFFERID, currencyType = "CNY", platform = "android", buyQuantity = paymentArgs.money, zoneId = "1", outTradeNo = serverOrderNo, success = result => { HCDebugger.LogDebug($"[] result.errMsg = {result.errMsg}"); HCAnalyticsManager.Instance.IAPChannelSuccess(paymentArgs.productName, paymentArgs.productId, serverOrderNo, "CNY", paymentArgs.money, paymentArgs.gameExtraParam); // 保存订单,开始充值 SaveOrder(serverOrderNo, paymentArgs); ServerBuy(serverOrderNo, paymentArgs.productName, paymentArgs.money, (code, msg, data) => { }); }, fail = result => { CallbackPay(serverOrderNo, paymentArgs.productName, paymentArgs.productId, 1, paymentArgs.gameExtraParam, msg: $"支付失败: {result.errMsg} {result.errCode}"); HCAnalyticsManager.Instance.IAPChannelFail(paymentArgs.productName, paymentArgs.productId, serverOrderNo, "CNY", paymentArgs.money, paymentArgs.gameExtraParam, $"code = {result.errCode} msg = {result.errMsg}"); HCDebugger.LogDebug($"支付失败: {result.errMsg} {result.errCode}"); }, complete = result => { HCDebugger.LogDebug("支付完成"); HCDebugger.LogDebug($"支付完成: {result.errMsg} {result.errCode}"); } }; WX.RequestMidasPayment(requestMidasPaymentOption); } }); } public void Awarded(string orderID) { HCServer.Instance.OrderAwarded(orderID, ((code, msg, _) => { HCDebugger.LogDebug($"[Awarded] 上报结果: code ={code}"); })); } private string GenerateTradeNo() { // 微信客户端的订单号只要32位 var generateTradeNo = Guid.NewGuid().ToString().Replace("-", ""); HCDebugger.LogDebug($"[HCWxPurchase] [GenerateTradeNo] generateTradeNo = {generateTradeNo}"); return generateTradeNo; } /// /// 检查订单列表,进行补单。 /// private void CheckOrderList() { HCDebugger.LogDebug("[HCWxPurchase] [CheckOrderList] start"); var readAllPaymentArgs = ReadAllPaymentArgs(); if (readAllPaymentArgs.Count > 0) { HCSDKManager.Instance.LogEvent("CheckOrderList", "Count", readAllPaymentArgs.Count, "OrderList", OrderListInfoObjToString(readAllPaymentArgs)); } foreach (var (orderId, paymentArgs) in readAllPaymentArgs) { HCDebugger.LogDebug($"[HCWxPurchase] [CheckOrderList] start : orderId = {orderId}"); if (paymentArgs.ext.ContainsKey(PayTypeH5) && (bool)paymentArgs.ext.GetValue(PayTypeH5, false)) { HCServer.Instance.OrderQuery(orderId, callback: (code, msg, orderQueryResult) => { if (code != 0 || orderQueryResult == null) { HCDebugger.LogError($"[HCWxPurchase] [CheckOrderList] error. orderId = {orderId} code = {code} msg = {msg}"); return; } switch (orderQueryResult.pay_status) { case HCServer.OrderQueryResult.PayStatusNotPaid: HCDebugger.LogDebug($"[HCWxPurchase] [CheckOrderList] orderId = {orderId} pay_status = {orderQueryResult.pay_status}"); break; case HCServer.OrderQueryResult.PayStatusPaid when HCSDKManager.Instance.OnPurchaseDone == null: return; case HCServer.OrderQueryResult.PayStatusPaid: CallbackPay(orderId, paymentArgs.productName, paymentArgs.productId, 0, paymentArgs.gameExtraParam, false, orderQueryResult.game_extra_param, hcPaymentArgs: paymentArgs, msg: $"pay_status = {orderQueryResult.pay_status}"); DeleteOrder(orderId); break; case HCServer.OrderQueryResult.PayStatusPaymentFailed: DeleteOrder(orderId); break; } }); } else { ServerBuy(orderId, paymentArgs.productName, paymentArgs.money, (code, msg, data) => { }); } } } private void ServerBuy(string orderId, string productName, int money, [CanBeNull] Action callback = null) { HCServer.Instance.MiniAppPay(orderId, productName, money, (code, msg, data) => { HCDebugger.LogDebug($"支付成功后的服务器校验回调 code = {code} msg = {msg} data balance = {data.balance} order_no = {data.order_no} callback = {callback}"); callback?.Invoke(code, msg, data); if (HCSDKManager.Instance.OnPurchaseDone == null) { HCDebugger.LogError("[HCWxPurchase] [ServerBuy] [MiniAppPay] OnPurchaseDone is null;"); } // 如果服务器返回的了订单id,那就直接给删除掉 var orderNo = data.order_no; if (code == 0 && !string.IsNullOrEmpty(orderNo)) { HCDebugger.LogDebug($"微信支付成功了,删除订单, orderNo = {orderNo}"); // DeleteOrder(orderId); var paymentArgs = ReadPaymentArgsFromOrderId(orderNo); paymentArgs.ext ??= new Dictionary(); paymentArgs.ext[PayTypeH5] = true; HCDebugger.LogDebug($"微信支付成功了,保存h5订单, orderNo = {orderNo} paymentArgs = {Json.Serialize(paymentArgs)}"); SaveOrder(orderId, paymentArgs); // 查h5订单 h5callbackOrderStatus.Add(lastOrderId); H5CheckOrderStatus(); InvokeRepeating("H5CheckOrderStatus", 2, 2); } else { HCDebugger.LogDebug("微信支付成功了,请求失败了。"); } }); } private void SaveOrder(string orderId, HCPaymentArgs paymentArgs) { HCDebugger.LogDebug($"[HCWxPurchase] [SaveOrder] orderId = {orderId}"); var readAllPaymentArgs = ReadAllPaymentArgs(); if (readAllPaymentArgs.ContainsKey(orderId)) { readAllPaymentArgs.Remove(orderId); } readAllPaymentArgs[orderId] = paymentArgs; var data = Save(readAllPaymentArgs); HCDebugger.LogDebug($"[HCWxPurchase] [SaveOrder] orderId = {orderId} data = {data}"); } private void DeleteOrder(string orderId) { HCDebugger.LogDebug($"[HCWxPurchase] [DeleteOrder] orderId = {orderId}"); var readAllPaymentArgs = ReadAllPaymentArgs(); if (readAllPaymentArgs.ContainsKey(orderId)) { HCDebugger.LogDebug($"[HCWxPurchase] [DeleteOrder] orderId = {orderId} success"); readAllPaymentArgs.Remove(orderId); } var data = Save(readAllPaymentArgs); HCDebugger.LogDebug($"[HCWxPurchase] [DeleteOrder] orderId = {orderId} data = {data}"); } private static string Save(Dictionary readAllPaymentArgs) { var saveString = OrderListInfoObjToString(readAllPaymentArgs); HCTools.SavePlayerPrefsString("HCIPurchase", saveString); return saveString; } private static string OrderListInfoObjToString(Dictionary readAllPaymentArgs) { var saveData = new Dictionary(); readAllPaymentArgs ??= new Dictionary(); foreach (var (key, paymentArgs) in readAllPaymentArgs) { saveData[key] = new Dictionary() { ["productId"] = paymentArgs.productId, ["productName"] = paymentArgs.productName, ["gameExtraParam"] = paymentArgs.gameExtraParam, ["money"] = paymentArgs.money, ["ext"] = paymentArgs.ext ??= new Dictionary() }; } var saveString = MiniJSON.Json.Serialize(saveData); return saveString; } public HCPaymentArgs ReadPaymentArgsFromOrderId(string orderId) { return ReadAllPaymentArgs().GetValue(orderId, null); } private Dictionary ReadAllPaymentArgs() { var result = new Dictionary(); try { var playerPrefsString = HCTools.GetPlayerPrefsString("HCIPurchase"); HCDebugger.LogDebug($"[HCWxPurchase] [ReadAllPaymentArgs] playerPrefsString = {playerPrefsString}"); if (string.IsNullOrEmpty(playerPrefsString)) { return result; } var deserialize = (Dictionary)MiniJSON.Json.Deserialize(playerPrefsString); foreach (var (key, value) in deserialize) { var data = value as Dictionary; result[key] = new HCPaymentArgs { productId = (string)data.GetValue("productId", ""), gameExtraParam = (string)data.GetValue("gameExtraParam", ""), productName = (string)data.GetValue("productName", ""), money = int.Parse("" + data.GetValue("money", 0)), ext = (Dictionary)data.GetValue("ext", new Dictionary()) }; } } catch (Exception e) { // ignored HCDebugger.LogDebug($"[HCWxPurchase] [ReadAllPaymentArgs] Error = {e.Message}"); } return result; } } } #endif