Tuesday, 25 August 2020

Why does an order with Refunded status show as PURCHASED in Google in-app payment system?

I use Google in-app Billing Version 3 in my Android App, I'm testing the order module of the App based the following code.

In the case, a user's order has been Refunded by Google Play, but when I run mBilling.initBillingClient(), I find purchase.purchaseState == Purchase.PurchaseState.PURCHASED in private fun processPurchases is launched.

It seems that an order with Refunded status as PURCHASED successfully, how can I fix it?

FragmentBuy.kt

class FragmentBuy : Fragment() {
     ...
     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = DataBindingUtil.inflate(
            inflater, R.layout.layout_buy, container, false
        )
   
        val mBilling=Billing.getInstance(requireActivity(), getString(R.string.skuRegisterApp)) 
        mBilling.initBillingClient()
        ...       
    }

}

Billing.kt

class Billing private constructor (private val mContext: Context, private val purchaseItem :String)
    :PurchasesUpdatedListener, BillingClientStateListener   {

    private lateinit var playStoreBillingClient: BillingClient
    private val mapSkuDetails = mutableMapOf<String,SkuDetails>()

    fun initBillingClient() {
        playStoreBillingClient = BillingClient
            .newBuilder(mContext)
            .enablePendingPurchases() 
            .setListener(this)
            .build()

        if (!playStoreBillingClient.isReady) {
            playStoreBillingClient.startConnection(this)  //It will launach override fun onBillingSetupFinished()
        }
    }

    override fun onBillingSetupFinished(billingResult: BillingResult) {
        when (billingResult.responseCode) {
            BillingClient.BillingResponseCode.OK -> {                   
                queryAndProcessPurchasesAsync()
            }
                ...
        }
    }

    private fun queryAndProcessPurchasesAsync() {
        val purchasesResult = HashSet<Purchase>()
        var result = playStoreBillingClient.queryPurchases(BillingClient.SkuType.INAPP)
        result?.purchasesList?.apply { purchasesResult.addAll(this) }

        processPurchases(purchasesResult)
    }


    private fun processPurchases(purchasesResult: Set<Purchase>): Job {
        val validPurchases = HashSet<Purchase>(purchasesResult.size)
        purchasesResult.forEach { purchase ->
            if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
                if (purchase.sku.equals(purchaseItem)) {
                    if (isSignatureValid(purchase)) {
                        validPurchases.add(purchase)
                        setIsRegisteredAppAsTrue(mContext)  //It will be launched even if the status of the order is refunded.                           
                    }
                }
            }
            ...

        }
        acknowledgeNonConsumablePurchasesAsync(validPurchases.toList())

    }


    private fun acknowledgeNonConsumablePurchasesAsync(nonConsumables: List<Purchase>) {
        ...
    }


    override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
        when (billingResult.responseCode) {
            BillingClient.BillingResponseCode.OK -> {
                purchases?.apply { processPurchases(this.toSet()) }
            }
                ...
        }
    }

    fun purchaseProduct(activity: Activity) {
        val skuDetails = mapSkuDetails[purchaseItem]
        skuDetails?.let{
            val purchaseParams = BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build()
            playStoreBillingClient.launchBillingFlow(activity, purchaseParams)
        }
    }

    companion object {
        private const val LOG_TAG = "BillingRepository"

        private var INSTANCE: Billing? = null
        fun getInstance(mContext: Context, purchaseItem: String): Billing =
            INSTANCE ?: synchronized(this) {
                INSTANCE ?: Billing(mContext, purchaseItem).also { INSTANCE = it }
            }
    }


}


from Why does an order with Refunded status show as PURCHASED in Google in-app payment system?

No comments:

Post a Comment