Skip to content

[WIP] CF-1196 Fix offerings parsing for Amazon#802

Closed
beylmk wants to merge 9 commits into
bc5-supportfrom
amazon-parsing
Closed

[WIP] CF-1196 Fix offerings parsing for Amazon#802
beylmk wants to merge 9 commits into
bc5-supportfrom
amazon-parsing

Conversation

@beylmk

@beylmk beylmk commented Feb 15, 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.

I see a few routes for this:

  • 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...

  • pull the offering parsing into Billing implementation. See the latest changes in the PR for this version. There is really only one line of code that differs, so i only pulled that line out into a function member in the Billing classes for now. but we could theoretically refactor and make that line a normal function in Billing.

I like this route best, as it re-uses code and doesn't create a lot of overhead. There are probably cleaner ways to achieve the same thing... i.e. rather than passing the function through all the methods, just have a billing.createOfferings() method which calls into super() for the repetitive code?

Tests will need to be updated based on the approach chosen..

@beylmk beylmk added the pr:feat A new feature label Feb 15, 2023
}
}
val planIdentifier = optString("platform_product_plan_identifier").takeIf { it.isNotEmpty() }
val product = productMatchingMethod.invoke(productsById, productIdentifier, 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.

if we went this route i'd need to think through thread-safety

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.

Are there potential threading issues because the productMatchingMethod might be accessing some shared cache state? 🤔

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 don't think there are right now, but mayyyybe there could be in the future, so was thinking we should just be defensive? might refactor this anyway...

# Conflicts:
#	common/src/test/java/com/revenuecat/purchases/common/OfferingsTest.kt
#	purchases/src/main/kotlin/com/revenuecat/purchases/Purchases.kt

override val productMatchingMethod: ((Map<String, List<StoreProduct>>, String, String?) -> StoreProduct?) = {
productsById, productIdentifier: String, _ ->
productsById[productIdentifier]?.get(0)

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 we want firstOrNull() to prevent an index out of bounds?

Suggested change
productsById[productIdentifier]?.get(0)
productsById[productIdentifier]?.firstOrNull()

return@matcher productsById[productIdentifier]
.takeIf { it?.size == 1 }
?.takeIf { it[0].type == ProductType.INAPP }
?.get(0)

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.

Just for safety? 🤷

Suggested change
?.get(0)
?.firstOrNull()

Comment on lines +713 to +715
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.

nit: add a return on this line for explicitness/consistency since there is a return above

}
}
val planIdentifier = optString("platform_product_plan_identifier").takeIf { it.isNotEmpty() }
val product = productMatchingMethod.invoke(productsById, productIdentifier, 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.

Are there potential threading issues because the productMatchingMethod might be accessing some shared cache state? 🤔

@beylmk

beylmk commented Feb 27, 2023

Copy link
Copy Markdown
Contributor Author

spoke with @joshdholtz and we agreed a Factory is the better route... so closing this in lieu of #824

@beylmk beylmk closed this Feb 27, 2023
@beylmk beylmk mentioned this pull request Feb 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:feat A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants