Skip to content

Amazon Offering Parsing#824

Merged
beylmk merged 28 commits into
bc5-supportfrom
offering-factory
Mar 16, 2023
Merged

Amazon Offering Parsing#824
beylmk merged 28 commits into
bc5-supportfrom
offering-factory

Conversation

@beylmk

@beylmk beylmk commented Feb 27, 2023

Copy link
Copy Markdown
Contributor

Amazon only has a single productId (the termSku) returned in offerings, while google has both the subId and the basePlanID. So now the way we parse offerings must split between the stores.

This PR introduces an OfferingParser and OfferingParserFactory, instantiating the correct parser from the factory upon initialization. I'd love to get some feedback on this approach before writing tests, as I think those will be a lot of work...

My thoughts on other potential implementations and why i chose this one:

  • simply pass the store as a parameter into the OfferingFactories methods, and if/else split how we do parsing on that

this is the easiest, but it breaks our general "don't have store-specific stuff in purchases" rule. see this commit as an example

  • make OfferingFactory an abstract class and instantiate a store-specific implementation upon purchases initialization, somewhat like BillingFactory works. see this commit for example (it's not complete/perfect, i just committed for easy reviewing of the overall architecture idea)

this feels a bit like over-architecting to me... but i could see more complex offering parsing in the future -- for instance, if we implement sorted SubscriptionOptions. This is the route I took in this PR.

  • pull the offering parsing into Billing implementation. There is really only one line of code that differs, so we could only pull line out into a function in the Billing classes for now (and keep the rest in the base billing class).

I went this route here, but it doesn't feel totally right since offering parsing doesn't communicate with the billing libraries and isn't really a "billing" thing.

@beylmk beylmk changed the title Amazon Offering Parsing [WIP] Amazon Offering Parsing Feb 27, 2023

@swehner swehner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good - I like the approach. Small comment re: the interface

Comment on lines +43 to +44
"offering",
Store.PLAY_STORE

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these changes are completely unrelated, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah, the test changes are left from a different approach. was waiting to update them to this one until i get sign off

val productIdentifier = packageJson.getString("platform_product_identifier")

val planIdentifier = packageJson.optString("platform_product_plan_identifier").takeIf { it.isNotEmpty() }
val product = findMatchingProduct(productsById, productIdentifier, planIdentifier)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this interface is a bit strange - one difference between Amazon and Google is that Amazon just needs platform_product_identifier and that Google also needs the platform_product_plan_identifier. I would move this difference into the findMatchingProduct method.
Otherwise for any new piece of information we'll have to change the API again.

Maybe we can do findMatchingProduct(productsById, packageJson)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair point... i was just trying to reuse as much code as possible but it's less future-proof.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, since we are trying to avoid having store-specific logic here, that makes sense.

@beylmk beylmk requested review from a team and tonidero and removed request for tonidero February 28, 2023 16:47
# Conflicts:
#	common/src/main/java/com/revenuecat/purchases/common/OfferingFactories.kt
#	feature/amazon/src/main/java/com/revenuecat/purchases/amazon/storeProductConversions.kt
@beylmk beylmk requested review from tonidero and vegaro March 2, 2023 21:11

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay! The approach makes sense to me 👍


abstract class OfferingParser {

abstract fun findMatchingProduct(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be protected I think?

}
}

fun String.toPackageType(): PackageType =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this could be private I think?

val productIdentifier = packageJson.getString("platform_product_identifier")

val planIdentifier = packageJson.optString("platform_product_plan_identifier").takeIf { it.isNotEmpty() }
val product = findMatchingProduct(productsById, productIdentifier, planIdentifier)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, since we are trying to avoid having store-specific logic here, that makes sense.

@beylmk

beylmk commented Mar 8, 2023

Copy link
Copy Markdown
Contributor Author

@tonidero thanks for the review :)

@vegaro vegaro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach also makes sense to me. Sorry for the delay

?.firstOrNull()
}
return storeProducts?.firstOrNull { storeProduct ->
storeProduct.subscriptionOptions?.firstOrNull { it.isBasePlan }?.id == planIdentifier

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SubscriptionOptions has a basePlan property now you can now use 👇

Suggested change
storeProduct.subscriptionOptions?.firstOrNull { it.isBasePlan }?.id == planIdentifier
storeProduct.subscriptionOptions?.basePlan?.id == planIdentifier

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, i hope i didn't miss anything else when merging... it seems like that was the only change to OfferingFactories since this PR...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup yup, I think this is the only part of the improvements that can be used here 😇 Pretty small improvement but 🤷‍♂️

@beylmk beylmk force-pushed the offering-factory branch from ee3c8d1 to 9acd764 Compare March 15, 2023 19:43
import org.junit.runner.RunWith
import org.robolectric.annotation.Config

//@RunWith(AndroidJUnit4::class)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i started writing these but felt like it would kinda be wasted time without AmazonStoreProduct work done..

@beylmk beylmk marked this pull request as ready for review March 15, 2023 19:45
@beylmk beylmk requested a review from a team March 15, 2023 19:47
@beylmk beylmk changed the title [WIP] Amazon Offering Parsing Amazon Offering Parsing Mar 16, 2023
@beylmk beylmk force-pushed the offering-factory branch from b49189d to cbc11a0 Compare March 16, 2023 16:20

@joshdholtz joshdholtz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me! Just one question about some commented out tests and I think you have a commented about writing more tests but... LGTM 💪

Comment on lines +4452 to +4478
// private fun mockOfferingsParser() {
// with(mockOfferingParser) {
// every {
// retrieveCustomerInfo(any(), any(), false, any())
// } answers {
// val callback = arg<ReceiveCustomerInfoCallback?>(3)
// if (errorGettingCustomerInfo == null) {
// callback?.onReceived(mockInfo)
// } else {
// callback?.onError(errorGettingCustomerInfo)
// }
// }
// every {
// cacheCustomerInfo(any())
// } just runs
// every {
// sendUpdatedCustomerInfoToDelegateIfChanged(any())
// } just runs
// every {
// updatedCustomerInfoListener = any()
// } just runs
// every {
// updatedCustomerInfoListener
// } returns null
// }
// }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these need to be uncommented or rewritten yet?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was gonna wait until amazonstoreproduct is done!

@beylmk beylmk force-pushed the offering-factory branch from b9450a1 to fe5f4a7 Compare March 16, 2023 20:22
@beylmk beylmk merged commit 16a6e1c into bc5-support Mar 16, 2023
@beylmk beylmk deleted the offering-factory branch March 16, 2023 20:40
@joshdholtz joshdholtz mentioned this pull request Mar 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants