diff --git a/app/src/main/java/com/sw/inbound/di/NetworkModule.kt b/app/src/main/java/com/sw/inbound/di/NetworkModule.kt index 8b50ad3..765abe7 100644 --- a/app/src/main/java/com/sw/inbound/di/NetworkModule.kt +++ b/app/src/main/java/com/sw/inbound/di/NetworkModule.kt @@ -36,7 +36,7 @@ object NetworkModule { Timber.d("okhttp logger ==>${it}") }).apply { level = if (MyApp.DEBUG) { - HttpLoggingInterceptor.Level.BODY + HttpLoggingInterceptor.Level.BASIC } else { HttpLoggingInterceptor.Level.NONE } diff --git a/app/src/main/java/com/sw/inbound/ext/CommonExt.kt b/app/src/main/java/com/sw/inbound/ext/CommonExt.kt index 9fcbabe..e389a1c 100644 --- a/app/src/main/java/com/sw/inbound/ext/CommonExt.kt +++ b/app/src/main/java/com/sw/inbound/ext/CommonExt.kt @@ -33,6 +33,17 @@ private fun Double.roundToDouble(decimalPlaces: Int): Double { return kotlin.math.round(this * factor) / factor } +private fun Float.roundToDouble(decimalPlaces: Int): Double { + val factor = 10.0.pow(decimalPlaces) + return kotlin.math.round(this * factor) / factor +} + +fun Float?.toSafeString(unitName: String?): String { + if (this == null || this == 0f) return "" + val decimalPlaces = getDecimalPlaces(unitName) + return "%.${decimalPlaces}f".format(this) +} + fun Double?.toSafeString(unitName: String?): String { if (this == null || this == 0.0) return "" val decimalPlaces = getDecimalPlaces(unitName) @@ -46,6 +57,12 @@ fun Double?.toSafeDouble(unitName: String?): Double { return roundToDouble(decimalPlaces) } +fun Double?.toSafeDouble(decimalPlaces: Int = 2): Double { + if (this == null || this == 0.0) return 0.0 + + return roundToDouble(decimalPlaces) +} + fun Double?.toSafeFloat(unitName: String?): Float { if (this == null || this == 0.0) return 0f @@ -53,6 +70,18 @@ fun Double?.toSafeFloat(unitName: String?): Float { return roundToDouble(decimalPlaces).toFloat() } +fun Double?.toSafeFloat(decimalPlaces: Int = 2): Float { + if (this == null || this == 0.0) return 0f + + return roundToDouble(decimalPlaces).toFloat() +} + +fun Float?.toSafeFloat(decimalPlaces: Int = 2): Float { + if (this == null || this == 0f) return 0f + + return roundToDouble(decimalPlaces).toFloat() +} + /** * 通过单位判断小数 */ diff --git a/app/src/main/java/com/sw/inbound/model/request/PurchaseWarehouseParam.kt b/app/src/main/java/com/sw/inbound/model/request/PurchaseWarehouseParam.kt index c4e613e..d123c62 100644 --- a/app/src/main/java/com/sw/inbound/model/request/PurchaseWarehouseParam.kt +++ b/app/src/main/java/com/sw/inbound/model/request/PurchaseWarehouseParam.kt @@ -33,10 +33,15 @@ data class PurchaseWarehouseParam( * 入库单价 */ var goodsUnitPrice: Double = 0.0, + // 单价 输入框显示 + var goodsUnitPriceTemp: String = "", /** * 入库金额 */ var goodsPrice: Double = 0.0, + + // 用于界面显示的金额 + var goodsPriceTemp: String = "", /** * (物品列表里 businessUnitId字段的值) */ diff --git a/app/src/main/java/com/sw/inbound/model/response/GoodsInfo.kt b/app/src/main/java/com/sw/inbound/model/response/GoodsInfo.kt index 874c2d9..184f234 100644 --- a/app/src/main/java/com/sw/inbound/model/response/GoodsInfo.kt +++ b/app/src/main/java/com/sw/inbound/model/response/GoodsInfo.kt @@ -29,6 +29,9 @@ data class GoodsInfo( */ var recUnitPriceTaxIn: Float? = null, + // 单价 界面显示 + var recUnitPriceTaxInTemp: String = "", + /** * 单位名称 */ @@ -47,6 +50,8 @@ data class GoodsInfo( * 金额 */ var recPriceExItem: Float? = null, + // 金额 界面显示 + var recPriceExItemTemp: String = "", /** * 仓库id */ diff --git a/app/src/main/java/com/sw/inbound/ui/page/ReceiptProductScreen.kt b/app/src/main/java/com/sw/inbound/ui/page/ReceiptProductScreen.kt index bd22ae9..7a03a7d 100644 --- a/app/src/main/java/com/sw/inbound/ui/page/ReceiptProductScreen.kt +++ b/app/src/main/java/com/sw/inbound/ui/page/ReceiptProductScreen.kt @@ -555,21 +555,35 @@ private fun ReceiptProductEditView( RowInputLayout( label = "收货单价", - value = selectedItem!!.recUnitPriceTaxInStr, + value = selectedItem!!.recUnitPriceTaxInTemp, trailingLabel = "元", + isInitUpdate = true, onValueChange = { value -> + viewModel.updatePriceInputState(value.isNotEmpty()) selectedItem?.let { - viewModel.updateSelectedItem(selectedItem!!.copy(recUnitPriceTaxIn = value.toSafeFloat())) + viewModel.updateSelectedItem( + selectedItem!!.copy( + recUnitPriceTaxInTemp = value, + recUnitPriceTaxIn = value.toSafeFloat() + ) + ) } }, inputType = InputType.Decimal ) RowInputLayout( label = "收货金额", - value = selectedItem!!.recPriceExItemStr, + value = selectedItem!!.recPriceExItemTemp, trailingLabel = "元", + isInitUpdate = true, onValueChange = { value -> + viewModel.updateAmountInputState(value.isNotEmpty()) selectedItem?.let { - viewModel.updateSelectedItem(selectedItem!!.copy(recPriceExItem = value.toSafeFloat())) + viewModel.updateSelectedItem( + selectedItem!!.copy( + recPriceExItemTemp = value, + recPriceExItem = value.toSafeFloat() + ) + ) } }, inputType = InputType.Decimal ) @@ -622,6 +636,13 @@ private fun ReceiptProductEditView( ToastUtils.showToast(errorInfo) return@clickable } + val expectAmount = + selectedItem!!.receivedNum!!.times(selectedItem!!.recUnitPriceTaxIn!!) + Timber.d("金额判断:期望金额 = $expectAmount, 实际金额 = ${selectedItem!!.recPriceExItem}") + if (expectAmount != selectedItem!!.recPriceExItem) { + ToastUtils.showToast("数量和金额不符,请检查后再试") + return@clickable + } viewModel.updatePurchaseItem(purchaseOrder = selectedItem!!.copy(isAdjusted = true)) viewModel.updateSelectedItem(null) }, painter = painterResource(R.mipmap.ic_btn_confirm), contentDescription = "确定") diff --git a/app/src/main/java/com/sw/inbound/ui/page/SelfProcurementScreen.kt b/app/src/main/java/com/sw/inbound/ui/page/SelfProcurementScreen.kt index 3435719..651ea02 100644 --- a/app/src/main/java/com/sw/inbound/ui/page/SelfProcurementScreen.kt +++ b/app/src/main/java/com/sw/inbound/ui/page/SelfProcurementScreen.kt @@ -581,7 +581,7 @@ private fun SelfProductEditView( val lifecycleOwner = LocalLifecycleOwner.current LaunchedEffect(selectedItem) { - Timber.d("界面显示") + Timber.d("selectedItem变化 selectedItem is ${selectedItem == null}") if (selectedItem == null) { viewModel.updateSelectedItem(purchaseOrder = PurchaseWarehouseParam()) } @@ -589,6 +589,7 @@ private fun SelfProductEditView( DisposableEffect(lifecycleOwner) { Timber.d("开始传感器采集") + viewModel.startSensorScale() onDispose { Timber.d("停止传感器采集") @@ -670,22 +671,37 @@ private fun SelfProductEditView( RowInputLayout( label = "采购单价", - value = selectedItem!!.goodsUnitPriceStr, + value = selectedItem!!.goodsUnitPriceTemp, inputType = InputType.Decimal, trailingLabel = "元", + isInitUpdate = true, onValueChange = { value -> + viewModel.updatePriceInputState(value.isNotEmpty()) selectedItem.let { - viewModel.updateSelectedItem(selectedItem!!.copy(goodsUnitPrice = value.toSafeDouble())) + Timber.d("goodsUnitPrice 更新 = $value") + viewModel.updateSelectedItem( + selectedItem!!.copy( + goodsUnitPriceTemp = value, + goodsUnitPrice = value.toSafeDouble() + ) + ) } }) RowInputLayout( label = "采购金额", - value = selectedItem!!.goodsPriceStr, + value = selectedItem!!.goodsPriceTemp, inputType = InputType.Decimal, trailingLabel = "元", + isInitUpdate = true, onValueChange = { value -> + viewModel.updateAmountInputState(value.isNotEmpty()) selectedItem.let { - viewModel.updateSelectedItem(selectedItem!!.copy(goodsPrice = value.toSafeDouble())) + viewModel.updateSelectedItem( + selectedItem!!.copy( + goodsPriceTemp = value, + goodsPrice = value.toSafeDouble() + ) + ) } }) @@ -760,7 +776,12 @@ private fun SelfProductEditView( ToastUtils.showToast(errInfo) return@CustomButton } - + val expectAmount = selectedItem!!.goodsCount * selectedItem!!.goodsUnitPrice + Timber.d("金额判断:期望金额 = $expectAmount, 实际金额 = ${selectedItem!!.goodsPrice}") + if (expectAmount != selectedItem!!.goodsPrice) { + ToastUtils.showToast("数量和金额不符,请检查后再试") + return@CustomButton + } viewModel.addPurchaseItem(selectedItem!!) }) } diff --git a/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt b/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt index a292a1c..940645a 100644 --- a/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt +++ b/app/src/main/java/com/sw/inbound/viewmodel/ReceiptViewModel.kt @@ -1,9 +1,9 @@ package com.sw.inbound.viewmodel import androidx.lifecycle.viewModelScope +import com.sw.inbound.ext.toFormattedString import com.sw.inbound.ext.toSafeBigDecimal import com.sw.inbound.ext.toSafeFloat -import com.sw.inbound.ext.toSafeString import com.sw.inbound.model.request.UploadInfo import com.sw.inbound.model.response.DictType import com.sw.inbound.model.response.GoodsInfo @@ -72,6 +72,8 @@ class ReceiptViewModel @Inject constructor( // 物品数量 是否由用户输入 private val _countUserInput = MutableStateFlow(false) + private val _priceUserInput = MutableStateFlow(false) + private val _amountUserInput = MutableStateFlow(false) /** * 更新调整状态 @@ -84,6 +86,7 @@ class ReceiptViewModel @Inject constructor( fun StateFlow>.getValidOrders(): List { return this.value.filter { it.goodId != null } } + /** * 更新收货提示弹窗 */ @@ -103,6 +106,28 @@ class ReceiptViewModel @Inject constructor( * 更新选中的item */ fun updateSelectedItem(purchaseOrder: GoodsInfo?) { + if (purchaseOrder != null) { + purchaseOrder.receivedNum.takeIf { it != 0f }?.let { receivedNum -> + // 计算金额 单价不为空,并且金额没有手动输入 + if (purchaseOrder.recUnitPriceTaxIn != null && purchaseOrder.recUnitPriceTaxIn == 0f && !_amountUserInput.value) { + val result = + receivedNum.times(purchaseOrder.recUnitPriceTaxIn!!) + purchaseOrder.recPriceExItem = result.toSafeFloat() + purchaseOrder.recPriceExItemTemp = result.toFormattedString() + } + // 计算单价 金额不为空,并且单价没有手动输入 + if (purchaseOrder.recPriceExItem != null && purchaseOrder.recPriceExItem == 0f && !_priceUserInput.value) { + val result = + purchaseOrder.recPriceExItem!!.div(receivedNum) + purchaseOrder.recUnitPriceTaxIn = result.toSafeFloat() + purchaseOrder.recUnitPriceTaxInTemp = result.toFormattedString() + } + } + } else { + _countUserInput.value = false + _priceUserInput.value = false + _amountUserInput.value = false + } _selectedItem.value = purchaseOrder } @@ -179,31 +204,70 @@ class ReceiptViewModel @Inject constructor( _orders.value = emptyList() } + /** + * 更新数量输入状态 + */ fun updateCountInputState(boolean: Boolean) { _countUserInput.value = boolean } + /** + * 更新单价输入状态 + */ + fun updatePriceInputState(boolean: Boolean) { + _priceUserInput.value = boolean + } + + /** + * 更新金额输入状态 + */ + fun updateAmountInputState(boolean: Boolean) { + _amountUserInput.value = boolean + } + fun startSensorScale() { Timber.d("开始称重") SensorScaleUtils.startScale(callback = { weight -> val currentItem = _selectedItem.value currentItem?.let { info -> + // 用户输入数量后不再通过重量反算 + if (_countUserInput.value) { + _selectedItem.value = info.copy( + goodsWeight = weight.toSafeBigDecimal(), + ) + return@startScale + } val consumeValue = currentItem.consumeValue?.toDouble() ?: 1.0 val purchaseValue = currentItem.purchaseValue?.toDouble() ?: 1.0 val count = weight * 1000 / consumeValue / purchaseValue val finalCount = count.toSafeFloat(currentItem.unitName) Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue") - if (info.receivedNumTemp.isEmpty()) { - _countUserInput.value = false - } + // 计算单价 + val finalPrice = if (count == 0.0) { + 0f + } else if (info.recPriceExItem != null && info.recPriceExItem != 0f && !_countUserInput.value && !_priceUserInput.value) { + info.recPriceExItem!!.div(count).toSafeFloat() + } else info.recUnitPriceTaxIn ?: 0f + // 计算金额 + val finalAmount = if (count == 0.0) { + 0f + } else if (info.recUnitPriceTaxIn != null && info.recUnitPriceTaxIn != 0f && !_countUserInput.value && !_amountUserInput.value) { + count.times(info.recUnitPriceTaxIn!!).toSafeFloat() + } else info.recPriceExItem ?: 0f + _selectedItem.value = info.copy( goodsWeight = weight.toSafeBigDecimal(), - receivedNumTemp = if (_countUserInput.value) info.receivedNumTemp else count.toSafeString( - currentItem.unitName - ), - receivedNum = if (_countUserInput.value) info.receivedNum else finalCount + // 收货数量 + receivedNumTemp = if (_countUserInput.value) info.receivedNumTemp else count.toFormattedString(), + receivedNum = if (_countUserInput.value) info.receivedNum else finalCount, + // 单价 + recUnitPriceTaxIn = if (_priceUserInput.value) info.recUnitPriceTaxIn else finalPrice, + recUnitPriceTaxInTemp = if (_priceUserInput.value) info.recUnitPriceTaxInTemp else finalPrice.toFormattedString(), + // 金额 + recPriceExItem = if (_amountUserInput.value) info.recPriceExItem else finalAmount, + recPriceExItemTemp = if (_amountUserInput.value) info.recPriceExItemTemp else finalAmount.toFormattedString(), ) } }) diff --git a/app/src/main/java/com/sw/inbound/viewmodel/SelfProcurementViewModel.kt b/app/src/main/java/com/sw/inbound/viewmodel/SelfProcurementViewModel.kt index f5e6a1c..a4e8355 100644 --- a/app/src/main/java/com/sw/inbound/viewmodel/SelfProcurementViewModel.kt +++ b/app/src/main/java/com/sw/inbound/viewmodel/SelfProcurementViewModel.kt @@ -2,9 +2,9 @@ package com.sw.inbound.viewmodel import androidx.lifecycle.viewModelScope import com.sw.inbound.GlobalData +import com.sw.inbound.ext.toFormattedString import com.sw.inbound.ext.toSafeBigDecimal import com.sw.inbound.ext.toSafeDouble -import com.sw.inbound.ext.toSafeString import com.sw.inbound.model.request.GoodsAddParam import com.sw.inbound.model.request.PurchaseWarehouseParam import com.sw.inbound.model.response.DictType @@ -67,6 +67,16 @@ class SelfProcurementViewModel @Inject constructor( */ private val _countUserInput = MutableStateFlow(false) + /** + * 单价是否是用户输入的值 + */ + private val _priceUserInput = MutableStateFlow(false) + + /** + * 金额输入状态 + */ + private val _amountUserInput = MutableStateFlow(false) + /** * 更新全局仓库 */ @@ -80,6 +90,14 @@ class SelfProcurementViewModel @Inject constructor( val currentItem = _selectedItem.value currentItem?.let { info -> + // 用户输入数量后不再通过重量反算 + if (_countUserInput.value) { + _selectedItem.value = info.copy( + goodsWeight = weight.toSafeBigDecimal(), + ) + return@startScale + } + val selectUnitType = currentItem.selectUnitType if (selectUnitType == null) return@startScale @@ -89,15 +107,35 @@ class SelfProcurementViewModel @Inject constructor( weight * 1000 / consumeValue / purchaseValue val finalCount = count.toSafeDouble(currentItem.unitName) Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue") - if (info.goodsCountTemp.isEmpty()) { - _countUserInput.value = false - } + + Timber.d("startSensorScale goodsUnitPrice = ${info.goodsUnitPrice}, goodsPrice = ${info.goodsPrice} ") + // 计算单价 金额不为空,数量也不为空, 不是数量输入 也不是单价输入 + val finalPrice = + if (count == 0.0) { + 0.0 + } else if (info.goodsPrice != 0.0 && !_countUserInput.value && !_priceUserInput.value) { + info.goodsPrice.div(count).toSafeDouble() + } else info.goodsUnitPrice + + // 计算金额 单价不为空,不是数量输入 也不是金额输入 + val finalAmount = + if (count == 0.0) { + 0.0 + } else if (info.goodsUnitPrice != 0.0 && !_countUserInput.value && !_amountUserInput.value) { + count.times(info.goodsUnitPrice).toSafeDouble() + } else info.goodsPrice + Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ") _selectedItem.value = info.copy( goodsWeight = weight.toSafeBigDecimal(), - goodsCountTemp = if (_countUserInput.value) info.goodsCountTemp else count.toSafeString( - currentItem.unitName - ), - goodsCount = if (_countUserInput.value) info.goodsCount else finalCount + // 数量 + goodsCountTemp = if (_countUserInput.value) info.goodsCountTemp else finalCount.toFormattedString(), + goodsCount = if (_countUserInput.value) info.goodsCount else finalCount, + // 单价 + goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice, + goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(), + // 金额 + goodsPrice = if (_amountUserInput.value) info.goodsPrice else finalAmount, + goodsPriceTemp = if (_amountUserInput.value) info.goodsPriceTemp else finalAmount.toFormattedString() ) } }) @@ -113,7 +151,34 @@ class SelfProcurementViewModel @Inject constructor( } fun updateSelectedItem(purchaseOrder: PurchaseWarehouseParam?) { + if (purchaseOrder != null) { + purchaseOrder.goodsCount.takeIf { it != 0.0 }?.let { receivedNum -> + // 计算金额 单价不为空,并且金额没有手动输入 + if (purchaseOrder.goodsUnitPrice != 0.0 && !_amountUserInput.value) { + Timber.d("updateSelectedItem 计算金额") + val result = + receivedNum.times(purchaseOrder.goodsUnitPrice) + purchaseOrder.goodsPrice = result.toSafeDouble() + purchaseOrder.goodsPriceTemp = result.toFormattedString() + } + // 计算单价 金额不为空,并且单价没有手动输入 + if (purchaseOrder.goodsPrice != 0.0 && !_priceUserInput.value) { + Timber.d("updateSelectedItem 计算单价") + val result = + purchaseOrder.goodsPrice.div(receivedNum) + purchaseOrder.goodsUnitPrice = result.toSafeDouble() + purchaseOrder.goodsUnitPriceTemp = result.toFormattedString() + } + } + } else { + // 重置输入状态 + Timber.d("重置输入状态") + _countUserInput.value = false + _priceUserInput.value = false + _amountUserInput.value = false + } _selectedItem.value = purchaseOrder + Timber.d("updateSelectedItem 更新,goodsUnitPrice = ${_selectedItem.value?.goodsUnitPrice}, ${_selectedItem.value?.goodsUnitPriceTemp}") } fun updateGoodsAddParam(newState: GoodsAddParam) { @@ -195,10 +260,27 @@ class SelfProcurementViewModel @Inject constructor( } } + /** + * 数量输入状态 + */ fun updateCountInputState(boolean: Boolean) { _countUserInput.value = boolean } + /** + * 单价输入状态 + */ + fun updatePriceInputState(boolean: Boolean) { + _priceUserInput.value = boolean + } + + /** + * 金额输入状态 + */ + fun updateAmountInputState(boolean: Boolean) { + _amountUserInput.value = boolean + } + fun addGoodsInfo() { val imageUri = GlobalData.imageUri if (imageUri == null) {