处理数量、单价、金额之间的计算

This commit is contained in:
zxj
2025-07-11 09:46:08 +08:00
parent 32bc730a21
commit f92ae70423
10 changed files with 98 additions and 79 deletions
@@ -36,7 +36,7 @@ object NetworkModule {
Timber.d("okhttp logger ==>${it}") Timber.d("okhttp logger ==>${it}")
}).apply { }).apply {
level = if (MyApp.DEBUG) { level = if (MyApp.DEBUG) {
HttpLoggingInterceptor.Level.BASIC HttpLoggingInterceptor.Level.BODY
} else { } else {
HttpLoggingInterceptor.Level.NONE HttpLoggingInterceptor.Level.NONE
} }
@@ -7,7 +7,8 @@ import kotlin.math.pow
fun Float.toFormattedString(decimalPlaces: Int = 2): String { fun Float.toFormattedString(decimalPlaces: Int = 2): String {
return when (this) { return when (this) {
0f -> "" 0f -> ""
else -> "%.${decimalPlaces}f".format(this) else -> "%.${decimalPlaces}f".format(this) // 先格式化为固定位数
// .replace(Regex("\\.?0+$"), "") // 移除末尾的0
} }
} }
@@ -15,6 +16,7 @@ fun Double.toFormattedString(decimalPlaces: Int = 2): String {
return when (this) { return when (this) {
0.0 -> "" 0.0 -> ""
else -> "%.${decimalPlaces}f".format(this) else -> "%.${decimalPlaces}f".format(this)
// .replace(Regex("\\.?0+$"), "")
} }
} }
@@ -29,9 +29,10 @@ fun String.isNumeric(): Boolean {
return this.matches("-?\\d+(\\.\\d+)?".toRegex()) return this.matches("-?\\d+(\\.\\d+)?".toRegex())
} }
fun String.toFormattedString(decimalPlaces: Int = 2): String { fun String?.toFormattedString(decimalPlaces: Int = 2): String {
return when (this) { return when (this) {
else -> "%.${decimalPlaces}f".format(this) null -> ""
else -> "%.${decimalPlaces}s".format(this)
} }
} }
@@ -73,7 +74,14 @@ fun String.toSafeDouble(): Double {
fun String.isValidFloat(): Boolean { fun String.isValidFloat(): Boolean {
if (startsWith(".")) return false if (startsWith(".")) return false
val decimalRegex = Regex("^\\d*\\.?\\d{0,2}$") // 处理前导零的情况
if (length > 1 && startsWith("0")) {
// 允许 "0" 和 "0.x" 但不允许 "00", "01", "00.1" 等
if (!startsWith("0.")) {
return false
}
}
val decimalRegex = Regex("^\\d+\\.?\\d{0,2}$")
return this.matches(decimalRegex) return this.matches(decimalRegex)
// return input.matches(Regex("-?\\d+(\\.\\d+)?")) // return input.matches(Regex("-?\\d+(\\.\\d+)?"))
} }
@@ -93,14 +93,6 @@ data class GoodsInfo(
var unitList: List<UnitVo> = emptyList<UnitVo>() var unitList: List<UnitVo> = emptyList<UnitVo>()
) : Parcelable, BaseBean() { ) : Parcelable, BaseBean() {
val unitDictTypeList: List<DictType>
get() {
return unitList.map {
DictType(it.businessUnitId!!.toInt(), it.purchaseUnitName!!)
}
}
val goodNameStr: String val goodNameStr: String
get() { get() {
if (goodName == null) return "-" if (goodName == null) return "-"
@@ -540,7 +540,8 @@ private fun ReceiptProductEditView(
label = "收货数量", label = "收货数量",
value = selectedItem!!.receivedNumTemp, value = selectedItem!!.receivedNumTemp,
onValueChange = { value -> onValueChange = { value ->
viewModel.updateCountInputState(value.isNotEmpty()) viewModel.updateCountInputState(true)
selectedItem?.let { selectedItem?.let {
viewModel.updateSelectedItem( viewModel.updateSelectedItem(
selectedItem!!.copy( selectedItem!!.copy(
@@ -557,14 +558,17 @@ private fun ReceiptProductEditView(
RowInputLayout( RowInputLayout(
label = "收货单价", label = "收货单价",
value = selectedItem!!.recUnitPriceTaxInTemp ?: "", value = selectedItem!!.recUnitPriceTaxInTemp,
trailingLabel = "", trailingLabel = "",
isInitUpdate = true, isInitUpdate = true,
onValueChange = { value -> onValueChange = { value ->
viewModel.updatePriceInputState(value.isNotEmpty()) viewModel.updatePriceInputState(true)
viewModel.updateAmountInputState(false)
selectedItem?.let { selectedItem?.let {
viewModel.updateSelectedItem( viewModel.updateSelectedItem(
selectedItem!!.copy( selectedItem!!.copy(
recPriceExItemTemp = "",
recPriceExItem = 0f,
recUnitPriceTaxInTemp = value, recUnitPriceTaxInTemp = value,
recUnitPriceTaxIn = value.toSafeFloat() recUnitPriceTaxIn = value.toSafeFloat()
) )
@@ -574,14 +578,18 @@ private fun ReceiptProductEditView(
) )
RowInputLayout( RowInputLayout(
label = "收货金额", label = "收货金额",
value = selectedItem!!.recPriceExItemTemp ?: "", value = selectedItem!!.recPriceExItemTemp,
trailingLabel = "", trailingLabel = "",
isInitUpdate = true, isInitUpdate = true,
onValueChange = { value -> onValueChange = { value ->
viewModel.updateAmountInputState(value.isNotEmpty()) viewModel.updateAmountInputState(true)
viewModel.updatePriceInputState(false)
selectedItem?.let { selectedItem?.let {
viewModel.updateSelectedItem( viewModel.updateSelectedItem(
selectedItem!!.copy( selectedItem!!.copy(
recUnitPriceTaxInTemp = "",
recUnitPriceTaxIn = 0f,
recPriceExItemTemp = value, recPriceExItemTemp = value,
recPriceExItem = value.toSafeFloat() recPriceExItem = value.toSafeFloat()
) )
@@ -656,7 +656,7 @@ private fun SelfProductEditView(
isInitUpdate = true, isInitUpdate = true,
onValueChange = { value -> onValueChange = { value ->
Timber.d("采购数量 onValueChange value = $value") Timber.d("采购数量 onValueChange value = $value")
viewModel.updateCountInputState(value.isNotEmpty()) viewModel.updateCountInputState(true)
selectedItem.let { selectedItem.let {
viewModel.updateSelectedItem( viewModel.updateSelectedItem(
selectedItem!!.copy( selectedItem!!.copy(
@@ -676,11 +676,14 @@ private fun SelfProductEditView(
trailingLabel = "", trailingLabel = "",
isInitUpdate = true, isInitUpdate = true,
onValueChange = { value -> onValueChange = { value ->
viewModel.updatePriceInputState(value.isNotEmpty()) viewModel.updatePriceInputState(true)
viewModel.updateAmountInputState(false)
selectedItem.let { selectedItem.let {
Timber.d("goodsUnitPrice 更新 = $value") Timber.d("goodsUnitPrice 更新 = $value")
viewModel.updateSelectedItem( viewModel.updateSelectedItem(
selectedItem!!.copy( selectedItem!!.copy(
goodsPrice = 0.0,
goodsPriceTemp = "",
goodsUnitPriceTemp = value, goodsUnitPriceTemp = value,
goodsUnitPrice = value.toSafeDouble() goodsUnitPrice = value.toSafeDouble()
) )
@@ -694,10 +697,13 @@ private fun SelfProductEditView(
trailingLabel = "", trailingLabel = "",
isInitUpdate = true, isInitUpdate = true,
onValueChange = { value -> onValueChange = { value ->
viewModel.updateAmountInputState(value.isNotEmpty()) viewModel.updateAmountInputState(true)
viewModel.updatePriceInputState(false)
selectedItem.let { selectedItem.let {
viewModel.updateSelectedItem( viewModel.updateSelectedItem(
selectedItem!!.copy( selectedItem!!.copy(
goodsUnitPrice = 0.0,
goodsUnitPriceTemp = "",
goodsPriceTemp = value, goodsPriceTemp = value,
goodsPrice = value.toSafeDouble() goodsPrice = value.toSafeDouble()
) )
@@ -108,9 +108,7 @@ fun CustomTextField(
onClick: () -> Unit = {}, // 点击 onClick: () -> Unit = {}, // 点击
) { ) {
val containerColor = if (enabled) Color.Transparent else Gray_DCDCF0 val containerColor = if (enabled) Color.Transparent else Gray_DCDCF0
// var inputValue by remember { mutableStateOf(value) } var inputValue by remember(if (isInitUpdate) value else null) {
var isUserInput by remember { mutableStateOf(false) }
var inputValue by remember(if (isInitUpdate && !isUserInput) value else null) {
mutableStateOf(value) mutableStateOf(value)
} }
val focusManager = LocalFocusManager.current val focusManager = LocalFocusManager.current
@@ -134,7 +132,6 @@ fun CustomTextField(
textStyle = newTextStyle, textStyle = newTextStyle,
onValueChange = { newValue -> onValueChange = { newValue ->
Timber.d("onValueChange newValue = $newValue") Timber.d("onValueChange newValue = $newValue")
isUserInput = newValue.isNotEmpty()
when (inputType) { when (inputType) {
InputType.Number -> { InputType.Number -> {
if (newValue.isEmpty() || newValue.isValidNumber()) { if (newValue.isEmpty() || newValue.isValidNumber()) {
@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
@@ -47,7 +48,9 @@ fun ReceiptUnadjustedListView(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(30.dp) .padding(horizontal = 60.dp)
.height(84.dp),
verticalAlignment = Alignment.CenterVertically
) { ) {
CustomSingleRightText( CustomSingleRightText(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
@@ -89,7 +92,8 @@ fun ReceiptUnadjustedListView(
Row( Row(
modifier = Modifier modifier = Modifier
.background(color = checkedBg) .background(color = checkedBg)
.padding(30.dp) .height(80.dp)
.padding(horizontal = 60.dp)
.clickable { .clickable {
onItemCheckedClick(it) onItemCheckedClick(it)
}, verticalAlignment = Alignment.CenterVertically }, verticalAlignment = Alignment.CenterVertically
@@ -114,23 +114,26 @@ class ReceiptViewModel @Inject constructor(
*/ */
fun updateSelectedItem(purchaseOrder: GoodsInfo?) { fun updateSelectedItem(purchaseOrder: GoodsInfo?) {
if (purchaseOrder != null) { if (purchaseOrder != null) {
purchaseOrder.receivedNum.takeIf { it != 0f }?.let { receivedNum -> if (purchaseOrder.receivedNum != null && purchaseOrder.receivedNum != 0f) {
// 计算金额 单价不为空,并且金额没有手动输入 if (purchaseOrder.recUnitPriceTaxInTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
// if (purchaseOrder.recUnitPriceTaxIn != null && purchaseOrder.recUnitPriceTaxIn == 0f && !_amountUserInput.value) {
if (purchaseOrder.recUnitPriceTaxIn != null && !_amountUserInput.value) {
val result = val result =
receivedNum.times(purchaseOrder.recUnitPriceTaxIn!!) purchaseOrder.receivedNum!!.times(purchaseOrder.recUnitPriceTaxIn!!)
purchaseOrder.recPriceExItem = result.toSafeFloat() purchaseOrder.recPriceExItem = result.toSafeFloat()
purchaseOrder.recPriceExItemTemp = result.toFormattedString() purchaseOrder.recPriceExItemTemp = result.toFormattedString()
} } else if (purchaseOrder.recPriceExItemTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
// 计算单价 金额不为空,并且单价没有手动输入
// if (purchaseOrder.recPriceExItem != null && purchaseOrder.recPriceExItem == 0f && !_priceUserInput.value) {
if (purchaseOrder.recPriceExItem != null && !_priceUserInput.value) {
val result = val result =
purchaseOrder.recPriceExItem!!.div(receivedNum) purchaseOrder.recPriceExItem!!.div(purchaseOrder.receivedNum!!)
purchaseOrder.recUnitPriceTaxIn = result.toSafeFloat() purchaseOrder.recUnitPriceTaxIn = result.toSafeFloat()
purchaseOrder.recUnitPriceTaxInTemp = result.toFormattedString() purchaseOrder.recUnitPriceTaxInTemp = result.toFormattedString()
} }
} else {
if (_priceUserInput.value) {
purchaseOrder.recPriceExItem = 0f
purchaseOrder.recPriceExItemTemp = ""
} else if (_amountUserInput.value) {
purchaseOrder.recUnitPriceTaxIn = 0f
purchaseOrder.recUnitPriceTaxInTemp = ""
}
} }
} else { } else {
_countUserInput.value = false _countUserInput.value = false
@@ -254,31 +257,35 @@ class ReceiptViewModel @Inject constructor(
val finalCount = count.toSafeFloat(currentItem.unitName) val finalCount = count.toSafeFloat(currentItem.unitName)
Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue") Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
// 计算单价 // 计算单价
val finalPrice = if (count == 0.0) { val finalPrice = when {
0f count == 0.0 -> {
} else if (!_countUserInput.value && !_priceUserInput.value) { 0f
if (info.recPriceExItemTemp.isNotEmpty()) { }
_amountUserInput.value && !_priceUserInput.value -> {
info.recPriceExItem!!.div(count).toSafeFloat() info.recPriceExItem!!.div(count).toSafeFloat()
} else {
0f
} }
} else info.recUnitPriceTaxIn ?: 0f
else -> 0f
}
// 计算金额 // 计算金额
val finalAmount = if (count == 0.0) { val finalAmount = when {
0f count == 0.0 -> {
} else if (!_countUserInput.value && !_amountUserInput.value) {
if (info.recUnitPriceTaxInTemp.isNotEmpty()) {
count.times(info.recUnitPriceTaxIn!!).toSafeFloat()
} else {
0f 0f
} }
} else info.recPriceExItem ?: 0f
_priceUserInput.value && !_amountUserInput.value -> {
count.times(info.recUnitPriceTaxIn!!).toSafeFloat()
}
else -> 0f
}
_selectedItem.value = info.copy( _selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(), goodsWeight = weight.toSafeBigDecimal(),
// 收货数量 // 收货数量
receivedNumTemp = if (_countUserInput.value) info.receivedNumTemp else count.toFormattedString(), receivedNumTemp = count.toFormattedString(),
receivedNum = if (_countUserInput.value) info.receivedNum else finalCount, receivedNum = finalCount,
// 单价 // 单价
recUnitPriceTaxIn = if (_priceUserInput.value) info.recUnitPriceTaxIn else finalPrice, recUnitPriceTaxIn = if (_priceUserInput.value) info.recUnitPriceTaxIn else finalPrice,
recUnitPriceTaxInTemp = if (_priceUserInput.value) info.recUnitPriceTaxInTemp else finalPrice.toFormattedString(), recUnitPriceTaxInTemp = if (_priceUserInput.value) info.recUnitPriceTaxInTemp else finalPrice.toFormattedString(),
@@ -113,31 +113,23 @@ class SelfProcurementViewModel @Inject constructor(
val finalPrice = val finalPrice =
if (count == 0.0) { if (count == 0.0) {
0.0 0.0
} else if (!_countUserInput.value && !_priceUserInput.value) { } else if (_amountUserInput.value && !_priceUserInput.value) {
if (info.goodsPriceTemp.isNotEmpty()) { info.goodsPrice.div(count).toSafeDouble()
info.goodsPrice.div(count).toSafeDouble() } else 0.0
} else {
0.0
}
} else info.goodsUnitPrice
// 计算金额 单价不为空,不是数量输入 也不是金额输入 // 计算金额 单价不为空,不是数量输入 也不是金额输入
val finalAmount = val finalAmount =
if (count == 0.0) { if (count == 0.0) {
0.0 0.0
} else if (!_countUserInput.value && !_amountUserInput.value) { } else if (_priceUserInput.value && !_amountUserInput.value) {
if (info.goodsUnitPriceTemp.isNotEmpty()) { count.times(info.goodsUnitPrice).toSafeDouble()
count.times(info.goodsUnitPrice).toSafeDouble() } else 0.0
} else {
0.0
}
} else info.goodsPrice
Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ") Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ")
_selectedItem.value = info.copy( _selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(), goodsWeight = weight.toSafeBigDecimal(),
// 数量 // 数量
goodsCountTemp = if (_countUserInput.value) info.goodsCountTemp else finalCount.toFormattedString(), goodsCountTemp = finalCount.toFormattedString(),
goodsCount = if (_countUserInput.value) info.goodsCount else finalCount, goodsCount = finalCount,
// 单价 // 单价
goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice, goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice,
goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(), goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(),
@@ -160,25 +152,28 @@ class SelfProcurementViewModel @Inject constructor(
fun updateSelectedItem(purchaseOrder: PurchaseWarehouseParam?) { fun updateSelectedItem(purchaseOrder: PurchaseWarehouseParam?) {
if (purchaseOrder != null) { if (purchaseOrder != null) {
purchaseOrder.goodsCount.takeIf { it != 0.0 }?.let { receivedNum -> if (purchaseOrder.goodsCount != 0.0) {
// 计算金额 单价不为空,并且金额没有手动输入 if (purchaseOrder.goodsUnitPriceTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
// if (purchaseOrder.goodsUnitPrice == 0.0 && !_amountUserInput.value) {
if (!_amountUserInput.value) {
Timber.d("updateSelectedItem 计算金额") Timber.d("updateSelectedItem 计算金额")
val result = val result =
receivedNum.times(purchaseOrder.goodsUnitPrice) purchaseOrder.goodsCount.times(purchaseOrder.goodsUnitPrice)
purchaseOrder.goodsPrice = result.toSafeDouble() purchaseOrder.goodsPrice = result.toSafeDouble()
purchaseOrder.goodsPriceTemp = result.toFormattedString() purchaseOrder.goodsPriceTemp = result.toFormattedString()
} } else if (purchaseOrder.goodsPriceTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
// 计算单价 金额不为空,并且单价没有手动输入
// if (purchaseOrder.goodsPrice == 0.0 && !_priceUserInput.value) {
if (!_priceUserInput.value) {
Timber.d("updateSelectedItem 计算单价") Timber.d("updateSelectedItem 计算单价")
val result = val result =
purchaseOrder.goodsPrice.div(receivedNum) purchaseOrder.goodsPrice.div(purchaseOrder.goodsCount)
purchaseOrder.goodsUnitPrice = result.toSafeDouble() purchaseOrder.goodsUnitPrice = result.toSafeDouble()
purchaseOrder.goodsUnitPriceTemp = result.toFormattedString() purchaseOrder.goodsUnitPriceTemp = result.toFormattedString()
} }
} else {
if (_priceUserInput.value) {
purchaseOrder.goodsPrice = 0.0
purchaseOrder.goodsPriceTemp = ""
} else if (_amountUserInput.value) {
purchaseOrder.goodsUnitPrice = 0.0
purchaseOrder.goodsUnitPriceTemp = ""
}
} }
} else { } else {
// 重置输入状态 // 重置输入状态