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

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}")
}).apply {
level = if (MyApp.DEBUG) {
HttpLoggingInterceptor.Level.BASIC
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
@@ -7,7 +7,8 @@ import kotlin.math.pow
fun Float.toFormattedString(decimalPlaces: Int = 2): String {
return when (this) {
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) {
0.0 -> ""
else -> "%.${decimalPlaces}f".format(this)
// .replace(Regex("\\.?0+$"), "")
}
}
@@ -29,9 +29,10 @@ fun String.isNumeric(): Boolean {
return this.matches("-?\\d+(\\.\\d+)?".toRegex())
}
fun String.toFormattedString(decimalPlaces: Int = 2): String {
fun String?.toFormattedString(decimalPlaces: Int = 2): String {
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 {
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 input.matches(Regex("-?\\d+(\\.\\d+)?"))
}
@@ -93,14 +93,6 @@ data class GoodsInfo(
var unitList: List<UnitVo> = emptyList<UnitVo>()
) : Parcelable, BaseBean() {
val unitDictTypeList: List<DictType>
get() {
return unitList.map {
DictType(it.businessUnitId!!.toInt(), it.purchaseUnitName!!)
}
}
val goodNameStr: String
get() {
if (goodName == null) return "-"
@@ -540,7 +540,8 @@ private fun ReceiptProductEditView(
label = "收货数量",
value = selectedItem!!.receivedNumTemp,
onValueChange = { value ->
viewModel.updateCountInputState(value.isNotEmpty())
viewModel.updateCountInputState(true)
selectedItem?.let {
viewModel.updateSelectedItem(
selectedItem!!.copy(
@@ -557,14 +558,17 @@ private fun ReceiptProductEditView(
RowInputLayout(
label = "收货单价",
value = selectedItem!!.recUnitPriceTaxInTemp ?: "",
value = selectedItem!!.recUnitPriceTaxInTemp,
trailingLabel = "",
isInitUpdate = true,
onValueChange = { value ->
viewModel.updatePriceInputState(value.isNotEmpty())
viewModel.updatePriceInputState(true)
viewModel.updateAmountInputState(false)
selectedItem?.let {
viewModel.updateSelectedItem(
selectedItem!!.copy(
recPriceExItemTemp = "",
recPriceExItem = 0f,
recUnitPriceTaxInTemp = value,
recUnitPriceTaxIn = value.toSafeFloat()
)
@@ -574,14 +578,18 @@ private fun ReceiptProductEditView(
)
RowInputLayout(
label = "收货金额",
value = selectedItem!!.recPriceExItemTemp ?: "",
value = selectedItem!!.recPriceExItemTemp,
trailingLabel = "",
isInitUpdate = true,
onValueChange = { value ->
viewModel.updateAmountInputState(value.isNotEmpty())
viewModel.updateAmountInputState(true)
viewModel.updatePriceInputState(false)
selectedItem?.let {
viewModel.updateSelectedItem(
selectedItem!!.copy(
recUnitPriceTaxInTemp = "",
recUnitPriceTaxIn = 0f,
recPriceExItemTemp = value,
recPriceExItem = value.toSafeFloat()
)
@@ -656,7 +656,7 @@ private fun SelfProductEditView(
isInitUpdate = true,
onValueChange = { value ->
Timber.d("采购数量 onValueChange value = $value")
viewModel.updateCountInputState(value.isNotEmpty())
viewModel.updateCountInputState(true)
selectedItem.let {
viewModel.updateSelectedItem(
selectedItem!!.copy(
@@ -676,11 +676,14 @@ private fun SelfProductEditView(
trailingLabel = "",
isInitUpdate = true,
onValueChange = { value ->
viewModel.updatePriceInputState(value.isNotEmpty())
viewModel.updatePriceInputState(true)
viewModel.updateAmountInputState(false)
selectedItem.let {
Timber.d("goodsUnitPrice 更新 = $value")
viewModel.updateSelectedItem(
selectedItem!!.copy(
goodsPrice = 0.0,
goodsPriceTemp = "",
goodsUnitPriceTemp = value,
goodsUnitPrice = value.toSafeDouble()
)
@@ -694,10 +697,13 @@ private fun SelfProductEditView(
trailingLabel = "",
isInitUpdate = true,
onValueChange = { value ->
viewModel.updateAmountInputState(value.isNotEmpty())
viewModel.updateAmountInputState(true)
viewModel.updatePriceInputState(false)
selectedItem.let {
viewModel.updateSelectedItem(
selectedItem!!.copy(
goodsUnitPrice = 0.0,
goodsUnitPriceTemp = "",
goodsPriceTemp = value,
goodsPrice = value.toSafeDouble()
)
@@ -108,9 +108,7 @@ fun CustomTextField(
onClick: () -> Unit = {}, // 点击
) {
val containerColor = if (enabled) Color.Transparent else Gray_DCDCF0
// var inputValue by remember { mutableStateOf(value) }
var isUserInput by remember { mutableStateOf(false) }
var inputValue by remember(if (isInitUpdate && !isUserInput) value else null) {
var inputValue by remember(if (isInitUpdate) value else null) {
mutableStateOf(value)
}
val focusManager = LocalFocusManager.current
@@ -134,7 +132,6 @@ fun CustomTextField(
textStyle = newTextStyle,
onValueChange = { newValue ->
Timber.d("onValueChange newValue = $newValue")
isUserInput = newValue.isNotEmpty()
when (inputType) {
InputType.Number -> {
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.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
@@ -47,7 +48,9 @@ fun ReceiptUnadjustedListView(
Row(
modifier = Modifier
.fillMaxWidth()
.padding(30.dp)
.padding(horizontal = 60.dp)
.height(84.dp),
verticalAlignment = Alignment.CenterVertically
) {
CustomSingleRightText(
modifier = Modifier.weight(1f),
@@ -89,7 +92,8 @@ fun ReceiptUnadjustedListView(
Row(
modifier = Modifier
.background(color = checkedBg)
.padding(30.dp)
.height(80.dp)
.padding(horizontal = 60.dp)
.clickable {
onItemCheckedClick(it)
}, verticalAlignment = Alignment.CenterVertically
@@ -114,23 +114,26 @@ class ReceiptViewModel @Inject constructor(
*/
fun updateSelectedItem(purchaseOrder: GoodsInfo?) {
if (purchaseOrder != null) {
purchaseOrder.receivedNum.takeIf { it != 0f }?.let { receivedNum ->
// 计算金额 单价不为空,并且金额没有手动输入
// if (purchaseOrder.recUnitPriceTaxIn != null && purchaseOrder.recUnitPriceTaxIn == 0f && !_amountUserInput.value) {
if (purchaseOrder.recUnitPriceTaxIn != null && !_amountUserInput.value) {
if (purchaseOrder.receivedNum != null && purchaseOrder.receivedNum != 0f) {
if (purchaseOrder.recUnitPriceTaxInTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
val result =
receivedNum.times(purchaseOrder.recUnitPriceTaxIn!!)
purchaseOrder.receivedNum!!.times(purchaseOrder.recUnitPriceTaxIn!!)
purchaseOrder.recPriceExItem = result.toSafeFloat()
purchaseOrder.recPriceExItemTemp = result.toFormattedString()
}
// 计算单价 金额不为空,并且单价没有手动输入
// if (purchaseOrder.recPriceExItem != null && purchaseOrder.recPriceExItem == 0f && !_priceUserInput.value) {
if (purchaseOrder.recPriceExItem != null && !_priceUserInput.value) {
} else if (purchaseOrder.recPriceExItemTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
val result =
purchaseOrder.recPriceExItem!!.div(receivedNum)
purchaseOrder.recPriceExItem!!.div(purchaseOrder.receivedNum!!)
purchaseOrder.recUnitPriceTaxIn = result.toSafeFloat()
purchaseOrder.recUnitPriceTaxInTemp = result.toFormattedString()
}
} else {
if (_priceUserInput.value) {
purchaseOrder.recPriceExItem = 0f
purchaseOrder.recPriceExItemTemp = ""
} else if (_amountUserInput.value) {
purchaseOrder.recUnitPriceTaxIn = 0f
purchaseOrder.recUnitPriceTaxInTemp = ""
}
}
} else {
_countUserInput.value = false
@@ -254,31 +257,35 @@ class ReceiptViewModel @Inject constructor(
val finalCount = count.toSafeFloat(currentItem.unitName)
Timber.d("startSensorScale weight = $weight, count = $count, finalCount = $finalCount, consumeValue = $consumeValue, purchaseValue = $purchaseValue")
// 计算单价
val finalPrice = if (count == 0.0) {
val finalPrice = when {
count == 0.0 -> {
0f
} else if (!_countUserInput.value && !_priceUserInput.value) {
if (info.recPriceExItemTemp.isNotEmpty()) {
}
_amountUserInput.value && !_priceUserInput.value -> {
info.recPriceExItem!!.div(count).toSafeFloat()
} else {
0f
}
} else info.recUnitPriceTaxIn ?: 0f
else -> 0f
}
// 计算金额
val finalAmount = if (count == 0.0) {
0f
} else if (!_countUserInput.value && !_amountUserInput.value) {
if (info.recUnitPriceTaxInTemp.isNotEmpty()) {
count.times(info.recUnitPriceTaxIn!!).toSafeFloat()
} else {
val finalAmount = when {
count == 0.0 -> {
0f
}
} else info.recPriceExItem ?: 0f
_priceUserInput.value && !_amountUserInput.value -> {
count.times(info.recUnitPriceTaxIn!!).toSafeFloat()
}
else -> 0f
}
_selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(),
// 收货数量
receivedNumTemp = if (_countUserInput.value) info.receivedNumTemp else count.toFormattedString(),
receivedNum = if (_countUserInput.value) info.receivedNum else finalCount,
receivedNumTemp = count.toFormattedString(),
receivedNum = finalCount,
// 单价
recUnitPriceTaxIn = if (_priceUserInput.value) info.recUnitPriceTaxIn else finalPrice,
recUnitPriceTaxInTemp = if (_priceUserInput.value) info.recUnitPriceTaxInTemp else finalPrice.toFormattedString(),
@@ -113,31 +113,23 @@ class SelfProcurementViewModel @Inject constructor(
val finalPrice =
if (count == 0.0) {
0.0
} else if (!_countUserInput.value && !_priceUserInput.value) {
if (info.goodsPriceTemp.isNotEmpty()) {
} else if (_amountUserInput.value && !_priceUserInput.value) {
info.goodsPrice.div(count).toSafeDouble()
} else {
0.0
}
} else info.goodsUnitPrice
} else 0.0
// 计算金额 单价不为空,不是数量输入 也不是金额输入
val finalAmount =
if (count == 0.0) {
0.0
} else if (!_countUserInput.value && !_amountUserInput.value) {
if (info.goodsUnitPriceTemp.isNotEmpty()) {
} else if (_priceUserInput.value && !_amountUserInput.value) {
count.times(info.goodsUnitPrice).toSafeDouble()
} else {
0.0
}
} else info.goodsPrice
} else 0.0
Timber.d("startSensorScale finalPrice = $finalPrice, finalAmount = $finalAmount ")
_selectedItem.value = info.copy(
goodsWeight = weight.toSafeBigDecimal(),
// 数量
goodsCountTemp = if (_countUserInput.value) info.goodsCountTemp else finalCount.toFormattedString(),
goodsCount = if (_countUserInput.value) info.goodsCount else finalCount,
goodsCountTemp = finalCount.toFormattedString(),
goodsCount = finalCount,
// 单价
goodsUnitPrice = if (_priceUserInput.value) info.goodsUnitPrice else finalPrice,
goodsUnitPriceTemp = if (_priceUserInput.value) info.goodsUnitPriceTemp else finalPrice.toFormattedString(),
@@ -160,25 +152,28 @@ 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) {
if (!_amountUserInput.value) {
if (purchaseOrder.goodsCount != 0.0) {
if (purchaseOrder.goodsUnitPriceTemp.isNotEmpty()) { // 计算金额 单价不为空,并且金额没有手动输入
Timber.d("updateSelectedItem 计算金额")
val result =
receivedNum.times(purchaseOrder.goodsUnitPrice)
purchaseOrder.goodsCount.times(purchaseOrder.goodsUnitPrice)
purchaseOrder.goodsPrice = result.toSafeDouble()
purchaseOrder.goodsPriceTemp = result.toFormattedString()
}
// 计算单价 金额不为空,并且单价没有手动输入
// if (purchaseOrder.goodsPrice == 0.0 && !_priceUserInput.value) {
if (!_priceUserInput.value) {
} else if (purchaseOrder.goodsPriceTemp.isNotEmpty()) { // 计算单价 金额不为空,并且单价没有手动输入
Timber.d("updateSelectedItem 计算单价")
val result =
purchaseOrder.goodsPrice.div(receivedNum)
purchaseOrder.goodsPrice.div(purchaseOrder.goodsCount)
purchaseOrder.goodsUnitPrice = result.toSafeDouble()
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 {
// 重置输入状态