public static async Task <(PoseBillingResult BillingResult, long Payload, string OrderId)> InAppProductProcess(InAppPurchase inAppPurchase, string appPackageName, string purchaseToken)
        {
            ProductPurchase poductPurchase = await _androidPublisher.Purchases.Products.Get(appPackageName, inAppPurchase.ProductId, purchaseToken).ExecuteAsync();

            if (!long.TryParse(poductPurchase.DeveloperPayload, out long payLoad))
            {
                return(null, 0, "");
            }

            PoseBillingResult billingResult = new PoseBillingResult();

            switch (poductPurchase.PurchaseState)
            {
            case 0:
                billingResult.PurchaseStateType = PosePurchaseStateType.Purchased;
                break;

            case 1:
                billingResult.PurchaseStateType = PosePurchaseStateType.Canceled;
                break;

            case 2:
                billingResult.PurchaseStateType = PosePurchaseStateType.Pending;
                break;
            }

            DateTime origin       = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            DateTime purchaseTime = origin.AddMilliseconds(poductPurchase.PurchaseTimeMillis ?? 0);

            billingResult.MemberRoleType = inAppPurchase.OfferRoleType;
            billingResult.RoleExpireTime = purchaseTime.AddDays(inAppPurchase.OfferPeriod);
            billingResult.ProductId      = inAppPurchase.ProductId;

            return(billingResult, payLoad, poductPurchase.OrderId);
        }
        public static async Task <(PoseBillingResult BillingResult, long Payload, string OrderId)> SubscriptionProcess(InAppPurchase inAppPurchase, string appPackageName, string purchaseToken)
        {
            SubscriptionPurchase subscriptionPurchase = await _androidPublisher.Purchases.Subscriptions.Get(appPackageName, inAppPurchase.ProductId, purchaseToken).ExecuteAsync();

            if (!long.TryParse(subscriptionPurchase.DeveloperPayload, out long payLoad))
            {
                return(null, 0, "");
            }

            DateTime origin     = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            DateTime expireTiem = origin.AddMilliseconds(subscriptionPurchase.ExpiryTimeMillis ?? 0);

            PoseBillingResult billingResult = new PoseBillingResult();

            billingResult.PurchaseStateType = ParseSubscriptionPurchaseState(subscriptionPurchase);
            billingResult.MemberRoleType    = inAppPurchase.OfferRoleType;
            billingResult.RoleExpireTime    = expireTiem;
            billingResult.ProductId         = inAppPurchase.ProductId;

            return(billingResult, payLoad, subscriptionPurchase.OrderId);
        }
