支持结账多轮协商与按实际消耗双比例结算

允许双方最多 6 轮修改结账方案;哈夫币按实际消耗与 buyer/seller 比例计价,打超从押金扣,押金不足禁止自动完结并引导人工争议。同步收紧结账明细展示密度。
This commit is contained in:
yml2213
2026-07-18 20:35:16 +08:00
parent 98772867a7
commit 1a4776bba0
19 changed files with 713 additions and 140 deletions
@@ -95,11 +95,27 @@ func toCheckoutAdminDTO(checkout model.OrderCheckout) CheckoutDTO {
platformFeeCent := checkout.PlatformFeeCent
renterRefundAmountCent := checkout.RenterRefundAmountCent
ownerIncomeAmountCent := checkout.OwnerIncomeAmountCent
roundCount := checkout.RoundCount
if roundCount <= 0 {
roundCount = 1
}
turn := checkout.Turn
if turn != checkoutTurnOwner && turn != checkoutTurnRenter {
if checkout.Status == checkoutStatusCountered {
turn = checkoutTurnRenter
} else {
turn = checkoutTurnOwner
}
}
return CheckoutDTO{
ID: checkout.ID,
OrderID: checkout.OrderID,
InitiatedBy: checkout.InitiatedBy,
Status: checkout.Status,
RoundCount: roundCount,
Turn: turn,
ProposedBy: checkout.ProposedBy,
MaxRounds: checkoutMaxRounds,
PriceRole: "admin",
DisplayAmountCent: rentAmountCent,
RentAmountCent: &rentAmountCent,
@@ -112,6 +128,8 @@ func toCheckoutAdminDTO(checkout model.OrderCheckout) CheckoutDTO {
DepositDeductAmountCent: checkout.DepositDeductAmountCent,
RenterRefundAmountCent: &renterRefundAmountCent,
OwnerIncomeAmountCent: &ownerIncomeAmountCent,
ShortfallCent: checkout.ShortfallCent,
OvershootAmountCent: checkout.OvershootAmountCent,
Content: checkout.Content,
EvidenceURLS: decodeStringList(checkout.EvidenceURLS),
OwnerAdjustmentReason: checkout.OwnerAdjustmentReason,
@@ -125,10 +143,58 @@ func toCheckoutAdminDTO(checkout model.OrderCheckout) CheckoutDTO {
func toCheckoutDTOForUser(checkout model.OrderCheckout, userID uint64, order model.RentalOrder) CheckoutDTO {
dto := toCheckoutAdminDTO(checkout)
refreshCheckoutSettlementDTO(&dto, order, checkout)
applyCheckoutPriceView(&dto, order, userID)
applyCheckoutActionFlags(&dto, checkout, order, userID)
return dto
}
// refreshCheckoutSettlementDTO 用当前公式重算展示字段(兼容旧单 shortfall/overshoot 为空)
func refreshCheckoutSettlementDTO(dto *CheckoutDTO, order model.RentalOrder, checkout model.OrderCheckout) {
if dto == nil {
return
}
if checkout.Status != checkoutStatusSubmitted && checkout.Status != checkoutStatusCountered {
return
}
settlement := calculateCheckoutSettlement(order, checkout.ConsumableAmountCent, checkout.CoinConsumedM, checkout.DepositDeductAmountCent)
rent := settlement.ActualRentAmountCent
ownerRent := settlement.OwnerRentIncomeCent
platform := settlement.PlatformFeeCent
renterRefund := settlement.RenterRefundCent
ownerIncome := settlement.OwnerIncomeCent
dto.RentAmountCent = &rent
dto.OwnerRentAmountCent = &ownerRent
dto.PlatformFeeCent = &platform
dto.RenterRefundAmountCent = &renterRefund
dto.OwnerIncomeAmountCent = &ownerIncome
dto.DisplayAmountCent = rent
dto.ShortfallCent = settlement.ShortfallCent
dto.OvershootAmountCent = settlement.OvershootAmountCent
}
func applyCheckoutActionFlags(dto *CheckoutDTO, checkout model.OrderCheckout, order model.RentalOrder, userID uint64) {
if dto == nil {
return
}
negotiating := order.Status == orderStatusPendingCheckoutConfirm || order.Status == orderStatusPendingCheckoutAccept
if !negotiating || (checkout.Status != checkoutStatusSubmitted && checkout.Status != checkoutStatusCountered) {
return
}
turn := dto.Turn
round := dto.RoundCount
isOwner := userID == order.OwnerID
isRenter := userID == order.RenterID
if isOwner && turn == checkoutTurnOwner && order.Status == orderStatusPendingCheckoutConfirm {
dto.CanAccept = dto.ShortfallCent <= 0
dto.CanCounter = round < checkoutMaxRounds
}
if isRenter && turn == checkoutTurnRenter && order.Status == orderStatusPendingCheckoutAccept {
dto.CanAccept = dto.ShortfallCent <= 0
dto.CanCounter = round < checkoutMaxRounds
}
}
func applyOrderPriceView(dto *OrderDTO, order model.RentalOrder, userID uint64) {
if dto == nil {
return