Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose Klarna property on Source object #2396

Merged
merged 1 commit into from
Apr 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ class KlarnaSourceActivity : AppCompatActivity() {
klarnaParams = KlarnaSourceParams(
purchaseCountry = "UK",
lineItems = LINE_ITEMS,
customPaymentMethods = setOf(
KlarnaSourceParams.CustomPaymentMethods.Installments,
KlarnaSourceParams.CustomPaymentMethods.PayIn4
),
billingFirstName = "Arthur",
billingLastName = "Dent",
billingAddress = Address.Builder()
Expand Down
37 changes: 35 additions & 2 deletions stripe/src/main/java/com/stripe/android/model/Source.kt
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ data class Source internal constructor(
@param:Usage @field:Usage @get:Usage
val usage: String? = null,

private val weChatParam: WeChat? = null,
private val _weChat: WeChat? = null,

private val _klarna: Klarna? = null,

/**
* Information about the items and shipping associated with the source. Required for
Expand All @@ -147,7 +149,16 @@ data class Source internal constructor(
"Source type must be '${SourceType.WECHAT}'"
}

return requireNotNull(weChatParam)
return requireNotNull(_weChat)
}

val klarna: Klarna
get() {
check(SourceType.KLARNA == type) {
"Source type must be '${SourceType.KLARNA}'"
}

return requireNotNull(_klarna)
}

@Retention(AnnotationRetention.SOURCE)
Expand Down Expand Up @@ -208,6 +219,28 @@ data class Source internal constructor(
}
}

@Parcelize
data class Klarna(
val firstName: String?,
val lastName: String?,
val purchaseCountry: String?,
val clientToken: String?,
val payNowAssetUrlsDescriptive: String?,
val payNowAssetUrlsStandard: String?,
val payNowName: String?,
val payNowRedirectUrl: String?,
val payLaterAssetUrlsDescriptive: String?,
val payLaterAssetUrlsStandard: String?,
val payLaterName: String?,
val payLaterRedirectUrl: String?,
val payOverTimeAssetUrlsDescriptive: String?,
val payOverTimeAssetUrlsStandard: String?,
val payOverTimeName: String?,
val payOverTimeRedirectUrl: String?,
val paymentMethodCategories: Set<String>,
val customPaymentMethods: Set<String>
) : StripeModel

companion object {
internal const val OBJECT_TYPE = "source"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.annotation.Size
import com.stripe.android.model.Source
import com.stripe.android.model.SourceTypeModel
import com.stripe.android.model.StripeJsonUtils
import com.stripe.android.model.StripeJsonUtils.optString
import com.stripe.android.model.StripeModel
import org.json.JSONObject

Expand All @@ -16,6 +17,56 @@ internal class SourceJsonParser : ModelJsonParser<Source> {
}
}

internal class KlarnaJsonParser : ModelJsonParser<Source.Klarna> {
override fun parse(json: JSONObject): Source.Klarna {
return Source.Klarna(
firstName = optString(json, FIELD_FIRST_NAME),
lastName = optString(json, FIELD_LAST_NAME),
purchaseCountry = optString(json, FIELD_PURCHASE_COUNTRY),
clientToken = optString(json, FIELD_CLIENT_TOKEN),
payLaterAssetUrlsDescriptive = optString(json, FIELD_PAY_LATER_ASSET_URLS_DESCRIPTIVE),
payLaterAssetUrlsStandard = optString(json, FIELD_PAY_LATER_ASSET_URLS_STANDARD),
payLaterName = optString(json, FIELD_PAY_LATER_NAME),
payLaterRedirectUrl = optString(json, FIELD_PAY_LATER_REDIRECT_URL),
payNowAssetUrlsDescriptive = optString(json, FIELD_PAY_NOW_ASSET_URLS_DESCRIPTIVE),
payNowAssetUrlsStandard = optString(json, FIELD_PAY_NOW_ASSET_URLS_STANDARD),
payNowName = optString(json, FIELD_PAY_NOW_NAME),
payNowRedirectUrl = optString(json, FIELD_PAY_NOW_REDIRECT_URL),
payOverTimeAssetUrlsDescriptive = optString(json, FIELD_PAY_OVER_TIME_ASSET_URLS_DESCRIPTIVE),
payOverTimeAssetUrlsStandard = optString(json, FIELD_PAY_OVER_TIME_ASSET_URLS_STANDARD),
payOverTimeName = optString(json, FIELD_PAY_OVER_TIME_NAME),
payOverTimeRedirectUrl = optString(json, FIELD_PAY_OVER_TIME_REDIRECT_URL),
paymentMethodCategories = parseSet(json, FIELD_PAYMENT_METHOD_CATEGORIES),
customPaymentMethods = parseSet(json, FIELD_CUSTOM_PAYMENT_METHODS)
)
}

private fun parseSet(json: JSONObject, key: String): Set<String> {
return optString(json, key)?.split(",")?.toSet().orEmpty()
}

private companion object {
private const val FIELD_FIRST_NAME = "first_name"
private const val FIELD_LAST_NAME = "last_name"
private const val FIELD_PURCHASE_COUNTRY = "purchase_country"
private const val FIELD_CLIENT_TOKEN = "client_token"
private const val FIELD_PAY_LATER_ASSET_URLS_DESCRIPTIVE = "pay_later_asset_urls_descriptive"
private const val FIELD_PAY_LATER_ASSET_URLS_STANDARD = "pay_later_asset_urls_standard"
private const val FIELD_PAY_LATER_NAME = "pay_later_name"
private const val FIELD_PAY_LATER_REDIRECT_URL = "pay_later_redirect_url"
private const val FIELD_PAY_NOW_ASSET_URLS_DESCRIPTIVE = "pay_now_asset_urls_descriptive"
private const val FIELD_PAY_NOW_ASSET_URLS_STANDARD = "pay_now_asset_urls_standard"
private const val FIELD_PAY_NOW_NAME = "pay_now_name"
private const val FIELD_PAY_NOW_REDIRECT_URL = "pay_now_redirect_url"
private const val FIELD_PAY_OVER_TIME_ASSET_URLS_DESCRIPTIVE = "pay_over_time_asset_urls_descriptive"
private const val FIELD_PAY_OVER_TIME_ASSET_URLS_STANDARD = "pay_over_time_asset_urls_standard"
private const val FIELD_PAY_OVER_TIME_NAME = "pay_over_time_name"
private const val FIELD_PAY_OVER_TIME_REDIRECT_URL = "pay_over_time_redirect_url"
private const val FIELD_PAYMENT_METHOD_CATEGORIES = "payment_method_categories"
private const val FIELD_CUSTOM_PAYMENT_METHODS = "custom_payment_methods"
}
}

private companion object {
private const val VALUE_SOURCE = "source"
private const val VALUE_CARD = "card"
Expand Down Expand Up @@ -43,18 +94,19 @@ internal class SourceJsonParser : ModelJsonParser<Source> {
private const val FIELD_TYPE: String = "type"
private const val FIELD_USAGE: String = "usage"
private const val FIELD_WECHAT: String = "wechat"
private const val FIELD_KLARNA: String = "klarna"

private fun fromCardJson(jsonObject: JSONObject): Source {
return Source(
StripeJsonUtils.optString(jsonObject, FIELD_ID),
optString(jsonObject, FIELD_ID),
sourceTypeModel = SourceCardDataJsonParser().parse(jsonObject),
type = Source.SourceType.CARD,
typeRaw = Source.SourceType.CARD
)
}

private fun fromSourceJson(jsonObject: JSONObject): Source {
@Source.SourceType val typeRaw = StripeJsonUtils.optString(jsonObject, FIELD_TYPE)
@Source.SourceType val typeRaw = optString(jsonObject, FIELD_TYPE)
?: Source.SourceType.UNKNOWN
@Source.SourceType val type = asSourceType(typeRaw)

Expand All @@ -71,16 +123,16 @@ internal class SourceJsonParser : ModelJsonParser<Source> {
}

return Source(
id = StripeJsonUtils.optString(jsonObject, FIELD_ID),
id = optString(jsonObject, FIELD_ID),
amount = StripeJsonUtils.optLong(jsonObject, FIELD_AMOUNT),
clientSecret = StripeJsonUtils.optString(jsonObject, FIELD_CLIENT_SECRET),
clientSecret = optString(jsonObject, FIELD_CLIENT_SECRET),
codeVerification = optStripeJsonModel(
jsonObject,
FIELD_CODE_VERIFICATION
),
created = StripeJsonUtils.optLong(jsonObject, FIELD_CREATED),
currency = StripeJsonUtils.optString(jsonObject, FIELD_CURRENCY),
flow = asSourceFlow(StripeJsonUtils.optString(jsonObject, FIELD_FLOW)),
currency = optString(jsonObject, FIELD_CURRENCY),
flow = asSourceFlow(optString(jsonObject, FIELD_FLOW)),
isLiveMode = jsonObject.optBoolean(FIELD_LIVEMODE),
metaData = StripeJsonUtils.jsonObjectToStringMap(
jsonObject.optJSONObject(FIELD_METADATA)
Expand All @@ -91,19 +143,26 @@ internal class SourceJsonParser : ModelJsonParser<Source> {
sourceOrder = jsonObject.optJSONObject(FIELD_SOURCE_ORDER)?.let {
SourceOrderJsonParser().parse(it)
},
statementDescriptor = StripeJsonUtils.optString(jsonObject, FIELD_STATEMENT_DESCRIPTOR),
status = asSourceStatus(StripeJsonUtils.optString(jsonObject, FIELD_STATUS)),
statementDescriptor = optString(jsonObject, FIELD_STATEMENT_DESCRIPTOR),
status = asSourceStatus(optString(jsonObject, FIELD_STATUS)),
sourceTypeData = sourceTypeData,
sourceTypeModel = sourceTypeModel,
type = type,
typeRaw = typeRaw,
usage = asUsage(StripeJsonUtils.optString(jsonObject, FIELD_USAGE)),
weChatParam = if (Source.SourceType.WECHAT == type) {
usage = asUsage(optString(jsonObject, FIELD_USAGE)),
_weChat = if (Source.SourceType.WECHAT == type) {
WeChatJsonParser().parse(
jsonObject.optJSONObject(FIELD_WECHAT) ?: JSONObject()
)
} else {
null
},
_klarna = if (Source.SourceType.KLARNA == type) {
KlarnaJsonParser().parse(
jsonObject.optJSONObject(FIELD_KLARNA) ?: JSONObject()
)
} else {
null
}
)
}
Expand Down Expand Up @@ -184,6 +243,7 @@ internal class SourceJsonParser : ModelJsonParser<Source> {
Source.SourceType.MULTIBANCO -> Source.SourceType.MULTIBANCO
Source.SourceType.WECHAT -> Source.SourceType.WECHAT
Source.SourceType.UNKNOWN -> Source.SourceType.UNKNOWN
Source.SourceType.KLARNA -> Source.SourceType.KLARNA
else -> Source.SourceType.UNKNOWN
}
}
Expand Down
35 changes: 35 additions & 0 deletions stripe/src/test/java/com/stripe/android/model/SourceFixtures.kt
Original file line number Diff line number Diff line change
Expand Up @@ -471,4 +471,39 @@ internal object SourceFixtures {
}
""".trimIndent()
)

internal val KLARNA = requireNotNull(PARSER.parse(JSONObject(
"""
{
"id": "src_1FfB6GKmrohBAXC",
"object": "source",
"amount": 1000,
"created": 1573848540,
"currency": "eur",
"flow": "redirect",
"livemode": false,
"metadata": {},
"source_order": $SOURCE_ORDER_JSON,
"statement_descriptor": "WIDGET FACTORY",
"status": "pending",
"type": "klarna",
"usage": "single_use",
"klarna": {
"first_name": "Arthur",
"last_name": "Dent",
"purchase_country": "UK",
"client_token": "CLIENT_TOKEN",
"pay_later_asset_urls_descriptive": "https:\/\/x.klarnacdn.net\/payment-method\/assets\/badges\/generic\/klarna.svg",
"pay_later_asset_urls_standard": "https:\/\/x.klarnacdn.net\/payment-method\/assets\/badges\/generic\/klarna.svg",
"pay_later_name": "Pay later in 14 days",
"pay_later_redirect_url": "https:\/\/payment-eu.playground.klarna.com\/8b45xe2",
"pay_over_time_asset_urls_descriptive": "https:\/\/x.klarnacdn.net\/payment-method\/assets\/badges\/generic\/klarna.svg",
"pay_over_time_asset_urls_standard": "https:\/\/x.klarnacdn.net\/payment-method\/assets\/badges\/generic\/klarna.svg",
"pay_over_time_name": "3 interest-free instalments",
"pay_over_time_redirect_url": "https:\/\/payment-eu.playground.klarna.com\/8DA6imn",
"payment_method_categories": "pay_later,pay_over_time"
}
}
""".trimIndent()
)))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.stripe.android.model.parsers

import com.google.common.truth.Truth.assertThat
import com.stripe.android.model.Source
import com.stripe.android.model.SourceFixtures
import org.junit.Test

class SourceJsonParserTest {

@Test
fun parse_shouldReturnExpectedObject() {
assertThat(SourceFixtures.KLARNA.klarna)
.isEqualTo(
Source.Klarna(
firstName = "Arthur",
lastName = "Dent",
purchaseCountry = "UK",
clientToken = "CLIENT_TOKEN",
payLaterAssetUrlsDescriptive = "https://x.klarnacdn.net/payment-method/assets/badges/generic/klarna.svg",
payLaterAssetUrlsStandard = "https://x.klarnacdn.net/payment-method/assets/badges/generic/klarna.svg",
payLaterName = "Pay later in 14 days",
payLaterRedirectUrl = "https://payment-eu.playground.klarna.com/8b45xe2",
payNowAssetUrlsDescriptive = null,
payNowAssetUrlsStandard = null,
payNowName = null,
payNowRedirectUrl = null,
payOverTimeAssetUrlsDescriptive = "https://x.klarnacdn.net/payment-method/assets/badges/generic/klarna.svg",
payOverTimeAssetUrlsStandard = "https://x.klarnacdn.net/payment-method/assets/badges/generic/klarna.svg",
payOverTimeName = "3 interest-free instalments",
payOverTimeRedirectUrl = "https://payment-eu.playground.klarna.com/8DA6imn",
paymentMethodCategories = setOf("pay_later", "pay_over_time"),
customPaymentMethods = emptySet()
)
)
}
}