Order模块:完成分字段重构

核心改造:
1. DTO层全部改为*Cent int64字段(OrderDTO/CheckoutDTO/RefundStatusDTO)
2. 内部结构体orderPricing和checkoutSettlement改为分字段
3. calculateCheckoutSettlement函数改为返回分单位
4. 所有wallet.AppendEntries调用改为AmountCent
5. toAdminDTO/toCheckoutAdminDTO转换函数使用*Cent字段
6. applyOrderPriceView/applyCheckoutPriceView使用分字段
7. buildOrderPricing返回分单位
8. 订单取消/关闭/退款使用分字段计算

技术细节:
- 删除了3处float64金额相加后转分的逻辑
- calculateCheckoutSettlement内部仍用元计算保持兼容性,最后转为分
- 新增effectiveDepositOriginalAmountCent辅助函数
- buildRefundStatusDTO使用TotalAmountCent
- 编译验证通过 
This commit is contained in:
yml
2026-06-09 13:54:04 +08:00
parent 01909ee7e5
commit d803089890
4 changed files with 283 additions and 233 deletions
@@ -0,0 +1,35 @@
package adminuser
import "testing"
func TestDepositFreeQuotaAmountCent(t *testing.T) {
tests := []struct {
name string
req DepositFreeQuotaRequest
want int64
}{
{
name: "优先使用分字段",
req: DepositFreeQuotaRequest{AmountCent: 1234, Amount: 99},
want: 1234,
},
{
name: "缺少分字段时回退元字段",
req: DepositFreeQuotaRequest{Amount: 12.34},
want: 1234,
},
{
name: "负分拒绝",
req: DepositFreeQuotaRequest{AmountCent: -1, Amount: 12.34},
want: -1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := depositFreeQuotaAmountCent(tt.req); got != tt.want {
t.Fatalf("depositFreeQuotaAmountCent() = %d, want %d", got, tt.want)
}
})
}
}
+55 -55
View File
@@ -9,36 +9,36 @@ import (
) )
type OrderDTO struct { type OrderDTO struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
OrderNo string `json:"order_no"` OrderNo string `json:"order_no"`
ListingID uint64 `json:"listing_id"` ListingID uint64 `json:"listing_id"`
ListingNo string `json:"listing_no"` ListingNo string `json:"listing_no"`
AccountID uint64 `json:"account_id"` AccountID uint64 `json:"account_id"`
OwnerID uint64 `json:"owner_id"` OwnerID uint64 `json:"owner_id"`
RenterID uint64 `json:"renter_id"` RenterID uint64 `json:"renter_id"`
OwnerPhone string `json:"owner_phone,omitempty"` OwnerPhone string `json:"owner_phone,omitempty"`
RenterPhone string `json:"renter_phone,omitempty"` RenterPhone string `json:"renter_phone,omitempty"`
Title string `json:"title"` Title string `json:"title"`
ServerRegion string `json:"server_region"` ServerRegion string `json:"server_region"`
LoginPlatform string `json:"login_platform"` LoginPlatform string `json:"login_platform"`
RentedAt *time.Time `json:"rented_at"` RentedAt *time.Time `json:"rented_at"`
EstimatedDurationHours int `json:"estimated_duration_hours"` EstimatedDurationHours int `json:"estimated_duration_hours"`
PriceRole string `json:"price_role,omitempty"` PriceRole string `json:"price_role,omitempty"`
DisplayAmount float64 `json:"display_amount"` DisplayAmountCent int64 `json:"display_amount_cent"`
RentAmount *float64 `json:"rent_amount,omitempty"` RentAmountCent *int64 `json:"rent_amount_cent,omitempty"`
OwnerRentAmount *float64 `json:"owner_rent_amount,omitempty"` OwnerRentAmountCent *int64 `json:"owner_rent_amount_cent,omitempty"`
DepositAmount float64 `json:"deposit_amount"` DepositAmountCent int64 `json:"deposit_amount_cent"`
DepositOriginalAmount float64 `json:"deposit_original_amount"` DepositOriginalAmountCent int64 `json:"deposit_original_amount_cent"`
DepositWaivedAmount float64 `json:"deposit_waived_amount"` DepositWaivedAmountCent int64 `json:"deposit_waived_amount_cent"`
PlatformFee *float64 `json:"platform_fee,omitempty"` PlatformFeeCent *int64 `json:"platform_fee_cent,omitempty"`
AccountSnapshot datatypes.JSON `json:"account_snapshot"` AccountSnapshot datatypes.JSON `json:"account_snapshot"`
Status string `json:"status"` Status string `json:"status"`
HandoffStatus string `json:"handoff_status"` HandoffStatus string `json:"handoff_status"`
SettlementStatus string `json:"settlement_status"` SettlementStatus string `json:"settlement_status"`
Checkout *CheckoutDTO `json:"checkout,omitempty"` Checkout *CheckoutDTO `json:"checkout,omitempty"`
PaymentDeadlineAt *time.Time `json:"payment_deadline_at,omitempty"` PaymentDeadlineAt *time.Time `json:"payment_deadline_at,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type CreateRequest struct { type CreateRequest struct {
@@ -89,7 +89,7 @@ type RefundStatusDTO struct {
RefundStatus string `json:"refund_status"` RefundStatus string `json:"refund_status"`
RefundAmountCent int64 `json:"refund_amount_cent"` RefundAmountCent int64 `json:"refund_amount_cent"`
RefundedAt *time.Time `json:"refunded_at,omitempty"` RefundedAt *time.Time `json:"refunded_at,omitempty"`
TotalAmount float64 `json:"total_amount"` TotalAmountCent int64 `json:"total_amount_cent"`
} }
type HandoffRecordDTO struct { type HandoffRecordDTO struct {
@@ -105,28 +105,28 @@ type HandoffRecordDTO struct {
} }
type CheckoutDTO struct { type CheckoutDTO struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
OrderID uint64 `json:"order_id"` OrderID uint64 `json:"order_id"`
InitiatedBy uint64 `json:"initiated_by"` InitiatedBy uint64 `json:"initiated_by"`
Status string `json:"status"` Status string `json:"status"`
PriceRole string `json:"price_role,omitempty"` PriceRole string `json:"price_role,omitempty"`
DisplayAmount float64 `json:"display_amount"` DisplayAmountCent int64 `json:"display_amount_cent"`
RentAmount *float64 `json:"rent_amount,omitempty"` RentAmountCent *int64 `json:"rent_amount_cent,omitempty"`
OwnerRentAmount *float64 `json:"owner_rent_amount,omitempty"` OwnerRentAmountCent *int64 `json:"owner_rent_amount_cent,omitempty"`
PlatformFee *float64 `json:"platform_fee,omitempty"` PlatformFeeCent *int64 `json:"platform_fee_cent,omitempty"`
DepositAmount float64 `json:"deposit_amount"` DepositAmountCent int64 `json:"deposit_amount_cent"`
ConsumableAmount float64 `json:"consumable_amount"` ConsumableAmountCent int64 `json:"consumable_amount_cent"`
CoinConsumedM float64 `json:"coin_consumed_m"` CoinConsumedM float64 `json:"coin_consumed_m"`
OtherAmount float64 `json:"other_amount"` OtherAmountCent int64 `json:"other_amount_cent"`
DepositDeductAmount float64 `json:"deposit_deduct_amount"` DepositDeductAmountCent int64 `json:"deposit_deduct_amount_cent"`
RenterRefundAmount *float64 `json:"renter_refund_amount,omitempty"` RenterRefundAmountCent *int64 `json:"renter_refund_amount_cent,omitempty"`
OwnerIncomeAmount *float64 `json:"owner_income_amount,omitempty"` OwnerIncomeAmountCent *int64 `json:"owner_income_amount_cent,omitempty"`
Content string `json:"content"` Content string `json:"content"`
EvidenceURLS []string `json:"evidence_urls"` EvidenceURLS []string `json:"evidence_urls"`
OwnerAdjustmentReason string `json:"owner_adjustment_reason"` OwnerAdjustmentReason string `json:"owner_adjustment_reason"`
OwnerAdjustedAt *time.Time `json:"owner_adjusted_at"` OwnerAdjustedAt *time.Time `json:"owner_adjusted_at"`
RenterConfirmedAt *time.Time `json:"renter_confirmed_at"` RenterConfirmedAt *time.Time `json:"renter_confirmed_at"`
RenterRejectedAt *time.Time `json:"renter_rejected_at"` RenterRejectedAt *time.Time `json:"renter_rejected_at"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
+192 -178
View File
@@ -53,20 +53,20 @@ func (r *Repository) SetRefundFunc(fn RefundFunc) {
} }
type orderPricing struct { type orderPricing struct {
RentAmount float64 RentAmountCent int64
OwnerRentAmount float64 OwnerRentAmountCent int64
PlatformFee float64 PlatformFeeCent int64
} }
type checkoutSettlement struct { type checkoutSettlement struct {
OwnerRentIncome float64 OwnerRentIncomeCent int64
DepositCompensation float64 DepositCompensationCent int64
OwnerIncome float64 OwnerIncomeCent int64
RentRefund float64 RentRefundCent int64
DepositRefund float64 DepositRefundCent int64
RenterRefund float64 RenterRefundCent int64
PlatformFee float64 PlatformFeeCent int64
ActualRentAmount float64 ActualRentAmountCent int64
} }
func orderDurationHours(order model.RentalOrder) int { func orderDurationHours(order model.RentalOrder) int {
@@ -90,9 +90,9 @@ func buildOrderPricing(listing model.RentalListing, account model.GameAccount) o
platformFee = 0 platformFee = 0
} }
return orderPricing{ return orderPricing{
RentAmount: rentAmount, RentAmountCent: int64(math.Round(rentAmount * 100)),
OwnerRentAmount: roundMoney(ownerRentAmount), OwnerRentAmountCent: int64(math.Round(ownerRentAmount * 100)),
PlatformFee: roundMoney(platformFee), PlatformFeeCent: int64(math.Round(platformFee * 100)),
} }
} }
@@ -179,22 +179,22 @@ func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, erro
return err return err
} }
order := model.RentalOrder{ order := model.RentalOrder{
OrderNo: orderNo, OrderNo: orderNo,
ListingID: listing.ID, ListingID: listing.ID,
AccountID: listing.AccountID, AccountID: listing.AccountID,
OwnerID: listing.OwnerID, OwnerID: listing.OwnerID,
RenterID: renterID, RenterID: renterID,
EstimatedDurationHours: rentHours, EstimatedDurationHours: rentHours,
RentAmount: pricing.RentAmount, RentAmountCent: pricing.RentAmountCent,
OwnerRentAmount: pricing.OwnerRentAmount, OwnerRentAmountCent: pricing.OwnerRentAmountCent,
DepositAmount: paidDepositAmount, DepositAmountCent: int64(math.Round(paidDepositAmount * 100)),
DepositOriginalAmount: depositOriginalAmount, DepositOriginalAmountCent: int64(math.Round(depositOriginalAmount * 100)),
DepositWaivedAmount: waivedDepositAmount, DepositWaivedAmountCent: int64(math.Round(waivedDepositAmount * 100)),
PlatformFee: pricing.PlatformFee, PlatformFeeCent: pricing.PlatformFeeCent,
AccountSnapshot: snapshot, AccountSnapshot: snapshot,
Status: "pending_payment", Status: "pending_payment",
HandoffStatus: "none", HandoffStatus: "none",
SettlementStatus: "unsettled", SettlementStatus: "unsettled",
} }
if err := tx.Create(&order).Error; err != nil { if err := tx.Create(&order).Error; err != nil {
return err return err
@@ -368,7 +368,7 @@ func (r *Repository) Cancel(userID uint64, orderID uint64) error {
order.HandoffStatus = "cancelled" order.HandoffStatus = "cancelled"
orderID := order.ID orderID := order.ID
if beforeStatus == "pending_handoff" { if beforeStatus == "pending_handoff" {
totalCent := int64(math.Round((order.RentAmount + order.DepositAmount) * 100)) totalCent := order.RentAmountCent + order.DepositAmountCent
action, err := r.prepareRefund(&order, totalCent, "cancel_refund", "取消订单原路退款") action, err := r.prepareRefund(&order, totalCent, "cancel_refund", "取消订单原路退款")
if err != nil { if err != nil {
return err return err
@@ -690,10 +690,10 @@ func (r *Repository) CounterCheckout(userID uint64, orderID uint64, req CounterC
return nil, err return nil, err
} }
dto := toCheckoutDTOForUser(*checkout, userID, model.RentalOrder{ dto := toCheckoutDTOForUser(*checkout, userID, model.RentalOrder{
OwnerID: userID, OwnerID: userID,
RentAmount: checkout.RentAmount, RentAmountCent: int64(math.Round(checkout.RentAmount * 100)),
OwnerRentAmount: checkout.OwnerRentAmount, OwnerRentAmountCent: int64(math.Round(checkout.OwnerRentAmount * 100)),
DepositAmount: checkout.DepositAmount, DepositAmountCent: int64(math.Round(checkout.DepositAmount * 100)),
}) })
return &dto, nil return &dto, nil
} }
@@ -838,7 +838,7 @@ func (r *Repository) AdminClose(adminID uint64, orderID uint64, req AdminActionR
listing.InTransaction = false listing.InTransaction = false
account.Status = "offline" account.Status = "offline"
if beforeOrderStatus != "pending_payment" { if beforeOrderStatus != "pending_payment" {
totalCent := int64(math.Round((order.RentAmount + order.DepositAmount) * 100)) totalCent := order.RentAmountCent + order.DepositAmountCent
action, err := r.prepareRefund(order, totalCent, "admin_close_refund", "客服关闭订单原路退款") action, err := r.prepareRefund(order, totalCent, "admin_close_refund", "客服关闭订单原路退款")
if err != nil { if err != nil {
return err return err
@@ -976,7 +976,7 @@ func (r *Repository) AdminRefund(orderID uint64) (*RefundStatusDTO, error) {
if r.refundFunc == nil { if r.refundFunc == nil {
return nil, ErrDependencyUnavailable return nil, ErrDependencyUnavailable
} }
totalCent := int64(math.Round((order.RentAmount + order.DepositAmount) * 100)) totalCent := order.RentAmountCent + order.DepositAmountCent
if totalCent <= 0 { if totalCent <= 0 {
return nil, ErrInvalidCheckoutAmount return nil, ErrInvalidCheckoutAmount
} }
@@ -1011,7 +1011,7 @@ func (r *Repository) buildRefundStatusDTO(order *model.RentalOrder) *RefundStatu
RefundStatus: order.RefundStatus, RefundStatus: order.RefundStatus,
RefundAmountCent: order.RefundAmountCent, RefundAmountCent: order.RefundAmountCent,
RefundedAt: order.RefundedAt, RefundedAt: order.RefundedAt,
TotalAmount: order.RentAmount + order.DepositAmount, TotalAmountCent: order.RentAmountCent + order.DepositAmountCent,
} }
} }
@@ -1049,24 +1049,24 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che
// 卖家收入进入站内钱包;租客资金不进入站内钱包。 // 卖家收入进入站内钱包;租客资金不进入站内钱包。
var ownerEntries []wallet.Entry var ownerEntries []wallet.Entry
if settlement.OwnerRentIncome > 0 { if settlement.OwnerRentIncomeCent > 0 {
ownerEntries = append(ownerEntries, wallet.Entry{ ownerEntries = append(ownerEntries, wallet.Entry{
UserID: order.OwnerID, UserID: order.OwnerID,
OrderID: &orderID, OrderID: &orderID,
Direction: "in", Direction: "in",
Amount: settlement.OwnerRentIncome, AmountCent: settlement.OwnerRentIncomeCent,
BalanceType: "available", BalanceType: "available",
BizType: "owner_income", BizType: "owner_income",
BizNo: order.OrderNo, BizNo: order.OrderNo,
Remark: "订单结账租金收入", Remark: "订单结账租金收入",
}) })
} }
if settlement.DepositCompensation > 0 { if settlement.DepositCompensationCent > 0 {
ownerEntries = append(ownerEntries, wallet.Entry{ ownerEntries = append(ownerEntries, wallet.Entry{
UserID: order.OwnerID, UserID: order.OwnerID,
OrderID: &orderID, OrderID: &orderID,
Direction: "in", Direction: "in",
Amount: settlement.DepositCompensation, AmountCent: settlement.DepositCompensationCent,
BalanceType: "available", BalanceType: "available",
BizType: "deposit_compensation", BizType: "deposit_compensation",
BizNo: order.OrderNo, BizNo: order.OrderNo,
@@ -1080,21 +1080,20 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che
} }
var refund *refundAction var refund *refundAction
renterRefundTotal := settlement.RentRefund + settlement.DepositRefund renterRefundTotalCent := settlement.RentRefundCent + settlement.DepositRefundCent
if renterRefundTotal > 0 { if renterRefundTotalCent > 0 {
refundCent := int64(math.Round(renterRefundTotal * 100)) action, err := r.prepareRefund(order, renterRefundTotalCent, "checkout_refund", "结账退款原路退还")
action, err := r.prepareRefund(order, refundCent, "checkout_refund", "结账退款原路退还")
if err != nil { if err != nil {
return nil, err return nil, err
} }
refund = action refund = action
} }
checkout.RentAmount = settlement.ActualRentAmount checkout.RentAmount = float64(settlement.ActualRentAmountCent) / 100
checkout.OwnerRentAmount = settlement.OwnerRentIncome checkout.OwnerRentAmount = float64(settlement.OwnerRentIncomeCent) / 100
checkout.PlatformFee = settlement.PlatformFee checkout.PlatformFee = float64(settlement.PlatformFeeCent) / 100
checkout.RenterRefundAmount = settlement.RenterRefund checkout.RenterRefundAmount = float64(settlement.RenterRefundCent) / 100
checkout.OwnerIncomeAmount = settlement.OwnerIncome checkout.OwnerIncomeAmount = float64(settlement.OwnerIncomeCent) / 100
if err := notification.Append(tx, if err := notification.Append(tx,
notification.Entry{ notification.Entry{
UserID: order.RenterID, UserID: order.RenterID,
@@ -1235,7 +1234,8 @@ func buildCheckout(order model.RentalOrder, initiatedBy uint64, status string, c
if useExplicitDeduct { if useExplicitDeduct {
deductAmount = explicitDeduct deductAmount = explicitDeduct
} }
if deductAmount > order.DepositAmount { depositAmountFromCent := float64(order.DepositAmountCent) / 100
if deductAmount > depositAmountFromCent {
return model.OrderCheckout{}, ErrInvalidCheckoutAmount return model.OrderCheckout{}, ErrInvalidCheckoutAmount
} }
settlement := calculateCheckoutSettlement(order, consumableAmount, roundQuantity(coinConsumedM), deductAmount) settlement := calculateCheckoutSettlement(order, consumableAmount, roundQuantity(coinConsumedM), deductAmount)
@@ -1247,16 +1247,16 @@ func buildCheckout(order model.RentalOrder, initiatedBy uint64, status string, c
OrderID: order.ID, OrderID: order.ID,
InitiatedBy: initiatedBy, InitiatedBy: initiatedBy,
Status: status, Status: status,
RentAmount: settlement.ActualRentAmount, RentAmount: float64(settlement.ActualRentAmountCent) / 100,
OwnerRentAmount: settlement.OwnerRentIncome, OwnerRentAmount: float64(settlement.OwnerRentIncomeCent) / 100,
PlatformFee: settlement.PlatformFee, PlatformFee: float64(settlement.PlatformFeeCent) / 100,
DepositAmount: order.DepositAmount, DepositAmount: depositAmountFromCent,
ConsumableAmount: consumableAmount, ConsumableAmount: consumableAmount,
CoinConsumedM: roundQuantity(coinConsumedM), CoinConsumedM: roundQuantity(coinConsumedM),
OtherAmount: otherAmount, OtherAmount: otherAmount,
DepositDeductAmount: roundMoney(deductAmount), DepositDeductAmount: roundMoney(deductAmount),
RenterRefundAmount: settlement.RenterRefund, RenterRefundAmount: float64(settlement.RenterRefundCent) / 100,
OwnerIncomeAmount: settlement.OwnerIncome, OwnerIncomeAmount: float64(settlement.OwnerIncomeCent) / 100,
Content: content, Content: content,
EvidenceURLS: evidence, EvidenceURLS: evidence,
}, nil }, nil
@@ -1267,19 +1267,24 @@ func buildCheckoutSettlement(order model.RentalOrder, checkout *model.OrderCheck
} }
func calculateCheckoutSettlement(order model.RentalOrder, consumableAmount float64, coinConsumedM float64, depositDeductAmount float64) checkoutSettlement { func calculateCheckoutSettlement(order model.RentalOrder, consumableAmount float64, coinConsumedM float64, depositDeductAmount float64) checkoutSettlement {
// 从分字段读取,转为元进行计算(保持现有逻辑兼容性)
orderRentAmount := float64(order.RentAmountCent) / 100
orderOwnerRentAmount := float64(order.OwnerRentAmountCent) / 100
orderDepositAmount := float64(order.DepositAmountCent) / 100
buyerCoinBasePrice := readOrderSnapshotPrice(order.AccountSnapshot, "buyer_coin_base_price") buyerCoinBasePrice := readOrderSnapshotPrice(order.AccountSnapshot, "buyer_coin_base_price")
if buyerCoinBasePrice <= 0 || buyerCoinBasePrice > order.RentAmount { if buyerCoinBasePrice <= 0 || buyerCoinBasePrice > orderRentAmount {
buyerCoinBasePrice = order.RentAmount buyerCoinBasePrice = orderRentAmount
} }
sellerCoinBasePrice := readOrderSnapshotPrice(order.AccountSnapshot, "seller_coin_base_price") sellerCoinBasePrice := readOrderSnapshotPrice(order.AccountSnapshot, "seller_coin_base_price")
if sellerCoinBasePrice <= 0 || sellerCoinBasePrice > order.OwnerRentAmount { if sellerCoinBasePrice <= 0 || sellerCoinBasePrice > orderOwnerRentAmount {
sellerCoinBasePrice = order.OwnerRentAmount sellerCoinBasePrice = orderOwnerRentAmount
} }
prepaidConsumablePrice := readOrderSnapshotPrice(order.AccountSnapshot, "consumable_price") prepaidConsumablePrice := readOrderSnapshotPrice(order.AccountSnapshot, "consumable_price")
if prepaidConsumablePrice <= 0 || prepaidConsumablePrice > order.RentAmount-buyerCoinBasePrice { if prepaidConsumablePrice <= 0 || prepaidConsumablePrice > orderRentAmount-buyerCoinBasePrice {
prepaidConsumablePrice = maxMoney(order.RentAmount-buyerCoinBasePrice, 0) prepaidConsumablePrice = maxMoney(orderRentAmount-buyerCoinBasePrice, 0)
} }
prepaidOwnerConsumablePrice := maxMoney(order.OwnerRentAmount-sellerCoinBasePrice, 0) prepaidOwnerConsumablePrice := maxMoney(orderOwnerRentAmount-sellerCoinBasePrice, 0)
totalCoinM := readOrderSnapshotCoinM(order.AccountSnapshot) totalCoinM := readOrderSnapshotCoinM(order.AccountSnapshot)
coinUseRatio := 1.0 coinUseRatio := 1.0
if totalCoinM > 0 { if totalCoinM > 0 {
@@ -1293,20 +1298,22 @@ func calculateCheckoutSettlement(order model.RentalOrder, consumableAmount float
consumableUseRatio = minRatio(maxRatio(usedBuyerConsumablePrice/prepaidConsumablePrice, 0), 1) consumableUseRatio = minRatio(maxRatio(usedBuyerConsumablePrice/prepaidConsumablePrice, 0), 1)
} }
usedOwnerConsumablePrice := roundMoney(prepaidOwnerConsumablePrice * consumableUseRatio) usedOwnerConsumablePrice := roundMoney(prepaidOwnerConsumablePrice * consumableUseRatio)
actualRentAmount := minMoney(roundMoney(usedBuyerCoinPrice+usedBuyerConsumablePrice), order.RentAmount) actualRentAmount := minMoney(roundMoney(usedBuyerCoinPrice+usedBuyerConsumablePrice), orderRentAmount)
ownerRentIncome := minMoney(roundMoney(usedOwnerCoinPrice+usedOwnerConsumablePrice), order.OwnerRentAmount) ownerRentIncome := minMoney(roundMoney(usedOwnerCoinPrice+usedOwnerConsumablePrice), orderOwnerRentAmount)
depositCompensation := minMoney(roundMoney(depositDeductAmount), order.DepositAmount) depositCompensation := minMoney(roundMoney(depositDeductAmount), orderDepositAmount)
rentRefund := maxMoney(order.RentAmount-actualRentAmount, 0) rentRefund := maxMoney(orderRentAmount-actualRentAmount, 0)
depositRefund := maxMoney(order.DepositAmount-depositCompensation, 0) depositRefund := maxMoney(orderDepositAmount-depositCompensation, 0)
// 最后转换为分返回
return checkoutSettlement{ return checkoutSettlement{
OwnerRentIncome: ownerRentIncome, OwnerRentIncomeCent: int64(math.Round(ownerRentIncome * 100)),
DepositCompensation: depositCompensation, DepositCompensationCent: int64(math.Round(depositCompensation * 100)),
OwnerIncome: roundMoney(ownerRentIncome + depositCompensation), OwnerIncomeCent: int64(math.Round((ownerRentIncome + depositCompensation) * 100)),
RentRefund: rentRefund, RentRefundCent: int64(math.Round(rentRefund * 100)),
DepositRefund: depositRefund, DepositRefundCent: int64(math.Round(depositRefund * 100)),
RenterRefund: roundMoney(rentRefund + depositRefund), RenterRefundCent: int64(math.Round((rentRefund + depositRefund) * 100)),
PlatformFee: maxMoney(actualRentAmount-ownerRentIncome, 0), PlatformFeeCent: int64(math.Round(maxMoney(actualRentAmount-ownerRentIncome, 0) * 100)),
ActualRentAmount: actualRentAmount, ActualRentAmountCent: int64(math.Round(actualRentAmount * 100)),
} }
} }
@@ -1445,38 +1452,38 @@ type orderRow struct {
func (row orderRow) toAdminDTO() OrderDTO { func (row orderRow) toAdminDTO() OrderDTO {
rentedAt := row.RentedAt rentedAt := row.RentedAt
durationHours := orderDurationHours(row.RentalOrder) durationHours := orderDurationHours(row.RentalOrder)
rentAmount := row.RentAmount rentAmountCent := row.RentAmountCent
ownerRentAmount := row.OwnerRentAmount ownerRentAmountCent := row.OwnerRentAmountCent
platformFee := row.PlatformFee platformFeeCent := row.PlatformFeeCent
return OrderDTO{ return OrderDTO{
ID: row.ID, ID: row.ID,
OrderNo: row.OrderNo, OrderNo: row.OrderNo,
ListingID: row.ListingID, ListingID: row.ListingID,
ListingNo: row.ListingNo, ListingNo: row.ListingNo,
AccountID: row.AccountID, AccountID: row.AccountID,
OwnerID: row.OwnerID, OwnerID: row.OwnerID,
RenterID: row.RenterID, RenterID: row.RenterID,
OwnerPhone: row.OwnerPhone, OwnerPhone: row.OwnerPhone,
RenterPhone: row.RenterPhone, RenterPhone: row.RenterPhone,
Title: row.Title, Title: row.Title,
ServerRegion: row.ServerRegion, ServerRegion: row.ServerRegion,
LoginPlatform: row.LoginPlatform, LoginPlatform: row.LoginPlatform,
RentedAt: rentedAt, RentedAt: rentedAt,
EstimatedDurationHours: durationHours, EstimatedDurationHours: durationHours,
PriceRole: "admin", PriceRole: "admin",
DisplayAmount: row.RentAmount, DisplayAmountCent: row.RentAmountCent,
RentAmount: &rentAmount, RentAmountCent: &rentAmountCent,
OwnerRentAmount: &ownerRentAmount, OwnerRentAmountCent: &ownerRentAmountCent,
DepositAmount: row.DepositAmount, DepositAmountCent: row.DepositAmountCent,
DepositOriginalAmount: effectiveDepositOriginalAmount(row.RentalOrder), DepositOriginalAmountCent: effectiveDepositOriginalAmountCent(row.RentalOrder),
DepositWaivedAmount: row.DepositWaivedAmount, DepositWaivedAmountCent: row.DepositWaivedAmountCent,
PlatformFee: &platformFee, PlatformFeeCent: &platformFeeCent,
AccountSnapshot: row.AccountSnapshot, AccountSnapshot: row.AccountSnapshot,
Status: row.Status, Status: row.Status,
HandoffStatus: row.HandoffStatus, HandoffStatus: row.HandoffStatus,
SettlementStatus: row.SettlementStatus, SettlementStatus: row.SettlementStatus,
CreatedAt: row.CreatedAt, CreatedAt: row.CreatedAt,
UpdatedAt: row.UpdatedAt, UpdatedAt: row.UpdatedAt,
} }
} }
@@ -1507,37 +1514,44 @@ func effectiveDepositOriginalAmount(order model.RentalOrder) float64 {
return order.DepositAmount return order.DepositAmount
} }
func effectiveDepositOriginalAmountCent(order model.RentalOrder) int64 {
if order.DepositOriginalAmountCent > 0 {
return order.DepositOriginalAmountCent
}
return order.DepositAmountCent
}
func toCheckoutAdminDTO(checkout model.OrderCheckout) CheckoutDTO { func toCheckoutAdminDTO(checkout model.OrderCheckout) CheckoutDTO {
rentAmount := checkout.RentAmount rentAmountCent := int64(math.Round(checkout.RentAmount * 100))
ownerRentAmount := checkout.OwnerRentAmount ownerRentAmountCent := int64(math.Round(checkout.OwnerRentAmount * 100))
platformFee := checkout.PlatformFee platformFeeCent := int64(math.Round(checkout.PlatformFee * 100))
renterRefundAmount := checkout.RenterRefundAmount renterRefundAmountCent := int64(math.Round(checkout.RenterRefundAmount * 100))
ownerIncomeAmount := checkout.OwnerIncomeAmount ownerIncomeAmountCent := int64(math.Round(checkout.OwnerIncomeAmount * 100))
return CheckoutDTO{ return CheckoutDTO{
ID: checkout.ID, ID: checkout.ID,
OrderID: checkout.OrderID, OrderID: checkout.OrderID,
InitiatedBy: checkout.InitiatedBy, InitiatedBy: checkout.InitiatedBy,
Status: checkout.Status, Status: checkout.Status,
PriceRole: "admin", PriceRole: "admin",
DisplayAmount: checkout.RentAmount, DisplayAmountCent: rentAmountCent,
RentAmount: &rentAmount, RentAmountCent: &rentAmountCent,
OwnerRentAmount: &ownerRentAmount, OwnerRentAmountCent: &ownerRentAmountCent,
PlatformFee: &platformFee, PlatformFeeCent: &platformFeeCent,
DepositAmount: checkout.DepositAmount, DepositAmountCent: int64(math.Round(checkout.DepositAmount * 100)),
ConsumableAmount: checkout.ConsumableAmount, ConsumableAmountCent: int64(math.Round(checkout.ConsumableAmount * 100)),
CoinConsumedM: checkout.CoinConsumedM, CoinConsumedM: checkout.CoinConsumedM,
OtherAmount: checkout.OtherAmount, OtherAmountCent: int64(math.Round(checkout.OtherAmount * 100)),
DepositDeductAmount: checkout.DepositDeductAmount, DepositDeductAmountCent: int64(math.Round(checkout.DepositDeductAmount * 100)),
RenterRefundAmount: &renterRefundAmount, RenterRefundAmountCent: &renterRefundAmountCent,
OwnerIncomeAmount: &ownerIncomeAmount, OwnerIncomeAmountCent: &ownerIncomeAmountCent,
Content: checkout.Content, Content: checkout.Content,
EvidenceURLS: decodeStringList(checkout.EvidenceURLS), EvidenceURLS: decodeStringList(checkout.EvidenceURLS),
OwnerAdjustmentReason: checkout.OwnerAdjustmentReason, OwnerAdjustmentReason: checkout.OwnerAdjustmentReason,
OwnerAdjustedAt: checkout.OwnerAdjustedAt, OwnerAdjustedAt: checkout.OwnerAdjustedAt,
RenterConfirmedAt: checkout.RenterConfirmedAt, RenterConfirmedAt: checkout.RenterConfirmedAt,
RenterRejectedAt: checkout.RenterRejectedAt, RenterRejectedAt: checkout.RenterRejectedAt,
CreatedAt: checkout.CreatedAt, CreatedAt: checkout.CreatedAt,
UpdatedAt: checkout.UpdatedAt, UpdatedAt: checkout.UpdatedAt,
} }
} }
@@ -1551,30 +1565,30 @@ func applyOrderPriceView(dto *OrderDTO, order model.RentalOrder, userID uint64)
if dto == nil { if dto == nil {
return return
} }
dto.PlatformFee = nil dto.PlatformFeeCent = nil
switch { switch {
case userID == order.OwnerID: case userID == order.OwnerID:
ownerAmount := order.OwnerRentAmount ownerAmountCent := order.OwnerRentAmountCent
if ownerAmount <= 0 { if ownerAmountCent <= 0 {
ownerAmount = order.RentAmount ownerAmountCent = order.RentAmountCent
} }
dto.PriceRole = "owner" dto.PriceRole = "owner"
dto.DisplayAmount = ownerAmount dto.DisplayAmountCent = ownerAmountCent
dto.RentAmount = nil dto.RentAmountCent = nil
dto.OwnerRentAmount = &ownerAmount dto.OwnerRentAmountCent = &ownerAmountCent
sanitizeOrderSnapshot(&dto.AccountSnapshot, "owner") sanitizeOrderSnapshot(&dto.AccountSnapshot, "owner")
case userID == order.RenterID: case userID == order.RenterID:
rentAmount := order.RentAmount rentAmountCent := order.RentAmountCent
dto.PriceRole = "renter" dto.PriceRole = "renter"
dto.DisplayAmount = rentAmount dto.DisplayAmountCent = rentAmountCent
dto.RentAmount = &rentAmount dto.RentAmountCent = &rentAmountCent
dto.OwnerRentAmount = nil dto.OwnerRentAmountCent = nil
sanitizeOrderSnapshot(&dto.AccountSnapshot, "renter") sanitizeOrderSnapshot(&dto.AccountSnapshot, "renter")
default: default:
dto.PriceRole = "" dto.PriceRole = ""
dto.DisplayAmount = 0 dto.DisplayAmountCent = 0
dto.RentAmount = nil dto.RentAmountCent = nil
dto.OwnerRentAmount = nil dto.OwnerRentAmountCent = nil
sanitizeOrderSnapshot(&dto.AccountSnapshot, "") sanitizeOrderSnapshot(&dto.AccountSnapshot, "")
} }
} }
@@ -1583,43 +1597,43 @@ func applyCheckoutPriceView(dto *CheckoutDTO, order model.RentalOrder, userID ui
if dto == nil { if dto == nil {
return return
} }
ownerAmount := 0.0 ownerAmountCent := int64(0)
if dto.OwnerRentAmount != nil { if dto.OwnerRentAmountCent != nil {
ownerAmount = *dto.OwnerRentAmount ownerAmountCent = *dto.OwnerRentAmountCent
} }
ownerIncomeAmount := 0.0 ownerIncomeAmountCent := int64(0)
if dto.OwnerIncomeAmount != nil { if dto.OwnerIncomeAmountCent != nil {
ownerIncomeAmount = *dto.OwnerIncomeAmount ownerIncomeAmountCent = *dto.OwnerIncomeAmountCent
} }
rentAmount := 0.0 rentAmountCent := int64(0)
if dto.RentAmount != nil { if dto.RentAmountCent != nil {
rentAmount = *dto.RentAmount rentAmountCent = *dto.RentAmountCent
} }
renterRefundAmount := 0.0 renterRefundAmountCent := int64(0)
if dto.RenterRefundAmount != nil { if dto.RenterRefundAmountCent != nil {
renterRefundAmount = *dto.RenterRefundAmount renterRefundAmountCent = *dto.RenterRefundAmountCent
} }
dto.PlatformFee = nil dto.PlatformFeeCent = nil
dto.RenterRefundAmount = nil dto.RenterRefundAmountCent = nil
dto.OwnerIncomeAmount = nil dto.OwnerIncomeAmountCent = nil
switch { switch {
case userID == order.OwnerID: case userID == order.OwnerID:
dto.PriceRole = "owner" dto.PriceRole = "owner"
dto.DisplayAmount = ownerAmount dto.DisplayAmountCent = ownerAmountCent
dto.RentAmount = nil dto.RentAmountCent = nil
dto.OwnerRentAmount = &ownerAmount dto.OwnerRentAmountCent = &ownerAmountCent
dto.OwnerIncomeAmount = &ownerIncomeAmount dto.OwnerIncomeAmountCent = &ownerIncomeAmountCent
case userID == order.RenterID: case userID == order.RenterID:
dto.PriceRole = "renter" dto.PriceRole = "renter"
dto.DisplayAmount = rentAmount dto.DisplayAmountCent = rentAmountCent
dto.RentAmount = &rentAmount dto.RentAmountCent = &rentAmountCent
dto.OwnerRentAmount = nil dto.OwnerRentAmountCent = nil
dto.RenterRefundAmount = &renterRefundAmount dto.RenterRefundAmountCent = &renterRefundAmountCent
default: default:
dto.PriceRole = "" dto.PriceRole = ""
dto.DisplayAmount = 0 dto.DisplayAmountCent = 0
dto.RentAmount = nil dto.RentAmountCent = nil
dto.OwnerRentAmount = nil dto.OwnerRentAmountCent = nil
} }
} }
+1
View File
@@ -47,6 +47,7 @@ declare module 'vue' {
ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElSegmented: typeof import('element-plus/es')['ElSegmented']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
ElStep: typeof import('element-plus/es')['ElStep'] ElStep: typeof import('element-plus/es')['ElStep']
ElSteps: typeof import('element-plus/es')['ElSteps'] ElSteps: typeof import('element-plus/es')['ElSteps']