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

[FEAT/#78] Portone 결제 모듈 세팅 #79

Merged
merged 7 commits into from
Aug 19, 2024
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
6 changes: 6 additions & 0 deletions presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ android {
"MERCHANT_UID",
gradleLocalProperties(rootDir).getProperty("merchant.uid"),
)

buildConfigField(
"String",
"PAYMENT_UID",
gradleLocalProperties(rootDir).getProperty("payment.uid"),
)
}

compileOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class PhoneActivity : BaseActivity<ActivityPhoneBinding>(R.layout.activity_phone
}

private fun startIamportCertification() {
Timber.tag("okhttp").d("START IAMPORT CERTIFICATION")
Iamport.certification(
userCode = IAMPORT_CODE,
iamPortCertification =
Expand All @@ -75,6 +76,7 @@ class PhoneActivity : BaseActivity<ActivityPhoneBinding>(R.layout.activity_phone
}
} else {
Timber.tag("okhttp").d("IAMPORT CERTIFICATION ERROR : $response")
toast(stringOf(R.string.error_msg))
setLoadingScreen(false)
}
}
Expand Down Expand Up @@ -134,6 +136,7 @@ class PhoneActivity : BaseActivity<ActivityPhoneBinding>(R.layout.activity_phone

override fun onDestroy() {
super.onDestroy()

Iamport.close()
termBottomSheet = null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ import co.orange.core.extension.toast
import co.orange.core.state.UiState
import co.orange.domain.entity.response.AddressInfoModel
import co.orange.domain.entity.response.BuyProgressModel
import co.orange.presentation.buy.push.BuyPushActivity
import co.orange.presentation.setting.delivery.DeliveryActivity
import coil.load
import com.iamport.sdk.domain.core.Iamport
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kr.genti.presentation.BuildConfig.IAMPORT_CODE
import kr.genti.presentation.R
import kr.genti.presentation.databinding.ActivityBuyProgressBinding
import timber.log.Timber

@AndroidEntryPoint
class BuyProgressActivity :
Expand All @@ -35,7 +37,7 @@ class BuyProgressActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding.vm = viewModel
initView()
initExitBtnListener()
initDeliveryChangeBtnListener()
initTermBtnListener()
Expand All @@ -50,6 +52,11 @@ class BuyProgressActivity :
getIntentInfo()
}

private fun initView() {
binding.vm = viewModel
Iamport.init(this)
}

private fun initExitBtnListener() {
binding.btnExit.setOnSingleClickListener { finish() }
}
Expand Down Expand Up @@ -85,19 +92,43 @@ class BuyProgressActivity :
private fun initConfirmBtnListener() {
binding.btnConfirmPurchase.setOnSingleClickListener {
// TODO 구매 요청 서버통신 이후
BuyPushActivity.createIntent(this, viewModel.productId).apply {
startActivity(this)
}
startIamportPurchase()
// BuyPushActivity.createIntent(this, viewModel.productId).apply {
// startActivity(this)
// }
}
}

private fun getIntentInfo() {
with(viewModel) {
if (productId.isEmpty()) productId = intent.getStringExtra(EXTRA_PRODUCT_ID).orEmpty()
if (productId.isEmpty()) {
productId = intent.getStringExtra(EXTRA_PRODUCT_ID).orEmpty()
optionList = intent.getLongArrayExtra(EXTRA_OPTION_LIST)?.toList()
}
getBuyProgressDataFromServer()
}
}

private fun startIamportPurchase() {
val request = viewModel.createIamportRequest()
if (request == null) {
toast(stringOf(R.string.error_msg))
return
}
Timber.tag("okhttp").d("IAMPORT PURCHASE REQUEST : $request")
Iamport.payment(
userCode = IAMPORT_CODE,
iamPortRequest = request,
) { response ->
Timber.tag("okhttp").d("IAMPORT PURCHASE RESPONSE : $response")
if (response != null && response.success == true) {
// TODO
} else {
toast(stringOf(R.string.error_msg))
}
}
}

private fun observeGetBuyProgressDataState() {
viewModel.getBuyProgressDataState.flowWithLifecycle(lifecycle).distinctUntilChanged()
.onEach { state ->
Expand Down Expand Up @@ -146,16 +177,25 @@ class BuyProgressActivity :
}
}

override fun onDestroy() {
super.onDestroy()

Iamport.close()
}

companion object {
private const val EXTRA_PRODUCT_ID = "EXTRA_PRODUCT_ID"
private const val EXTRA_OPTION_LIST = "EXTRA_OPTION_LIST"

@JvmStatic
fun createIntent(
context: Context,
productId: String,
optionList: Array<Long>? = null,
): Intent =
Intent(context, BuyProgressActivity::class.java).apply {
putExtra(EXTRA_PRODUCT_ID, productId)
putExtra(EXTRA_OPTION_LIST, optionList)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import androidx.lifecycle.viewModelScope
import co.orange.core.state.UiState
import co.orange.domain.entity.response.BuyProgressModel
import co.orange.domain.repository.BuyRepository
import com.iamport.sdk.data.sdk.IamPortRequest
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kr.genti.presentation.BuildConfig.PAYMENT_UID
import timber.log.Timber
import javax.inject.Inject

@HiltViewModel
Expand All @@ -19,12 +22,15 @@ class BuyProgressViewModel
private val buyRepository: BuyRepository,
) : ViewModel() {
var productId: String = ""
var optionList: List<Long>? = null
var buyProgressData: BuyProgressModel? = null

var payMethodId = MutableLiveData<Int>(-1)
var payMethod = ""

var isTermAllSelected = MutableLiveData<Boolean>(false)
var isTermServiceSelected = MutableLiveData<Boolean>(false)
var isTermPurchaseSelected = MutableLiveData<Boolean>(false)
var isAddressSelected = false
var isMethodSelected = true
var isCompleted = MutableLiveData<Boolean>(false)

private val _getBuyProgressDataState =
Expand All @@ -48,11 +54,26 @@ class BuyProgressViewModel
checkIsCompleted()
}

fun setPayMethod(methodId: Int) {
payMethodId.value = methodId
payMethod =
when (methodId) {
0 -> "card"
1 -> "naverpay_card"
2 -> "kakao"
3 -> "samsungpay"
4 -> "trans"
5 -> "phone"
else -> return
}
checkIsCompleted()
}

private fun checkIsCompleted() {
isTermAllSelected.value =
(isTermServiceSelected.value == true && isTermPurchaseSelected.value == true)
isCompleted.value =
(isTermServiceSelected.value == true && isTermPurchaseSelected.value == true && isAddressSelected && isMethodSelected)
(isTermAllSelected.value == true && !buyProgressData?.addressInfo?.address.isNullOrBlank() && payMethod.isNotBlank())
}

fun getBuyProgressDataFromServer() {
Expand All @@ -61,13 +82,35 @@ class BuyProgressViewModel
// TODO 추후 productId 활용
buyRepository.getBuyProgressData("0110055338")
.onSuccess {
isAddressSelected = !it.addressInfo.address.isNullOrEmpty()
checkIsCompleted()
buyProgressData = it
_getBuyProgressDataState.value = UiState.Success(it)
}
.onFailure {
_getBuyProgressDataState.value = UiState.Failure(it.message.toString())
}
}
}

fun createIamportRequest(): IamPortRequest? {
return if (buyProgressData?.productName.isNullOrBlank() || payMethod.isBlank()) {
Timber.tag("okhttp").d("IAMPORT PURCHASE REQUEST ERROR : $buyProgressData & $payMethod")
null
} else {
IamPortRequest(
pg = NICE_PAYMENTS,
pay_method = payMethod,
// TODO 추후 수정
name = "예시상품",
merchant_uid = "0123456789",
amount = buyProgressData?.totalPrice.toString(),
buyer_name = buyProgressData?.addressInfo?.recipient,
buyer_tel = buyProgressData?.addressInfo?.recipientPhone,
)
}
}

companion object {
private const val NICE_PAYMENTS = "nice_v2.{$PAYMENT_UID}"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class DetailViewModel
var infoUrl: String = ""
var interestCount: Int = 0
var optionList = listOf<ProductOptionModel>()
var selectedOptionList = mutableListOf<Long>()

private val _getProductDetailState =
MutableStateFlow<UiState<ProductDetailModel>>(UiState.Empty)
Expand All @@ -43,6 +44,7 @@ class DetailViewModel
infoUrl = it.infoUrl
interestCount = it.interestCount
optionList = it.optionList
selectedOptionList = MutableList(optionList.size) { -1 }
isLiked = it.isInterested
_getProductDetailState.value = UiState.Success(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import co.orange.domain.entity.response.ProductOptionModel
import kr.genti.presentation.databinding.ItemOptionBinding

class OptionAdapter(
private val itemClick: (Long, Long) -> Unit,
private val itemClick: (Int, Long) -> Unit,
) : ListAdapter<ProductOptionModel, OptionViewHolder>(diffUtil) {
override fun onCreateViewHolder(
parent: ViewGroup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,11 @@ class OptionBottomSheet :

private fun initPurchaseBtnListener() {
binding.btnPurchase.setOnSingleClickListener {
// TODO 버튼 활성화 설정
BuyProgressActivity.createIntent(
requireContext(),
viewModel.productId,
).apply {
startActivity(this)
}
viewModel.selectedOptionList.toTypedArray(),
).apply { startActivity(this) }
}
}

Expand All @@ -80,10 +78,13 @@ class OptionBottomSheet :
}

private fun initItemClickListener(
optionId: Long,
position: Int,
optionDetailId: Long,
) {
// TODO 옵션 저장
if (position < viewModel.selectedOptionList.size) {
viewModel.selectedOptionList[position] = optionDetailId
}
binding.btnPurchase.isEnabled = !viewModel.selectedOptionList.contains(-1)
}

private fun setInterestCount() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import kr.genti.presentation.databinding.ItemOptionBinding

class OptionViewHolder(
val binding: ItemOptionBinding,
private val itemClick: (Long, Long) -> Unit,
private val itemClick: (Int, Long) -> Unit,
) : RecyclerView.ViewHolder(binding.root) {
var selectedItemId: Long = -1
var selectedPosition: Int = -1

fun onBind(
item: ProductOptionModel,
position: Int,
) {
selectedItemId = item.optionId
selectedPosition = position
with(binding) {
tvOptionItemTitle.text = item.type
tvOptionItemTitle.setOnClickListener {
Expand All @@ -32,6 +32,6 @@ class OptionViewHolder(
}

private fun initItemClickListener(optionDetailId: Long) {
itemClick(selectedItemId, optionDetailId)
itemClick(selectedPosition, optionDetailId)
}
}
Loading
Loading