修复不能支付的bug

This commit is contained in:
2026-06-18 09:57:49 +08:00
parent c82066ca38
commit cf9d9e8224
16 changed files with 113 additions and 43 deletions

View File

@@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-06-15T09:38:09.014028800Z"> <DropdownSelection timestamp="2026-06-16T02:26:23.004237800Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=GBG5T19625003301" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=3A251FDJH000CE" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

View File

@@ -29,8 +29,8 @@ android {
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 35 targetSdkVersion 35
versionCode 2211 versionCode 2211
// versionName "2.2.11" versionName "2.2.11"
versionName "2.2.11-Beta1" // versionName "2.2.11-Beta1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -48,12 +48,11 @@ class HistoryFenceAdapter(
timeStamp, Utils.DATE_FORMAT_PATTERN_CN2 timeStamp, Utils.DATE_FORMAT_PATTERN_CN2
) )
) )
val now = System.currentTimeMillis()
formatDateStr = if (DateUtils.isToday(cTimeStamp)) { formatDateStr = if (DateUtils.isToday(cTimeStamp)) {
mContext.getString(R.string.txt_today) + " " + Utils.formatTime( mContext.getString(R.string.txt_today) + " " + Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN14 timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
) )
} else if (now - cTimeStamp < (48 * 60 * 60 * 1000)) { } else if (Utils.isYesterday(cTimeStamp)) {
mContext.getString(R.string.txt_yesterday) + " " + Utils.formatTime( mContext.getString(R.string.txt_yesterday) + " " + Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN14 timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
) )

View File

@@ -64,12 +64,11 @@ class NotificationV2Adapter(
timeStamp, Utils.DATE_FORMAT_PATTERN_CN2 timeStamp, Utils.DATE_FORMAT_PATTERN_CN2
) )
) )
val now = System.currentTimeMillis()
formatDateStr = if (DateUtils.isToday(cTimeStamp)) { formatDateStr = if (DateUtils.isToday(cTimeStamp)) {
mContext.getString(R.string.txt_today) + " " + Utils.formatTime( mContext.getString(R.string.txt_today) + " " + Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN14 timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
) )
} else if (now - cTimeStamp < (48 * 60 * 60 * 1000)) { } else if (Utils.isYesterday(cTimeStamp)) {
mContext.getString(R.string.txt_yesterday) + " " + Utils.formatTime( mContext.getString(R.string.txt_yesterday) + " " + Utils.formatTime(
timeStamp, Utils.DATE_FORMAT_PATTERN_EN14 timeStamp, Utils.DATE_FORMAT_PATTERN_EN14
) )

View File

@@ -24,7 +24,10 @@ data class CreditCardBean(
@ColumnInfo var cvv: String,//信用卡验证值Card Verification Value @ColumnInfo var cvv: String,//信用卡验证值Card Verification Value
@ColumnInfo var countryCode: String, @ColumnInfo var countryCode: String,
@ColumnInfo var isPrimary: Boolean, @ColumnInfo var isPrimary: Boolean,
@Ignore var checked: Boolean = false @Ignore var checked: Boolean = false,
@Ignore var expMonth: Int,
@Ignore var expYear: Int,
@Ignore var lastFourNumber: String,
) : Parcelable { ) : Parcelable {
constructor() : this("", "", "", "", "", "", "USA", false, false) constructor() : this("", "", "", "", "", "", "USA", false, false, 0, 0, "")
} }

View File