Exemple #3
0
        public async Task <PoseBillingResult> PurchaseAsync(string productId, ItemType itemType)
        {
            PoseBillingResult billingResult = null;
            var billing          = CrossInAppBilling.Current;
            var webApiService    = ShinyHost.Resolve <IWebApiService>();
            var deviceInfoHelper = DependencyService.Resolve <IDeviceInfoHelper>();

            try
            {
                var connected = await billing.ConnectAsync(itemType);

                if (!connected)
                {
                    return new PoseBillingResult {
                               PurchaseErrorType = PosePurchaseErrorType.FailStoreConnect
                    }
                }
                ;

                // 서버에서 payload 얻어오기
                var server_payload = await webApiService.RequestAsyncWithToken <O_E_INSERT_IN_APP_BILLING_BY_GOOGLE>(new WebRequestContext
                {
                    SerializeType = SerializeType.MessagePack,
                    MethodType    = WebMethodType.POST,
                    BaseUrl       = AppConfig.PoseWebBaseUrl,
                    ServiceUrl    = BillingProxy.ServiceUrl,
                    SegmentGroup  = BillingProxy.P_E_INSERT_IN_APP_BILLING_BY_GOOGLE,
                    NeedEncrypt   = true,
                    PostData      = new I_E_INSERT_IN_APP_BILLING_BY_GOOGLE
                    {
                        ProductID = productId,
                    }
                });

                if (server_payload == null)
                {
                    return new PoseBillingResult {
                               PurchaseErrorType = PosePurchaseErrorType.ServerError
                    }
                }
                ;

                //check purchases
                var googlePurchaseResult = await billing.PurchaseAsync(productId, itemType, server_payload.BillingPayload);

                if (googlePurchaseResult == null)
                {
                    return new PoseBillingResult {
                               PurchaseErrorType = PosePurchaseErrorType.FailStoreConnect
                    }
                }
                ;

                // 서버 인증
                using (UserDialogs.Instance.Loading(LocalizeString.Loading))
                {
                    var server_billingResult = await webApiService.RequestAsyncWithToken <O_E_UPDATE_IN_APP_BILLING_BY_GOOGLE>(new WebRequestContext
                    {
                        SerializeType = SerializeType.MessagePack,
                        MethodType    = WebMethodType.POST,
                        BaseUrl       = AppConfig.PoseWebBaseUrl,
                        ServiceUrl    = BillingProxy.ServiceUrl,
                        SegmentGroup  = BillingProxy.P_E_UPDATE_IN_APP_BILLING_BY_GOOGLE,
                        NeedEncrypt   = true,
                        PostData      = new I_E_UPDATE_IN_APP_BILLING_BY_GOOGLE
                        {
                            AppPackageName = deviceInfoHelper.AppPackageName,
                            ProductID      = googlePurchaseResult.ProductId,
                            PurchaseToken  = googlePurchaseResult.PurchaseToken,
                        }
                    });

                    billingResult = server_billingResult?.BillingResult ?? new PoseBillingResult {
                        PurchaseErrorType = PosePurchaseErrorType.SuccessPurchaseButServerError
                    };

                    //If we are on iOS we are done, else try to consume the purchase
                    //Device.RuntimePlatform comes from Xamarin.Forms, you can also use a conditional flag or the DeviceInfo plugin
                    //if (Device.RuntimePlatform == Device.iOS)
                    //    return result;

                    // 소비성 상품은 컨슘 처리
                    if (itemType == ItemType.InAppPurchase &&
                        billingResult.PurchaseStateType == PosePurchaseStateType.Purchased)
                    {
                        await CrossInAppBilling.Current.ConsumePurchaseAsync(googlePurchaseResult.ProductId, googlePurchaseResult.PurchaseToken);
                    }
                }
            }
            catch (InAppBillingPurchaseException pEx)
            {
                billingResult = new PoseBillingResult();

                if (pEx.PurchaseError == PurchaseError.AlreadyOwned)
                {
                    billingResult.PurchaseErrorType = PosePurchaseErrorType.AlreadyOwned;
                }
            }
            catch (Exception)
            {
                billingResult = new PoseBillingResult();
                billingResult.PurchaseErrorType = PosePurchaseErrorType.UnknownError;
            }
            finally
            {
                await billing.DisconnectAsync();
            }

            return(billingResult);
        }
        public static async Task <O_E_CHECK_MEMBERSHIP_BY_GOOGLE> Execute(I_E_CHECK_MEMBERSHIP_BY_GOOGLE input, long userNo, int serviceRoleType)
        {
            PoseBillingResult billingResult = null;

            ////////////////////////////////////////////////////
            /// 프로모션 유저 만료 처리
            ///////////////////////////////////////////////////
            if (serviceRoleType == (int)ServiceRoleType.Promotion)
            {
                billingResult = new PoseBillingResult()
                {
                    MemberRoleType = MemberRoleType.Regular,
                    RoleExpireTime = DateTime.UtcNow,
                };

                // Update DB
                bool db_output_promo;
                using (var P_UPDATE_USER_ROLE = new PoseGlobalDB.Procedures.P_UPDATE_USER_ROLE())
                {
                    P_UPDATE_USER_ROLE.SetInput(new PoseGlobalDB.Procedures.P_UPDATE_USER_ROLE.Input
                    {
                        UserNo         = userNo,
                        LinkedTransNo  = 0,
                        RoleType       = billingResult.MemberRoleType.ToString(),
                        RoleExpireTime = billingResult.RoleExpireTime,
                        CurrentTime    = DateTime.UtcNow,
                    });

                    db_output_promo = P_UPDATE_USER_ROLE.OnQuery();

                    if (P_UPDATE_USER_ROLE.EntityStatus != null || db_output_promo == false)
                    {
                        ErrorHandler.OccurException(RowCode.DB_User_Role_Update_Failed);
                    }
                }

                // Refrash PoseToken
                billingResult.MemberRoleType.ToString().TryParseEnum(out ServiceRoleType promoServiceRoleType);
                billingResult.PoseToken = PoseCredentials.CreateToken(userNo, promoServiceRoleType);

                return(new O_E_CHECK_MEMBERSHIP_BY_GOOGLE
                {
                    BillingResult = billingResult,
                });
            }

            ////////////////////////////////////////////////////
            /// 결제 유저 멤버십 처리
            ///////////////////////////////////////////////////

            // Check DB
            PoseGlobalDB.Procedures.P_SELECT_LINKED_BILLING.Output db_output;
            using (var P_SELECT_LINKED_BILLING = new PoseGlobalDB.Procedures.P_SELECT_LINKED_BILLING())
            {
                P_SELECT_LINKED_BILLING.SetInput(userNo);

                db_output = P_SELECT_LINKED_BILLING.OnQuery();

                if (P_SELECT_LINKED_BILLING.EntityStatus != null || db_output.Result != 0)
                {
                    ErrorHandler.OccurException(RowCode.P_SELECT_LINKED_BILLING + db_output.Result);
                }
            }

            // Check ProductID valid
            if (!InAppPurchase.TryGetInAppPurchase(db_output.InAppBilling.product_id, out var inAppPurchase) ||
                inAppPurchase.StoreType != StoreType.GooglePlay)
            {
                Log4Net.WriteLog($"Invalid Google ProudctId, UserNo: {userNo}, productId: {db_output.InAppBilling.product_id}", Log4Net.Level.ERROR);
                ErrorHandler.OccurException(RowCode.Invalid_Product_Id);
            }

            long linkedTransNo = 0;

            if (inAppPurchase.PurchaseType == InAppPurchaseType.InAppProduct)
            {
                linkedTransNo = db_output.UserRole.linked_trans_no;

                billingResult = new PoseBillingResult();
                billingResult.MemberRoleType    = inAppPurchase.OfferRoleType;
                billingResult.RoleExpireTime    = db_output.UserRole.expire_time;
                billingResult.ProductId         = db_output.InAppBilling.product_id;
                billingResult.PurchaseStateType = db_output.UserRole.expire_time > DateTime.UtcNow ?
                                                  PosePurchaseStateType.Purchased : PosePurchaseStateType.Unknown;
            }
            else if (inAppPurchase.PurchaseType == InAppPurchaseType.Subscription)
            {
                var process_ret = await P_E_UPDATE_IN_APP_BILLING_BY_GOOGLE.SubscriptionProcess(inAppPurchase, input.AppPackageName, db_output.InAppBilling.purchase_token);

                billingResult = process_ret.BillingResult;
                linkedTransNo = process_ret.Payload;
            }

            // 회원등급 심사
            if (billingResult.PurchaseStateType != PosePurchaseStateType.Purchased &&
                billingResult.PurchaseStateType != PosePurchaseStateType.Grace)    // 결제 유예기간..
            {
                billingResult.MemberRoleType = MemberRoleType.Regular;
                linkedTransNo = 0;
            }

            // Update DB
            bool db_output2;

            using (var P_UPDATE_USER_ROLE = new PoseGlobalDB.Procedures.P_UPDATE_USER_ROLE())
            {
                P_UPDATE_USER_ROLE.SetInput(new PoseGlobalDB.Procedures.P_UPDATE_USER_ROLE.Input
                {
                    UserNo         = userNo,
                    LinkedTransNo  = linkedTransNo,
                    RoleType       = billingResult.MemberRoleType.ToString(),
                    RoleExpireTime = billingResult.RoleExpireTime,
                    CurrentTime    = DateTime.UtcNow,
                });

                db_output2 = P_UPDATE_USER_ROLE.OnQuery();

                if (P_UPDATE_USER_ROLE.EntityStatus != null || db_output2 == false)
                {
                    ErrorHandler.OccurException(RowCode.DB_User_Role_Update_Failed);
                }
            }

            // Refrash PoseToken
            billingResult.MemberRoleType.ToString().TryParseEnum(out ServiceRoleType convertedServiceRoleType);
            billingResult.PoseToken = PoseCredentials.CreateToken(userNo, convertedServiceRoleType);

            return(new O_E_CHECK_MEMBERSHIP_BY_GOOGLE
            {
                BillingResult = billingResult,
            });
        }
        public static async Task <O_E_UPDATE_IN_APP_BILLING_BY_GOOGLE> Execute(I_E_UPDATE_IN_APP_BILLING_BY_GOOGLE input, long userNo)
        {
            if (input == null ||
                string.IsNullOrEmpty(input.ProductID) ||
                string.IsNullOrEmpty(input.AppPackageName) ||
                string.IsNullOrEmpty(input.PurchaseToken))
            {
                ErrorHandler.OccurException(RowCode.Invalid_InputValue);
            }

            // Check ProductID valid
            if (!InAppPurchase.TryGetInAppPurchase(input.ProductID, out var inAppPurchase) ||
                inAppPurchase.StoreType != StoreType.GooglePlay)
            {
                Log4Net.WriteLog($"Invalid Google ProudctId, UserNo: {userNo}, productId: {input.ProductID}", Log4Net.Level.ERROR);
                ErrorHandler.OccurException(RowCode.Invalid_Product_Id);
            }

            PoseBillingResult billingResult = null;
            long   trasNo  = 0;
            string orderId = string.Empty;

            switch (inAppPurchase.PurchaseType)
            {
            case InAppPurchaseType.InAppProduct:     // 소비성 상품
            {
                var process_ret = await InAppProductProcess(inAppPurchase, input.AppPackageName, input.PurchaseToken);

                billingResult = process_ret.BillingResult;
                trasNo        = process_ret.Payload;
                orderId       = process_ret.OrderId;
            }
            break;

            case InAppPurchaseType.Subscription:     // 구독 상품
            {
                var process_ret = await SubscriptionProcess(inAppPurchase, input.AppPackageName, input.PurchaseToken);

                billingResult = process_ret.BillingResult;
                trasNo        = process_ret.Payload;
                orderId       = process_ret.OrderId;
            }
            break;
            }

            // 유효하지않은 PurchaseToken
            if (billingResult == null)
            {
                Log4Net.WriteLog($"Google PurchaseToken is Invalid, UserNo: {userNo}, productId: {input.ProductID}, purchaseToken: {input.PurchaseToken}", Log4Net.Level.ERROR);
                ErrorHandler.OccurException(RowCode.Invalid_Google_Receipt);
            }

            if (billingResult.PurchaseStateType == PosePurchaseStateType.Purchased)
            {
                // DB Process
                PoseGlobalDB.Procedures.P_UPDATE_IN_APP_BILLING.Output db_output;
                using (var P_UPDATE_IN_APP_BILLING = new PoseGlobalDB.Procedures.P_UPDATE_IN_APP_BILLING())
                {
                    P_UPDATE_IN_APP_BILLING.SetInput(new PoseGlobalDB.Procedures.P_UPDATE_IN_APP_BILLING.Input
                    {
                        UserNo         = userNo,
                        TransNo        = trasNo,
                        PurchaseState  = PosePurchaseStateType.Purchased.ToString(),
                        PurchaseToken  = input.PurchaseToken,
                        OrderId        = orderId,
                        RoleType       = billingResult.MemberRoleType.ToString(),
                        RoleExpireTime = billingResult.RoleExpireTime,
                        CurrentTime    = DateTime.UtcNow,
                    });

                    db_output = P_UPDATE_IN_APP_BILLING.OnQuery();

                    if (P_UPDATE_IN_APP_BILLING.EntityStatus != null || db_output.Result != 0)
                    {
                        ErrorHandler.OccurException(RowCode.P_UPDATE_IN_APP_BILLING + db_output.Result);
                    }
                }

                // Refrash PoseToken
                billingResult.MemberRoleType.ToString().TryParseEnum(out ServiceRoleType serviceRoleType);
                billingResult.PoseToken = PoseCredentials.CreateToken(userNo, serviceRoleType);
            }

            return(new O_E_UPDATE_IN_APP_BILLING_BY_GOOGLE
            {
                BillingResult = billingResult,
            });
        }