feat(payment): 添加会员折扣功能并重构支付逻辑
- 新增 getMemberDiscount 接口用于查询会员折扣 - 在人脸识别支付中集成会员折扣计算逻辑 - 将支付金额计算从 vipPrice 切换到 specPrice 并应用会员折扣 - 在初始化活动中添加设备配置获取功能 - 使用 ConstraintLayout 重构主餐品列表布局 - 添加 Timber 日志框架替换原有 Log 工具 - 重构 MainScreenPresentation 中的食物价格计算逻辑 - 移除重复的设备配置获取代码,统一在 InitActivity 中处理
This commit is contained in:
@@ -17,9 +17,11 @@ import com.sw.dualscreen.objbox.FoodModule
|
||||
import com.sw.dualscreen.utils.FoodVectorTool
|
||||
import com.sw.dualscreen.utils.L
|
||||
import com.sw.dualscreen.utils.NetworkUtils
|
||||
import com.sw.dualscreen.utils.SpTool
|
||||
import com.sw.dualscreen.viewmodel.BaseViewModel
|
||||
import com.sw.dualscreen.viewmodel.UserViewModel
|
||||
import com.sw.plate.utils.AppUtil
|
||||
import com.sw.plate.utils.ToastUtils
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class InitActivity : BaseActivity<ActivityInitBinding>() {
|
||||
@@ -180,11 +182,32 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
|
||||
loadNetworkErrorDialog()
|
||||
return
|
||||
}
|
||||
getDeviceConfig()
|
||||
getCollectedFoodVector()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDeviceConfig() {
|
||||
userViewModel.getDeviceConfig { deviceConfig ->
|
||||
runOnUiThread {
|
||||
if (deviceConfig == null) {
|
||||
ToastUtils.showToast("获取设备配置数据失败")
|
||||
return@runOnUiThread
|
||||
}
|
||||
var settlementMode = 1
|
||||
//结算模式:1-独立支付,2-联合结算
|
||||
//settlementMode = if (deviceConfig.payType == 2) 0 else 1
|
||||
// TODO: 2022/10/13 修改为独立支付
|
||||
SpTool.settlementMode = settlementMode
|
||||
|
||||
GlobalData.appId = deviceConfig.arcsoftAppId ?: ""
|
||||
GlobalData.sdkKey = deviceConfig.arcsoftSdkKey ?: ""
|
||||
GlobalData.activeKey = deviceConfig.arcsoftActiveKey ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadNetworkErrorDialog() {
|
||||
RemindDialog(
|
||||
context = context,
|
||||
|
||||
@@ -86,6 +86,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import org.json.JSONObject
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
@@ -200,6 +201,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
|
||||
override fun initialize() {
|
||||
super.initialize()
|
||||
settlementMode = SpTool.settlementMode
|
||||
isPageVisible = true
|
||||
// 拦截扫码枪按键事件,防止触发页面按钮点击
|
||||
registerKeyEvent()
|
||||
@@ -212,9 +214,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
initData()
|
||||
}
|
||||
|
||||
private fun initLayoutEatDetailBinding(mode: Int) {
|
||||
private fun initLayoutEatDetailBinding() {
|
||||
Timber.tag(TAG).d("initLayoutEatDetailBinding,settlementMode=$settlementMode")
|
||||
binding.flFoodList.removeAllViews()
|
||||
if (mode == 0) {
|
||||
if (settlementMode == 0) {
|
||||
//联合支付
|
||||
val b = LayoutMainFoodList2Binding.inflate(layoutInflater, binding.flFoodList, true)
|
||||
rvFoodList = b.rvFoodList
|
||||
@@ -255,25 +258,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
initLayoutEatDetailBinding(SpTool.settlementMode)
|
||||
viewModel.getDeviceConfig { deviceConfig ->
|
||||
runOnUiThread {
|
||||
if (deviceConfig == null) {
|
||||
ToastUtils.showToast("获取设备配置数据失败")
|
||||
initLayoutEatDetailBinding(SpTool.settlementMode)
|
||||
return@runOnUiThread
|
||||
}
|
||||
//结算模式:1-独立支付,2-联合结算
|
||||
settlementMode = if (deviceConfig.payType == 2) 0 else 1
|
||||
SpTool.settlementMode = settlementMode
|
||||
|
||||
GlobalData.appId = deviceConfig.arcsoftAppId ?: ""
|
||||
GlobalData.sdkKey = deviceConfig.arcsoftSdkKey ?: ""
|
||||
GlobalData.activeKey = deviceConfig.arcsoftActiveKey ?: ""
|
||||
viewModel.activeEngine()
|
||||
initLayoutEatDetailBinding(settlementMode)
|
||||
}
|
||||
}
|
||||
viewModel.activeEngine()
|
||||
initLayoutEatDetailBinding()
|
||||
updateDateTime()
|
||||
binding.tvTitleTime.setOnClickListener {
|
||||
EnvSwitchDialog(context = this, onEnvChanged = {
|
||||
|
||||
@@ -166,6 +166,8 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
var memberDiscount = 1.0
|
||||
|
||||
var memberInfo: MemberInfo? = null
|
||||
fun showPayInfo(type: Int = 1, isVip: Boolean = false, memberInfo: MemberInfo? = null) {
|
||||
this.memberInfo = memberInfo
|
||||
@@ -191,9 +193,19 @@ class PayActivity : BaseActivity<ActivityPayBinding>() {
|
||||
it.type = type
|
||||
it.foodName = foodInfo?.foodName
|
||||
//确认使用vipPrice 还是 specPrice
|
||||
val onePrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice
|
||||
it.totalPrice = (onePrice ?: 0.0) * eatNum
|
||||
presentation.initView()
|
||||
//val onePrice = if (isVip) foodInfo?.vipPrice else foodInfo?.specPrice
|
||||
if (isVip) {
|
||||
userViewModel.getMemberDiscount(memberInfo?.faceUserId?:"") { discount ->
|
||||
memberDiscount = if (discount == null) 1.0 else discount / 10
|
||||
var onePrice = foodInfo?.specPrice ?: 0.0
|
||||
onePrice = if (isVip) onePrice * memberDiscount else onePrice
|
||||
it.totalPrice = onePrice * eatNum
|
||||
presentation.initView()
|
||||
}
|
||||
} else {
|
||||
it.totalPrice = (foodInfo?.specPrice ?: 0.0) * eatNum
|
||||
presentation.initView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ class FacePayFragment : BaseFragment<FragmentFacePayBinding>() {
|
||||
// }
|
||||
payActivity.foodInfo?.let {
|
||||
foodName = it.foodName
|
||||
payAmount = (it.vipPrice ?: 0.0) * payActivity.eatNum
|
||||
// payAmount = (it.vipPrice ?: 0.0) * payActivity.eatNum
|
||||
val price = it.specPrice ?: 0.0
|
||||
payAmount = price * payActivity.memberDiscount * payActivity.eatNum
|
||||
}
|
||||
showSubScreen()
|
||||
}
|
||||
|
||||
@@ -75,7 +75,9 @@ class PayResultFragment : BaseFragment<FragmentPayResultBinding>() {
|
||||
}
|
||||
|
||||
if (memberInfo != null && memberInfo!!.member) {
|
||||
totalPrice = (payActivity.foodInfo?.vipPrice ?: 0.0) * payActivity.eatNum
|
||||
// totalPrice = (payActivity.foodInfo?.vipPrice ?: 0.0) * payActivity.eatNum
|
||||
val price = payActivity.foodInfo?.specPrice ?: 0.0
|
||||
totalPrice = price * payActivity.memberDiscount * payActivity.eatNum
|
||||
binding.layoutVip.visible()
|
||||
balance = (memberInfo!!.topUpBalance ?: 0.0) + (memberInfo!!.rewardBalance ?: 0.0)
|
||||
realPayPrice = if (balance >= totalPrice) 0.0 else totalPrice - balance
|
||||
|
||||
@@ -321,4 +321,13 @@ interface ApiService {
|
||||
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/settlement/terminal/app/getFoodInfoBySettlement",
|
||||
@Query("userId") userId: String
|
||||
): ApiResponse<FoodOrderModel?>
|
||||
|
||||
/**
|
||||
* 查询会员折扣
|
||||
*/
|
||||
@GET
|
||||
suspend fun getMemberDiscount(
|
||||
@Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/common/app/getMemberDiscount",
|
||||
@Query("userId") userId: String
|
||||
): ApiResponse<Double?>
|
||||
}
|
||||
@@ -69,6 +69,7 @@ import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged", "SetTextI18n")
|
||||
class MainScreenPresentation(
|
||||
val activity: MainActivity,
|
||||
display: Display,
|
||||
@@ -338,6 +339,7 @@ class MainScreenPresentation(
|
||||
}
|
||||
|
||||
private val step3Debouncer = Debouncer(10*1000)
|
||||
private var memberDiscount:Double = 1.0
|
||||
|
||||
/**
|
||||
* 根据接口数据更新热量、营养数据
|
||||
@@ -464,7 +466,6 @@ class MainScreenPresentation(
|
||||
/**
|
||||
* 餐品识别成功,不计费模式
|
||||
*/
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun loadUnbilledMode() {
|
||||
if (currentUserId.isNullOrBlank()) {
|
||||
return
|
||||
@@ -685,7 +686,7 @@ class MainScreenPresentation(
|
||||
|
||||
private var lastAddWeight = 0
|
||||
private fun addFoodToOrder(weight: Int, foodInfo: FoodInfo) {
|
||||
Log.d(TAG, "addFoodToOrder: ${weight == lastAddWeight}")
|
||||
Timber.tag(TAG) .d("addFoodToOrder: ${weight == lastAddWeight}")
|
||||
// if (weight == lastAddWeight) return
|
||||
lastAddWeight = weight
|
||||
if (weight <= 10) {
|
||||
@@ -701,9 +702,10 @@ class MainScreenPresentation(
|
||||
}
|
||||
return
|
||||
}
|
||||
val foodPrice = if (isMember) foodInfo.vipPrice else foodInfo.specPrice
|
||||
//val foodPrice = if (isMember) foodInfo.vipPrice else foodInfo.specPrice
|
||||
val foodPrice = (foodInfo.specPrice ?: 0.0) * memberDiscount
|
||||
val eatNum = activity.getEatNum(weight.toDouble(), foodInfo.specWeight)
|
||||
val price = eatNum * (foodPrice ?: 0.0)
|
||||
val price = eatNum * foodPrice
|
||||
if (foodOrderList.isNotEmpty() && mealPickupMode == 1) {
|
||||
val last = foodOrderList.last()
|
||||
if (last.isLocalData) {
|
||||
@@ -732,8 +734,7 @@ class MainScreenPresentation(
|
||||
)
|
||||
// foodOrderAdapter.submitList(foodOrderList)
|
||||
foodOrderAdapter.notifyDataSetChanged()
|
||||
Log.d(
|
||||
TAG,
|
||||
Timber.tag(TAG) .d(
|
||||
"addFoodToOrder: size=${foodOrderList.size},新增数据:${foodOrderList.last()}"
|
||||
)
|
||||
//foodOrderAdapter.notifyDataSetChanged()
|
||||
@@ -742,7 +743,7 @@ class MainScreenPresentation(
|
||||
eatWeightSum += it.num
|
||||
}
|
||||
binding.detailInclude.tvTotalWeight.text = "总重量:${eatWeightSum}克"
|
||||
Log.d(TAG, "addFoodToOrder: 更新总重量,新增数据------------------------------")
|
||||
Timber.tag(TAG) .d("addFoodToOrder: 更新总重量,新增数据------------------------------")
|
||||
}
|
||||
|
||||
private fun calculateNutrition(value: Int) {
|
||||
@@ -1031,7 +1032,11 @@ class MainScreenPresentation(
|
||||
}
|
||||
}
|
||||
// pauseCamera()
|
||||
step3ShowRecognizeResult(userId)
|
||||
//先查询会员折扣
|
||||
userViewModel.getMemberDiscount(userId) { discount ->
|
||||
memberDiscount = if (discount == null) 1.0 else discount / 10
|
||||
step3ShowRecognizeResult(userId)
|
||||
}
|
||||
})
|
||||
|
||||
recognizeViewModel.drawRectInfoText.observe(activity, Observer { info ->
|
||||
@@ -1471,7 +1476,6 @@ class MainScreenPresentation(
|
||||
/**
|
||||
* 加载订单列表
|
||||
*/
|
||||
@SuppressLint("NotifyDataSetChanged", "SetTextI18n")
|
||||
private fun loadOrderList(userId: String, callback: () -> Unit) {
|
||||
binding.llTopInfo.gone()
|
||||
binding.flFoodDetail.visible()
|
||||
@@ -1489,7 +1493,7 @@ class MainScreenPresentation(
|
||||
//foodOrderAdapter.submitList(foodOrderList)
|
||||
foodOrderAdapter.notifyDataSetChanged()
|
||||
//binding.detailInclude.tvTotalWeight.text = "总重量:${model.eatWeightSum}克"
|
||||
Log.d(TAG, "addFoodToOrder: 更新总重量,订单列表------------------------------")
|
||||
Timber.tag(TAG).d("addFoodToOrder: 更新总重量,订单列表------------------------------")
|
||||
// binding.detailInclude.tvTotalCalorie.text = "总热量:${model.calorie.roundedDecimalPlace(1)}千卡"
|
||||
jointPaymentQueryFinish = true
|
||||
|
||||
|
||||
@@ -359,4 +359,10 @@ class RemoteRepository constructor(
|
||||
apiService.getFoodOrderList(userId = userId)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getMemberDiscount(userId: String): ApiResponse<Double?> {
|
||||
return safeApiCall {
|
||||
apiService.getMemberDiscount(userId = userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -651,4 +651,16 @@ class UserViewModel : BaseViewModel() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getMemberDiscount(userId: String, block: (Double?) -> Unit) {
|
||||
Timber.tag(TAG).d("getMemberDiscount")
|
||||
launchWithLoading {
|
||||
val response = repository.getMemberDiscount(userId)
|
||||
if (parseResponse(response)) {
|
||||
block(response.data)
|
||||
} else {
|
||||
block(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvFoodList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginHorizontal="14dp"
|
||||
android:layout_marginTop="42dp"
|
||||
android:layout_weight="1"
|
||||
android:overScrollMode="never"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:spanCount="2"
|
||||
tools:itemCount="8"
|
||||
tools:listitem="@layout/list_item_search_food" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvToSearch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="38dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:padding="10dp"
|
||||
tools:text="以上都不是,手动搜索"
|
||||
android:textColor="#FFFF3232"
|
||||
android:textSize="31sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvFoodList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/tvToSearch"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginHorizontal="14dp"
|
||||
android:layout_marginTop="42dp"
|
||||
android:overScrollMode="never"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:spanCount="2"
|
||||
tools:itemCount="8"
|
||||
tools:listitem="@layout/list_item_search_food" />
|
||||
|
||||
<include
|
||||
android:id="@+id/detailInclude"
|
||||
layout="@layout/layout_eat_detail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginHorizontal="14dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Reference in New Issue
Block a user