@@ -1095,7 +1095,8 @@ interface INetworkService {
@Field("parms") param: String, @Field("parms") param: String,
@Field("userId") userId: String, @Field("userId") userId: String,
@Field("userName") userName: String, @Field("userName") userName: String,
@Field("email") email: String @Field("email") email: String,
@Field("paymentMethodID") paymentMethodID: String
): BaseResponse<StripeSubscriptionPriceBean> ): BaseResponse<StripeSubscriptionPriceBean>
/** /**

View File

@@ -1,6 +1,8 @@
package com.abbidot.tracker.retrofit2 package com.abbidot.tracker.retrofit2
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.network.base.BaseNetworkApi import com.abbidot.baselibrary.network.base.BaseNetworkApi
import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.bean.FencesBean import com.abbidot.tracker.bean.FencesBean
import com.abbidot.tracker.bean.PayResultBean import com.abbidot.tracker.bean.PayResultBean
import com.abbidot.tracker.bean.SetMealBean import com.abbidot.tracker.bean.SetMealBean
@@ -1008,7 +1010,8 @@ object NetworkApi : BaseNetworkApi<INetworkService>(INetworkService.BASE_URL) {
suspend fun createCustomer( suspend fun createCustomer(
param: String, userId: String, userName: String, email: String param: String, userId: String, userName: String, email: String
) = getResult { ) = getResult {
service.createCustomer(param, userId, userName, email) val paymentMethodID = MMKVUtil.getString(MMKVKey.PaymentMethodID)
service.createCustomer(param, userId, userName, email, paymentMethodID)
} }
/** /**

View File

@@ -5,7 +5,6 @@ import androidx.fragment.app.Fragment
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.abbidot.baselibrary.constant.EventName import com.abbidot.baselibrary.constant.EventName
import com.abbidot.baselibrary.eventbus.XEventBus import com.abbidot.baselibrary.eventbus.XEventBus
import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.tracker.R import com.abbidot.tracker.R
import com.abbidot.tracker.adapter.ViewPagerAdapter import com.abbidot.tracker.adapter.ViewPagerAdapter
import com.abbidot.tracker.base.BaseActivity import com.abbidot.tracker.base.BaseActivity
@@ -18,14 +17,9 @@ import com.abbidot.tracker.databinding.ActivityPaymentMethodBinding
import com.abbidot.tracker.deprecated.ui.fragment.vm.LoginCNViewModel import com.abbidot.tracker.deprecated.ui.fragment.vm.LoginCNViewModel
import com.abbidot.tracker.ui.fragment.subscribe.CreditCardPaymentFragment import com.abbidot.tracker.ui.fragment.subscribe.CreditCardPaymentFragment
import com.abbidot.tracker.ui.fragment.subscribe.PaypalPaymentFragment import com.abbidot.tracker.ui.fragment.subscribe.PaypalPaymentFragment
import com.abbidot.tracker.util.ThirdPartyUtil
import com.abbidot.tracker.util.Util import com.abbidot.tracker.util.Util
import com.abbidot.tracker.util.ViewUtil import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.vm.SubscriptionPayViewModel import com.abbidot.tracker.vm.SubscriptionPayViewModel
import com.stripe.android.ApiResultCallback
import com.stripe.android.Stripe
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.PaymentMethodCreateParams
class PaymentMethodActivity : class PaymentMethodActivity :
BaseActivity<ActivityPaymentMethodBinding>(ActivityPaymentMethodBinding::inflate) { BaseActivity<ActivityPaymentMethodBinding>(ActivityPaymentMethodBinding::inflate) {
@@ -53,24 +47,24 @@ class PaymentMethodActivity :
setLeftBackImage(R.drawable.icon_white_back_svg) setLeftBackImage(R.drawable.icon_white_back_svg)
// 用 PaymentMethodCreateParams 封装银行卡不再直接new Card // 用 PaymentMethodCreateParams 封装银行卡不再直接new Card
val cardParams = PaymentMethodCreateParams.Card.Builder() // val cardParams = PaymentMethodCreateParams.Card.Builder()
.setNumber("4242424242424242") // .setNumber("4242424242424242")
.setExpiryMonth(12) // .setExpiryMonth(12)
.setExpiryYear(2028) // .setExpiryYear(2028)
.setCvc("123") // .setCvc("123")
.build() // .build()
val paymentMethodParams = PaymentMethodCreateParams.create(cardParams) // val paymentMethodParams = PaymentMethodCreateParams.create(cardParams)
val stripeKey = ThirdPartyUtil.instance.getStripeKey(mContext) // val stripeKey = ThirdPartyUtil.instance.getStripeKey(mContext)
Stripe(mContext, stripeKey).createPaymentMethod( // Stripe(mContext, stripeKey).createPaymentMethod(
paymentMethodParams, callback = object : ApiResultCallback<PaymentMethod> { // paymentMethodParams, callback = object : ApiResultCallback<PaymentMethod> {
override fun onError(e: Exception) { // override fun onError(e: Exception) {
LogUtil.e("ApiResultCallback,${e.message}") // LogUtil.e("ApiResultCallback,${e.message}")
} // }
//
override fun onSuccess(result: PaymentMethod) { // override fun onSuccess(result: PaymentMethod) {
LogUtil.e(result.toString()) // LogUtil.e(result.toString())
} // }
}) // })
intent.extras?.apply { intent.extras?.apply {
mOrderBean = Util.getParcelableAdaptive( mOrderBean = Util.getParcelableAdaptive(
@@ -106,6 +100,10 @@ class PaymentMethodActivity :
} }
} }
getUserPaymentMethodID()
}
fun getUserPaymentMethodID(){
mSubscriptionPayViewModel.getUserPaymentMethodID() mSubscriptionPayViewModel.getUserPaymentMethodID()
} }

View File

@@ -490,7 +490,7 @@ class SureSubscriptionPlanActivity :
mViewBinding.apply { mViewBinding.apply {
when (v!!) { when (v!!) {
btnSureSubscribePlan1Continue -> { btnSureSubscribePlan1Continue -> {
if (!AppUtils.isChina()) { if (AppUtils.isChina()) {
if (null == mRechargePayOptionsCn) { if (null == mRechargePayOptionsCn) {
mRechargePayOptionsCn = ViewUtil.instance.showBottomSheet( mRechargePayOptionsCn = ViewUtil.instance.showBottomSheet(
mContext, mContext,

View File

@@ -6,9 +6,12 @@ import android.view.View
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.abbidot.baselibrary.constant.MMKVKey
import com.abbidot.baselibrary.constant.ResultCode import com.abbidot.baselibrary.constant.ResultCode
import com.abbidot.baselibrary.list.BaseRecyclerAdapter import com.abbidot.baselibrary.list.BaseRecyclerAdapter
import com.abbidot.baselibrary.util.AppUtils import com.abbidot.baselibrary.util.AppUtils
import com.abbidot.baselibrary.util.LogUtil
import com.abbidot.baselibrary.util.MMKVUtil
import com.abbidot.tracker.R import com.abbidot.tracker.R
import com.abbidot.tracker.adapter.CreditCardAdapter import com.abbidot.tracker.adapter.CreditCardAdapter
import com.abbidot.tracker.base.BaseFragment import com.abbidot.tracker.base.BaseFragment
@@ -20,8 +23,13 @@ import com.abbidot.tracker.databinding.FragmentCreditCardPaymentBinding
import com.abbidot.tracker.ui.activity.subscribe.AddCreditCardPaymentActivity import com.abbidot.tracker.ui.activity.subscribe.AddCreditCardPaymentActivity
import com.abbidot.tracker.ui.activity.subscribe.PaymentMethodActivity import com.abbidot.tracker.ui.activity.subscribe.PaymentMethodActivity
import com.abbidot.tracker.ui.activity.subscribe.PaymentSuccessActivity import com.abbidot.tracker.ui.activity.subscribe.PaymentSuccessActivity
import com.abbidot.tracker.util.ThirdPartyUtil
import com.abbidot.tracker.util.ViewUtil import com.abbidot.tracker.util.ViewUtil
import com.abbidot.tracker.vm.SubscriptionPayViewModel import com.abbidot.tracker.vm.SubscriptionPayViewModel
import com.stripe.android.ApiResultCallback
import com.stripe.android.Stripe
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.PaymentMethodCreateParams
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -208,12 +216,48 @@ class CreditCardPaymentFragment : BaseFragment<FragmentCreditCardPaymentBinding>
} }
} }
// fun showCard(stripeMethodInfo: CreditCardBean){
// stripeMethodInfo.apply {
// expirationDate="$expMonth/$expYear"
// cardNumber=lastFourNumber
// }
// mutableListOf<CreditCardBean>().apply {
//
// }
// mCreditCardAdapter.setData(sortedByList, true)
// }
private fun startCreditCardPayment() { private fun startCreditCardPayment() {
val list = mCreditCardAdapter.getData() val list = mCreditCardAdapter.getData()
for (card in list) { for (card in list) {
if (card.checked) { if (card.checked) {
showNoCancelableLoading(true) showNoCancelableLoading(true)
mSubscriptionPayViewModel.createCustomer(card)
val dates = card.expirationDate.split("/")
// 用 PaymentMethodCreateParams 封装银行卡不再直接new Card
val cardParams = PaymentMethodCreateParams.Card.Builder()
.setNumber(card.cardNumber)
.setExpiryMonth(dates[0].toInt())
.setExpiryYear(dates[1].toInt())
.setCvc(card.cvv)
.build()
val paymentMethodParams = PaymentMethodCreateParams.create(cardParams)
val stripeKey = ThirdPartyUtil.instance.getStripeKey(mContext!!)
Stripe(mContext!!, stripeKey).createPaymentMethod(
paymentMethodParams, callback = object : ApiResultCallback<PaymentMethod> {
override fun onError(e: Exception) {
showToast(R.string.txt_missing_param)
showNoCancelableLoading(false)
LogUtil.e("ApiResultCallback,${e.message}")
}
override fun onSuccess(result: PaymentMethod) {
LogUtil.e(result.toString())
val paymentMethodID = "${result.id}"
MMKVUtil.putString(MMKVKey.PaymentMethodID, paymentMethodID)
mSubscriptionPayViewModel.createCustomer(card)
}
})
break break
} }
} }

View File

@@ -52,9 +52,7 @@ class SubscriptionPayViewModel : ViewModel() {
val rsaKey = RSA.encrypt(cardJso, b) val rsaKey = RSA.encrypt(cardJso, b)
LogUtil.e(cardJso) LogUtil.e(cardJso)
val result = NetworkApi.createCustomer( val result = NetworkApi.createCustomer(rsaKey, userId, userName, email)
rsaKey, userId, userName, email
)
mSubscriptionCustomerLiveData.postValue(result) mSubscriptionCustomerLiveData.postValue(result)
} }
} }

View File

@@ -165,6 +165,7 @@
<androidx.appcompat.widget.AppCompatCheckBox <androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/cb_add_card_set_primary_switch" android:id="@+id/cb_add_card_set_primary_switch"
style="@style/my_checkbox_switch_style" style="@style/my_checkbox_switch_style"
android:visibility="gone"
android:layout_below="@id/ll_add_card_accepted_cards" android:layout_below="@id/ll_add_card_accepted_cards"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_marginTop="@dimen/dp_16" /> android:layout_marginTop="@dimen/dp_16" />
@@ -176,6 +177,7 @@
android:layout_alignBottom="@id/cb_add_card_set_primary_switch" android:layout_alignBottom="@id/cb_add_card_set_primary_switch"
android:text="@string/txt_set_primary_card" android:text="@string/txt_set_primary_card"
android:textSize="@dimen/textSize14" android:textSize="@dimen/textSize14"
android:visibility="gone"
app:typeface="@string/roboto_regular_font" /> app:typeface="@string/roboto_regular_font" />
</RelativeLayout> </RelativeLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@@ -1119,6 +1119,5 @@
<string name="txt_use_valid_phone">请使用有效的手机号码</string> <string name="txt_use_valid_phone">请使用有效的手机号码</string>
<string name="txt_account">账户</string> <string name="txt_account">账户</string>
<string name="title_activity_register_cnactivity">RegisterCNActivity</string>
</resources> </resources>

View File

@@ -38,6 +38,7 @@ import androidx.annotation.StringDef
MMKVKey.MapType, MMKVKey.MapType,
MMKVKey.ShowFence, MMKVKey.ShowFence,
MMKVKey.ShowDashedLine, MMKVKey.ShowDashedLine,
MMKVKey.PaymentMethodID,
MMKVKey.ShowAllPet, MMKVKey.ShowAllPet,
MMKVKey.isCrash, MMKVKey.isCrash,
MMKVKey.AvailableOrder, MMKVKey.AvailableOrder,
@@ -59,6 +60,7 @@ annotation class MMKVKey {
const val Phone = "phone" const val Phone = "phone"
const val ActivityGoal = "activityGoal" const val ActivityGoal = "activityGoal"
const val Location = "location" const val Location = "location"
const val PaymentMethodID = "paymentMethodID"
const val Gender = "gender" const val Gender = "gender"
const val BirthdayDate = "birthdayDate" const val BirthdayDate = "birthdayDate"
const val CountryCode = "countryCode" const val CountryCode = "countryCode"
@@ -84,6 +86,7 @@ annotation class MMKVKey {
//只使用谷歌地图 //只使用谷歌地图
const val OnlyGoogleMap = "onlyGoogleMap" const val OnlyGoogleMap = "onlyGoogleMap"
//是否gps坐标转换火星坐标 //是否gps坐标转换火星坐标
const val isGpsToGCJ02 = "gpsToGCJ02" const val isGpsToGCJ02 = "gpsToGCJ02"
const val MapShowDefaultLat = "mapDefaultLat" const val MapShowDefaultLat = "mapDefaultLat"

View File

@@ -93,7 +93,7 @@ class AppUtils {
* 是否是国内 * 是否是国内
*/ */
fun isChina(type: String = SWITCH_PAGE_TYPE): Boolean { fun isChina(type: String = SWITCH_PAGE_TYPE): Boolean {
// return false return false
if (isDebug()) { if (isDebug()) {
if (type == SWITCH_MAP_TYPE && MMKVUtil.getBoolean(MMKVKey.OnlyGoogleMap, false)) { if (type == SWITCH_MAP_TYPE && MMKVUtil.getBoolean(MMKVKey.OnlyGoogleMap, false)) {
//只启用谷歌地图 //只启用谷歌地图

View File

@@ -78,6 +78,27 @@ class Utils {
return sdf.format(date) return sdf.format(date)
} }
/**
* 判断毫秒时间戳是否是昨天
* @param timeMs 毫秒时间戳
*/
fun isYesterday(timeMs: Long): Boolean {
// 1. 获取今天零点
val todayCal = Calendar.getInstance()
todayCal.set(Calendar.HOUR_OF_DAY, 0)
todayCal.set(Calendar.MINUTE, 0)
todayCal.set(Calendar.SECOND, 0)
todayCal.set(Calendar.MILLISECOND, 0)
val todayZero = todayCal.timeInMillis
// 2. 昨天零点 = 今天零点 - 1天
val yesterdayCal = todayCal.apply { add(Calendar.DAY_OF_YEAR, -1) }
val yesterdayZero = yesterdayCal.timeInMillis
// 时间落在昨天0点 ~ 今天0点之间 = 昨天
return timeMs in yesterdayZero..<todayZero
}
/** /**
* 把字符串转成日期 * 把字符串转成日期
* @param parseFormat 字符串是什么格式的日期就传什么格式 * @param parseFormat 字符串是什么格式的日期就传什么格式