diff --git a/CHANGELOG.md b/CHANGELOG.md index 37aef10..fcaf22c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +# 0.1.17 (2024.12.19) +## Added +### Payment SDK 다통화승인(외화결제) 지원 + +# 0.1.16 (2024.07.03) +## Fixed +### 결제 취소 에러 문구 한글로 변경 + +# 0.1.15 (2024.03.06) +## Fixed +### 삼성카드 일반결제 백신 앱 (vguard) 이슈 대응 + +# 0.1.14 (2024.01.03) +## Added +### requestPayment의 PaymentInfo에 useInternationalCardOnly 파라미터 추가 + # 0.1.13 (2023.12.13) ## Fixed ### 카드사 결제 페이지에서 취소 시 에러 화면으로 이동하는 이슈 수정 diff --git a/app/src/main/java/com/tosspayments/paymentsdk/sample/activity/CardPaymentActivity.kt b/app/src/main/java/com/tosspayments/paymentsdk/sample/activity/CardPaymentActivity.kt index 44f3927..a03fda2 100644 --- a/app/src/main/java/com/tosspayments/paymentsdk/sample/activity/CardPaymentActivity.kt +++ b/app/src/main/java/com/tosspayments/paymentsdk/sample/activity/CardPaymentActivity.kt @@ -3,6 +3,7 @@ package com.tosspayments.paymentsdk.sample.activity import androidx.activity.viewModels import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +import com.tosspayments.paymentsdk.model.paymentinfo.Currency import com.tosspayments.paymentsdk.sample.viewmodel.CardPaymentViewModel import com.tosspayments.paymentsdk.model.paymentinfo.TossCardPaymentCompany import com.tosspayments.paymentsdk.model.paymentinfo.TossCardPaymentFlow @@ -25,6 +26,7 @@ class CardPaymentActivity : PaymentActivity() { FlowMode() EasyPay() DiscountCode() + Currency() } @Composable @@ -188,4 +190,15 @@ class CardPaymentActivity : PaymentActivity() { } } } + + @Composable + private fun Currency() { + ItemSelectDialog("통화", + buttonText = viewModel.currency.collectAsState().value?.name ?: "통화 선택", + items = Currency.values().map { Pair(it.name, it) }) { + it?.let { + viewModel.setCurrency(it) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tosspayments/paymentsdk/sample/viewmodel/CardPaymentViewModel.kt b/app/src/main/java/com/tosspayments/paymentsdk/sample/viewmodel/CardPaymentViewModel.kt index 2713f18..567fb6a 100644 --- a/app/src/main/java/com/tosspayments/paymentsdk/sample/viewmodel/CardPaymentViewModel.kt +++ b/app/src/main/java/com/tosspayments/paymentsdk/sample/viewmodel/CardPaymentViewModel.kt @@ -3,6 +3,7 @@ package com.tosspayments.paymentsdk.sample.viewmodel import android.app.Activity import android.content.Intent import androidx.activity.result.ActivityResultLauncher +import com.tosspayments.paymentsdk.model.paymentinfo.Currency import com.tosspayments.paymentsdk.model.paymentinfo.TossCardPaymentCompany import com.tosspayments.paymentsdk.model.paymentinfo.TossCardPaymentFlow import com.tosspayments.paymentsdk.model.paymentinfo.TossCardPaymentInfo @@ -30,6 +31,7 @@ class CardPaymentViewModel : BasePaymentViewModel() { this.flowMode = _flowMode.value this.easyPay = _easyPay.value this.discountCode = _discountCode.value + this.currency = _currency.value } private val _cardCompany = MutableStateFlow(null) @@ -59,6 +61,9 @@ class CardPaymentViewModel : BasePaymentViewModel() { private val _easyPay = MutableStateFlow(null) val easyPay = _easyPay.asStateFlow() + private val _currency = MutableStateFlow(null) + val currency = _currency.asStateFlow() + fun setCardCompany(cardCompany: TossCardPaymentCompany?) { _cardCompany.value = cardCompany } @@ -95,6 +100,10 @@ class CardPaymentViewModel : BasePaymentViewModel() { _discountCode.value = discountCode } + fun setCurrency(currency: Currency) { + _currency.value = currency + } + override fun requestPayment( activity: Activity, resultLauncher: ActivityResultLauncher diff --git a/gradle.properties b/gradle.properties index 8efd77f..1d82482 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,4 +22,4 @@ kotlin.code.style=official # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -versionName=0.1.13 \ No newline at end of file +versionName=0.1.17 \ No newline at end of file diff --git a/paymentsdk/src/dev/assets/tosspayment.html b/paymentsdk/src/dev/assets/tosspayment.html new file mode 100644 index 0000000..7facf6e --- /dev/null +++ b/paymentsdk/src/dev/assets/tosspayment.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/paymentsdk/src/main/assets/tosspayment.html b/paymentsdk/src/main/assets/tosspayment.html index 4e6e4c5..1962a4e 100644 --- a/paymentsdk/src/main/assets/tosspayment.html +++ b/paymentsdk/src/main/assets/tosspayment.html @@ -6,7 +6,7 @@ - + diff --git a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/activity/TossPaymentActivity.kt b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/activity/TossPaymentActivity.kt index e74d1f4..896a3f3 100644 --- a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/activity/TossPaymentActivity.kt +++ b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/activity/TossPaymentActivity.kt @@ -103,7 +103,7 @@ internal class TossPaymentActivity : AppCompatActivity() { } } val paymentDom = intent?.getStringExtra(TossPayments.EXTRA_PAYMENT_DOM) - val paymentCanceledMessage = "Payment has been canceled by the customer" + val paymentCanceledMessage = "사용자에 의해 결제가 취소되었습니다." val domain = intent?.getStringExtra(Constants.EXTRA_KEY_DOMAIN) val errorMessage = when { diff --git a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/model/paymentinfo/Currency.kt b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/model/paymentinfo/Currency.kt new file mode 100644 index 0000000..4cd27a1 --- /dev/null +++ b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/model/paymentinfo/Currency.kt @@ -0,0 +1,5 @@ +package com.tosspayments.paymentsdk.model.paymentinfo + +enum class Currency { + KRW, USD, JPY +} \ No newline at end of file diff --git a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/model/paymentinfo/TossCardPaymentInfo.kt b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/model/paymentinfo/TossCardPaymentInfo.kt index 017bd0f..5eb4b4e 100644 --- a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/model/paymentinfo/TossCardPaymentInfo.kt +++ b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/model/paymentinfo/TossCardPaymentInfo.kt @@ -18,6 +18,7 @@ data class TossCardPaymentInfo( var flowMode: TossCardPaymentFlow = TossCardPaymentFlow.DEFAULT var easyPay: TossEasyPayCompany? = null var discountCode: String? = null + var currency: Currency? = null override val paymentPayload: JSONObject.(JSONObject) -> JSONObject get() = { @@ -56,6 +57,8 @@ data class TossCardPaymentInfo( discountCode?.let { put("discountCode", it) } } + currency?.let { put("currency", it.name) } + put("flowMode", flowMode) } } \ No newline at end of file diff --git a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/view/PaymentMethod.kt b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/view/PaymentMethod.kt index b608340..bcb8b06 100644 --- a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/view/PaymentMethod.kt +++ b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/view/PaymentMethod.kt @@ -104,10 +104,11 @@ class PaymentMethod(context: Context, attrs: AttributeSet? = null) : ) } - data class PaymentInfo( - val orderId: String, + class PaymentInfo private constructor( + builder: Builder + ) : TossPaymentInfo(builder.orderId, builder.orderName, 0) { + val orderId: String val orderName: String - ) : TossPaymentInfo(orderId, orderName, 0) { var taxExemptionAmount: Number = 0 var useEscrow: Boolean? = null var escrowProducts: List? = null @@ -116,6 +117,36 @@ class PaymentMethod(context: Context, attrs: AttributeSet? = null) : var mobileCarrier: List? = null var useInternationalCardOnly: Boolean? = null + @Deprecated( + "해당 방식은 삭제할 예정입니다. Builder 사용해주세요.", + ReplaceWith("PaymentMethod.PaymentInfo.Builder()") + ) + constructor( + orderId: String, + orderName: String + ) : this( + Builder() + .setOrderId(orderId) + .setOrderName(orderName) + ) + + init { + orderId = builder.orderId + orderName = builder.orderName + taxExemptionAmount = builder.taxExemptionAmount + useEscrow = builder.useEscrow + escrowProducts = builder.escrowProducts + customerMobilePhone = builder.customerMobilePhone + showCustomerMobilePhone = builder.showCustomerMobilePhone + mobileCarrier = builder.mobileCarrier + + customerName = builder.customerName + customerEmail = builder.customerEmail + taxFreeAmount = builder.taxFreeAmount + cultureExpense = builder.cultureExpense + useInternationalCardOnly = builder.useInternationalCardOnly + } + override val paymentPayload: JSONObject.(JSONObject) -> JSONObject get() = { remove("amount") @@ -153,5 +184,198 @@ class PaymentMethod(context: Context, attrs: AttributeSet? = null) : this } + + @Suppress("unused", "MemberVisibilityCanBePrivate") + class Builder { + internal var orderId: String = "" + private set + internal var orderName: String = "" + private set + internal var amount: Long = 0 + private set + internal var taxExemptionAmount: Number = 0 + private set + internal var useEscrow: Boolean? = null + private set + internal var escrowProducts: List? = null + private set + internal var customerMobilePhone: String? = null + private set + internal var showCustomerMobilePhone: Boolean = false + private set + internal var mobileCarrier: List? = null + private set + + internal var customerName: String? = null + private set + internal var customerEmail: String? = null + private set + internal var taxFreeAmount: Number? = null + private set + internal var cultureExpense: Boolean = false + private set + internal var useInternationalCardOnly: Boolean? = null + private set + + /** + * Setter + * @param id 주문 번호 + */ + fun setOrderId(id: Int): Builder { + return setOrderId("$id") + } + + /** + * Setter + * @param id 주문 번호 + */ + fun setOrderId(id: Long): Builder { + return setOrderId("$id") + } + + /** + * Setter + * @param id 주문 번호 + */ + fun setOrderId(id: String): Builder { + this.orderId = id + return this + } + + /** + * Setter + * @param name 주문명 + */ + fun setOrderName(name: String): Builder { + this.orderName = name + return this + } + + /** + * Setter + * @param amount 주문 금액 + */ + fun setAmount(amount: Int): Builder { + return setAmount(amount.toLong()) + } + + /** + * Setter + * @param amount 주문 금액 + */ + fun setAmount(amount: Long): Builder { + this.amount = amount + return this + } + + /** + * Setter + * @param amount 세금 면제 금액 + */ + fun setTaxExemptionAmount(amount: Number): Builder { + this.taxExemptionAmount = amount + return this + } + + /** + * Setter + * @param useEscrow 에스크로 처리 유무 + */ + fun setUseEscrow(useEscrow: Boolean?): Builder { + this.useEscrow = useEscrow + return this + } + + /** + * Setter + * @param list 에스크로 상품 + */ + fun setEscroProducts(list: List?): Builder { + if (list == null) { + this.escrowProducts = null + return this + } + this.escrowProducts = list.map { it.copy() } + return this + } + + /** + * Setter + * @param phone 구매자 휴대폰 번호 + */ + fun setCustomerMobilePhone(phone: String?): Builder { + this.customerMobilePhone = phone + return this + } + + /** + * Setter + * @param isShowMobilePhone 휴대폰 번호 노출 유무 + */ + fun setShowCustomerMobilePhone(isShowMobilePhone: Boolean): Builder { + this.showCustomerMobilePhone = isShowMobilePhone + return this + } + + /** + * Setter + * @param list 휴대폰 결제창에 보여줄 통신사 + */ + fun setMobileCarrier(list: List?): Builder { + this.mobileCarrier = list + return this + } + + /** + * Setter + * @param name 구매자 명 + */ + fun setCustomerName(name: String?): Builder { + this.customerName = name + return this + } + + /** + * Setter + * @param email 구매자 메일 + */ + fun setCustomerEmail(email: String?): Builder { + this.customerEmail = email + return this + } + + /** + * Setter + * @param amount 면세 금액 + */ + fun setTaxFreeAmount(amount: Number?): Builder { + this.taxFreeAmount = amount + return this + } + + fun setCultureExpense(isCultureExpense: Boolean): Builder { + this.cultureExpense = isCultureExpense + return this + } + + fun setUseCardOnly(useCardOnly: Boolean): Builder { + this.useInternationalCardOnly = useCardOnly + return this + } + + /** + * 변수 유효성 검사 하는 함수 + */ + private fun validationCheck() { + if (orderId.isEmpty() || orderName.isEmpty()) { + throw IllegalArgumentException("주문번호와 주문명은 필수값입니다. orderId=${orderId} orderName=${orderName}") + } + } + + fun build(): PaymentInfo { + validationCheck() + return PaymentInfo(this) + } + } } } \ No newline at end of file diff --git a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/view/TossPaymentView.kt b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/view/TossPaymentView.kt index 588ee1a..9c21565 100644 --- a/paymentsdk/src/main/java/com/tosspayments/paymentsdk/view/TossPaymentView.kt +++ b/paymentsdk/src/main/java/com/tosspayments/paymentsdk/view/TossPaymentView.kt @@ -118,6 +118,13 @@ class TossPaymentView(context: Context, attrs: AttributeSet? = null) : } } } else { + /* + * 삼성카드 백신 앱 onestore 링크 대응 + */ + if (requestedUrl.startsWith("https://m.onestore") || requestedUrl.startsWith("https://onesto.re")) { + context.startActivity(Intent(Intent.ACTION_VIEW, uri)) + return true + } return false } } ?: false diff --git a/paymentsdk/src/staging/assets/tosspayment.html b/paymentsdk/src/staging/assets/tosspayment.html new file mode 100644 index 0000000..534773a --- /dev/null +++ b/paymentsdk/src/staging/assets/tosspayment.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file