diff --git a/backend/internal/modules/adminuser/repository_test.go b/backend/internal/modules/adminuser/repository_test.go new file mode 100644 index 0000000..1b20a4b --- /dev/null +++ b/backend/internal/modules/adminuser/repository_test.go @@ -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) + } + }) + } +} diff --git a/backend/internal/modules/order/dto.go b/backend/internal/modules/order/dto.go index a7cb937..42f25b5 100644 --- a/backend/internal/modules/order/dto.go +++ b/backend/internal/modules/order/dto.go @@ -9,36 +9,36 @@ import ( ) type OrderDTO struct { - ID uint64 `json:"id"` - OrderNo string `json:"order_no"` - ListingID uint64 `json:"listing_id"` - ListingNo string `json:"listing_no"` - AccountID uint64 `json:"account_id"` - OwnerID uint64 `json:"owner_id"` - RenterID uint64 `json:"renter_id"` - OwnerPhone string `json:"owner_phone,omitempty"` - RenterPhone string `json:"renter_phone,omitempty"` - Title string `json:"title"` - ServerRegion string `json:"server_region"` - LoginPlatform string `json:"login_platform"` - RentedAt *time.Time `json:"rented_at"` - EstimatedDurationHours int `json:"estimated_duration_hours"` - PriceRole string `json:"price_role,omitempty"` - DisplayAmount float64 `json:"display_amount"` - RentAmount *float64 `json:"rent_amount,omitempty"` - OwnerRentAmount *float64 `json:"owner_rent_amount,omitempty"` - DepositAmount float64 `json:"deposit_amount"` - DepositOriginalAmount float64 `json:"deposit_original_amount"` - DepositWaivedAmount float64 `json:"deposit_waived_amount"` - PlatformFee *float64 `json:"platform_fee,omitempty"` - AccountSnapshot datatypes.JSON `json:"account_snapshot"` - Status string `json:"status"` - HandoffStatus string `json:"handoff_status"` - SettlementStatus string `json:"settlement_status"` - Checkout *CheckoutDTO `json:"checkout,omitempty"` - PaymentDeadlineAt *time.Time `json:"payment_deadline_at,omitempty"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID uint64 `json:"id"` + OrderNo string `json:"order_no"` + ListingID uint64 `json:"listing_id"` + ListingNo string `json:"listing_no"` + AccountID uint64 `json:"account_id"` + OwnerID uint64 `json:"owner_id"` + RenterID uint64 `json:"renter_id"` + OwnerPhone string `json:"owner_phone,omitempty"` + RenterPhone string `json:"renter_phone,omitempty"` + Title string `json:"title"` + ServerRegion string `json:"server_region"` + LoginPlatform string `json:"login_platform"` + RentedAt *time.Time `json:"rented_at"` + EstimatedDurationHours int `json:"estimated_duration_hours"` + PriceRole string `json:"price_role,omitempty"` + DisplayAmountCent int64 `json:"display_amount_cent"` + RentAmountCent *int64 `json:"rent_amount_cent,omitempty"` + OwnerRentAmountCent *int64 `json:"owner_rent_amount_cent,omitempty"` + DepositAmountCent int64 `json:"deposit_amount_cent"` + DepositOriginalAmountCent int64 `json:"deposit_original_amount_cent"` + DepositWaivedAmountCent int64 `json:"deposit_waived_amount_cent"` + PlatformFeeCent *int64 `json:"platform_fee_cent,omitempty"` + AccountSnapshot datatypes.JSON `json:"account_snapshot"` + Status string `json:"status"` + HandoffStatus string `json:"handoff_status"` + SettlementStatus string `json:"settlement_status"` + Checkout *CheckoutDTO `json:"checkout,omitempty"` + PaymentDeadlineAt *time.Time `json:"payment_deadline_at,omitempty"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } type CreateRequest struct { @@ -89,7 +89,7 @@ type RefundStatusDTO struct { RefundStatus string `json:"refund_status"` RefundAmountCent int64 `json:"refund_amount_cent"` RefundedAt *time.Time `json:"refunded_at,omitempty"` - TotalAmount float64 `json:"total_amount"` + TotalAmountCent int64 `json:"total_amount_cent"` } type HandoffRecordDTO struct { @@ -105,28 +105,28 @@ type HandoffRecordDTO struct { } type CheckoutDTO struct { - ID uint64 `json:"id"` - OrderID uint64 `json:"order_id"` - InitiatedBy uint64 `json:"initiated_by"` - Status string `json:"status"` - PriceRole string `json:"price_role,omitempty"` - DisplayAmount float64 `json:"display_amount"` - RentAmount *float64 `json:"rent_amount,omitempty"` - OwnerRentAmount *float64 `json:"owner_rent_amount,omitempty"` - PlatformFee *float64 `json:"platform_fee,omitempty"` - DepositAmount float64 `json:"deposit_amount"` - ConsumableAmount float64 `json:"consumable_amount"` - CoinConsumedM float64 `json:"coin_consumed_m"` - OtherAmount float64 `json:"other_amount"` - DepositDeductAmount float64 `json:"deposit_deduct_amount"` - RenterRefundAmount *float64 `json:"renter_refund_amount,omitempty"` - OwnerIncomeAmount *float64 `json:"owner_income_amount,omitempty"` - Content string `json:"content"` - EvidenceURLS []string `json:"evidence_urls"` - OwnerAdjustmentReason string `json:"owner_adjustment_reason"` - OwnerAdjustedAt *time.Time `json:"owner_adjusted_at"` - RenterConfirmedAt *time.Time `json:"renter_confirmed_at"` - RenterRejectedAt *time.Time `json:"renter_rejected_at"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID uint64 `json:"id"` + OrderID uint64 `json:"order_id"` + InitiatedBy uint64 `json:"initiated_by"` + Status string `json:"status"` + PriceRole string `json:"price_role,omitempty"` + DisplayAmountCent int64 `json:"display_amount_cent"` + RentAmountCent *int64 `json:"rent_amount_cent,omitempty"` + OwnerRentAmountCent *int64 `json:"owner_rent_amount_cent,omitempty"` + PlatformFeeCent *int64 `json:"platform_fee_cent,omitempty"` + DepositAmountCent int64 `json:"deposit_amount_cent"` + ConsumableAmountCent int64 `json:"consumable_amount_cent"` + CoinConsumedM float64 `json:"coin_consumed_m"` + OtherAmountCent int64 `json:"other_amount_cent"` + DepositDeductAmountCent int64 `json:"deposit_deduct_amount_cent"` + RenterRefundAmountCent *int64 `json:"renter_refund_amount_cent,omitempty"` + OwnerIncomeAmountCent *int64 `json:"owner_income_amount_cent,omitempty"` + Content string `json:"content"` + EvidenceURLS []string `json:"evidence_urls"` + OwnerAdjustmentReason string `json:"owner_adjustment_reason"` + OwnerAdjustedAt *time.Time `json:"owner_adjusted_at"` + RenterConfirmedAt *time.Time `json:"renter_confirmed_at"` + RenterRejectedAt *time.Time `json:"renter_rejected_at"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } diff --git a/backend/internal/modules/order/repository.go b/backend/internal/modules/order/repository.go index 4c4345d..25d9eee 100644 --- a/backend/internal/modules/order/repository.go +++ b/backend/internal/modules/order/repository.go @@ -53,20 +53,20 @@ func (r *Repository) SetRefundFunc(fn RefundFunc) { } type orderPricing struct { - RentAmount float64 - OwnerRentAmount float64 - PlatformFee float64 + RentAmountCent int64 + OwnerRentAmountCent int64 + PlatformFeeCent int64 } type checkoutSettlement struct { - OwnerRentIncome float64 - DepositCompensation float64 - OwnerIncome float64 - RentRefund float64 - DepositRefund float64 - RenterRefund float64 - PlatformFee float64 - ActualRentAmount float64 + OwnerRentIncomeCent int64 + DepositCompensationCent int64 + OwnerIncomeCent int64 + RentRefundCent int64 + DepositRefundCent int64 + RenterRefundCent int64 + PlatformFeeCent int64 + ActualRentAmountCent int64 } func orderDurationHours(order model.RentalOrder) int { @@ -90,9 +90,9 @@ func buildOrderPricing(listing model.RentalListing, account model.GameAccount) o platformFee = 0 } return orderPricing{ - RentAmount: rentAmount, - OwnerRentAmount: roundMoney(ownerRentAmount), - PlatformFee: roundMoney(platformFee), + RentAmountCent: int64(math.Round(rentAmount * 100)), + OwnerRentAmountCent: int64(math.Round(ownerRentAmount * 100)), + PlatformFeeCent: int64(math.Round(platformFee * 100)), } } @@ -179,22 +179,22 @@ func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, erro return err } order := model.RentalOrder{ - OrderNo: orderNo, - ListingID: listing.ID, - AccountID: listing.AccountID, - OwnerID: listing.OwnerID, - RenterID: renterID, - EstimatedDurationHours: rentHours, - RentAmount: pricing.RentAmount, - OwnerRentAmount: pricing.OwnerRentAmount, - DepositAmount: paidDepositAmount, - DepositOriginalAmount: depositOriginalAmount, - DepositWaivedAmount: waivedDepositAmount, - PlatformFee: pricing.PlatformFee, - AccountSnapshot: snapshot, - Status: "pending_payment", - HandoffStatus: "none", - SettlementStatus: "unsettled", + OrderNo: orderNo, + ListingID: listing.ID, + AccountID: listing.AccountID, + OwnerID: listing.OwnerID, + RenterID: renterID, + EstimatedDurationHours: rentHours, + RentAmountCent: pricing.RentAmountCent, + OwnerRentAmountCent: pricing.OwnerRentAmountCent, + DepositAmountCent: int64(math.Round(paidDepositAmount * 100)), + DepositOriginalAmountCent: int64(math.Round(depositOriginalAmount * 100)), + DepositWaivedAmountCent: int64(math.Round(waivedDepositAmount * 100)), + PlatformFeeCent: pricing.PlatformFeeCent, + AccountSnapshot: snapshot, + Status: "pending_payment", + HandoffStatus: "none", + SettlementStatus: "unsettled", } if err := tx.Create(&order).Error; err != nil { return err @@ -368,7 +368,7 @@ func (r *Repository) Cancel(userID uint64, orderID uint64) error { order.HandoffStatus = "cancelled" orderID := order.ID 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", "取消订单原路退款") if err != nil { return err @@ -690,10 +690,10 @@ func (r *Repository) CounterCheckout(userID uint64, orderID uint64, req CounterC return nil, err } dto := toCheckoutDTOForUser(*checkout, userID, model.RentalOrder{ - OwnerID: userID, - RentAmount: checkout.RentAmount, - OwnerRentAmount: checkout.OwnerRentAmount, - DepositAmount: checkout.DepositAmount, + OwnerID: userID, + RentAmountCent: int64(math.Round(checkout.RentAmount * 100)), + OwnerRentAmountCent: int64(math.Round(checkout.OwnerRentAmount * 100)), + DepositAmountCent: int64(math.Round(checkout.DepositAmount * 100)), }) return &dto, nil } @@ -838,7 +838,7 @@ func (r *Repository) AdminClose(adminID uint64, orderID uint64, req AdminActionR listing.InTransaction = false account.Status = "offline" 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", "客服关闭订单原路退款") if err != nil { return err @@ -976,7 +976,7 @@ func (r *Repository) AdminRefund(orderID uint64) (*RefundStatusDTO, error) { if r.refundFunc == nil { return nil, ErrDependencyUnavailable } - totalCent := int64(math.Round((order.RentAmount + order.DepositAmount) * 100)) + totalCent := order.RentAmountCent + order.DepositAmountCent if totalCent <= 0 { return nil, ErrInvalidCheckoutAmount } @@ -1011,7 +1011,7 @@ func (r *Repository) buildRefundStatusDTO(order *model.RentalOrder) *RefundStatu RefundStatus: order.RefundStatus, RefundAmountCent: order.RefundAmountCent, 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 - if settlement.OwnerRentIncome > 0 { + if settlement.OwnerRentIncomeCent > 0 { ownerEntries = append(ownerEntries, wallet.Entry{ UserID: order.OwnerID, OrderID: &orderID, Direction: "in", - Amount: settlement.OwnerRentIncome, + AmountCent: settlement.OwnerRentIncomeCent, BalanceType: "available", BizType: "owner_income", BizNo: order.OrderNo, Remark: "订单结账租金收入", }) } - if settlement.DepositCompensation > 0 { + if settlement.DepositCompensationCent > 0 { ownerEntries = append(ownerEntries, wallet.Entry{ UserID: order.OwnerID, OrderID: &orderID, Direction: "in", - Amount: settlement.DepositCompensation, + AmountCent: settlement.DepositCompensationCent, BalanceType: "available", BizType: "deposit_compensation", BizNo: order.OrderNo, @@ -1080,21 +1080,20 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che } var refund *refundAction - renterRefundTotal := settlement.RentRefund + settlement.DepositRefund - if renterRefundTotal > 0 { - refundCent := int64(math.Round(renterRefundTotal * 100)) - action, err := r.prepareRefund(order, refundCent, "checkout_refund", "结账退款原路退还") + renterRefundTotalCent := settlement.RentRefundCent + settlement.DepositRefundCent + if renterRefundTotalCent > 0 { + action, err := r.prepareRefund(order, renterRefundTotalCent, "checkout_refund", "结账退款原路退还") if err != nil { return nil, err } refund = action } - checkout.RentAmount = settlement.ActualRentAmount - checkout.OwnerRentAmount = settlement.OwnerRentIncome - checkout.PlatformFee = settlement.PlatformFee - checkout.RenterRefundAmount = settlement.RenterRefund - checkout.OwnerIncomeAmount = settlement.OwnerIncome + checkout.RentAmount = float64(settlement.ActualRentAmountCent) / 100 + checkout.OwnerRentAmount = float64(settlement.OwnerRentIncomeCent) / 100 + checkout.PlatformFee = float64(settlement.PlatformFeeCent) / 100 + checkout.RenterRefundAmount = float64(settlement.RenterRefundCent) / 100 + checkout.OwnerIncomeAmount = float64(settlement.OwnerIncomeCent) / 100 if err := notification.Append(tx, notification.Entry{ UserID: order.RenterID, @@ -1235,7 +1234,8 @@ func buildCheckout(order model.RentalOrder, initiatedBy uint64, status string, c if useExplicitDeduct { deductAmount = explicitDeduct } - if deductAmount > order.DepositAmount { + depositAmountFromCent := float64(order.DepositAmountCent) / 100 + if deductAmount > depositAmountFromCent { return model.OrderCheckout{}, ErrInvalidCheckoutAmount } settlement := calculateCheckoutSettlement(order, consumableAmount, roundQuantity(coinConsumedM), deductAmount) @@ -1247,16 +1247,16 @@ func buildCheckout(order model.RentalOrder, initiatedBy uint64, status string, c OrderID: order.ID, InitiatedBy: initiatedBy, Status: status, - RentAmount: settlement.ActualRentAmount, - OwnerRentAmount: settlement.OwnerRentIncome, - PlatformFee: settlement.PlatformFee, - DepositAmount: order.DepositAmount, + RentAmount: float64(settlement.ActualRentAmountCent) / 100, + OwnerRentAmount: float64(settlement.OwnerRentIncomeCent) / 100, + PlatformFee: float64(settlement.PlatformFeeCent) / 100, + DepositAmount: depositAmountFromCent, ConsumableAmount: consumableAmount, CoinConsumedM: roundQuantity(coinConsumedM), OtherAmount: otherAmount, DepositDeductAmount: roundMoney(deductAmount), - RenterRefundAmount: settlement.RenterRefund, - OwnerIncomeAmount: settlement.OwnerIncome, + RenterRefundAmount: float64(settlement.RenterRefundCent) / 100, + OwnerIncomeAmount: float64(settlement.OwnerIncomeCent) / 100, Content: content, EvidenceURLS: evidence, }, 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 { + // 从分字段读取,转为元进行计算(保持现有逻辑兼容性) + orderRentAmount := float64(order.RentAmountCent) / 100 + orderOwnerRentAmount := float64(order.OwnerRentAmountCent) / 100 + orderDepositAmount := float64(order.DepositAmountCent) / 100 + buyerCoinBasePrice := readOrderSnapshotPrice(order.AccountSnapshot, "buyer_coin_base_price") - if buyerCoinBasePrice <= 0 || buyerCoinBasePrice > order.RentAmount { - buyerCoinBasePrice = order.RentAmount + if buyerCoinBasePrice <= 0 || buyerCoinBasePrice > orderRentAmount { + buyerCoinBasePrice = orderRentAmount } sellerCoinBasePrice := readOrderSnapshotPrice(order.AccountSnapshot, "seller_coin_base_price") - if sellerCoinBasePrice <= 0 || sellerCoinBasePrice > order.OwnerRentAmount { - sellerCoinBasePrice = order.OwnerRentAmount + if sellerCoinBasePrice <= 0 || sellerCoinBasePrice > orderOwnerRentAmount { + sellerCoinBasePrice = orderOwnerRentAmount } prepaidConsumablePrice := readOrderSnapshotPrice(order.AccountSnapshot, "consumable_price") - if prepaidConsumablePrice <= 0 || prepaidConsumablePrice > order.RentAmount-buyerCoinBasePrice { - prepaidConsumablePrice = maxMoney(order.RentAmount-buyerCoinBasePrice, 0) + if prepaidConsumablePrice <= 0 || prepaidConsumablePrice > orderRentAmount-buyerCoinBasePrice { + prepaidConsumablePrice = maxMoney(orderRentAmount-buyerCoinBasePrice, 0) } - prepaidOwnerConsumablePrice := maxMoney(order.OwnerRentAmount-sellerCoinBasePrice, 0) + prepaidOwnerConsumablePrice := maxMoney(orderOwnerRentAmount-sellerCoinBasePrice, 0) totalCoinM := readOrderSnapshotCoinM(order.AccountSnapshot) coinUseRatio := 1.0 if totalCoinM > 0 { @@ -1293,20 +1298,22 @@ func calculateCheckoutSettlement(order model.RentalOrder, consumableAmount float consumableUseRatio = minRatio(maxRatio(usedBuyerConsumablePrice/prepaidConsumablePrice, 0), 1) } usedOwnerConsumablePrice := roundMoney(prepaidOwnerConsumablePrice * consumableUseRatio) - actualRentAmount := minMoney(roundMoney(usedBuyerCoinPrice+usedBuyerConsumablePrice), order.RentAmount) - ownerRentIncome := minMoney(roundMoney(usedOwnerCoinPrice+usedOwnerConsumablePrice), order.OwnerRentAmount) - depositCompensation := minMoney(roundMoney(depositDeductAmount), order.DepositAmount) - rentRefund := maxMoney(order.RentAmount-actualRentAmount, 0) - depositRefund := maxMoney(order.DepositAmount-depositCompensation, 0) + actualRentAmount := minMoney(roundMoney(usedBuyerCoinPrice+usedBuyerConsumablePrice), orderRentAmount) + ownerRentIncome := minMoney(roundMoney(usedOwnerCoinPrice+usedOwnerConsumablePrice), orderOwnerRentAmount) + depositCompensation := minMoney(roundMoney(depositDeductAmount), orderDepositAmount) + rentRefund := maxMoney(orderRentAmount-actualRentAmount, 0) + depositRefund := maxMoney(orderDepositAmount-depositCompensation, 0) + + // 最后转换为分返回 return checkoutSettlement{ - OwnerRentIncome: ownerRentIncome, - DepositCompensation: depositCompensation, - OwnerIncome: roundMoney(ownerRentIncome + depositCompensation), - RentRefund: rentRefund, - DepositRefund: depositRefund, - RenterRefund: roundMoney(rentRefund + depositRefund), - PlatformFee: maxMoney(actualRentAmount-ownerRentIncome, 0), - ActualRentAmount: actualRentAmount, + OwnerRentIncomeCent: int64(math.Round(ownerRentIncome * 100)), + DepositCompensationCent: int64(math.Round(depositCompensation * 100)), + OwnerIncomeCent: int64(math.Round((ownerRentIncome + depositCompensation) * 100)), + RentRefundCent: int64(math.Round(rentRefund * 100)), + DepositRefundCent: int64(math.Round(depositRefund * 100)), + RenterRefundCent: int64(math.Round((rentRefund + depositRefund) * 100)), + PlatformFeeCent: int64(math.Round(maxMoney(actualRentAmount-ownerRentIncome, 0) * 100)), + ActualRentAmountCent: int64(math.Round(actualRentAmount * 100)), } } @@ -1445,38 +1452,38 @@ type orderRow struct { func (row orderRow) toAdminDTO() OrderDTO { rentedAt := row.RentedAt durationHours := orderDurationHours(row.RentalOrder) - rentAmount := row.RentAmount - ownerRentAmount := row.OwnerRentAmount - platformFee := row.PlatformFee + rentAmountCent := row.RentAmountCent + ownerRentAmountCent := row.OwnerRentAmountCent + platformFeeCent := row.PlatformFeeCent return OrderDTO{ - ID: row.ID, - OrderNo: row.OrderNo, - ListingID: row.ListingID, - ListingNo: row.ListingNo, - AccountID: row.AccountID, - OwnerID: row.OwnerID, - RenterID: row.RenterID, - OwnerPhone: row.OwnerPhone, - RenterPhone: row.RenterPhone, - Title: row.Title, - ServerRegion: row.ServerRegion, - LoginPlatform: row.LoginPlatform, - RentedAt: rentedAt, - EstimatedDurationHours: durationHours, - PriceRole: "admin", - DisplayAmount: row.RentAmount, - RentAmount: &rentAmount, - OwnerRentAmount: &ownerRentAmount, - DepositAmount: row.DepositAmount, - DepositOriginalAmount: effectiveDepositOriginalAmount(row.RentalOrder), - DepositWaivedAmount: row.DepositWaivedAmount, - PlatformFee: &platformFee, - AccountSnapshot: row.AccountSnapshot, - Status: row.Status, - HandoffStatus: row.HandoffStatus, - SettlementStatus: row.SettlementStatus, - CreatedAt: row.CreatedAt, - UpdatedAt: row.UpdatedAt, + ID: row.ID, + OrderNo: row.OrderNo, + ListingID: row.ListingID, + ListingNo: row.ListingNo, + AccountID: row.AccountID, + OwnerID: row.OwnerID, + RenterID: row.RenterID, + OwnerPhone: row.OwnerPhone, + RenterPhone: row.RenterPhone, + Title: row.Title, + ServerRegion: row.ServerRegion, + LoginPlatform: row.LoginPlatform, + RentedAt: rentedAt, + EstimatedDurationHours: durationHours, + PriceRole: "admin", + DisplayAmountCent: row.RentAmountCent, + RentAmountCent: &rentAmountCent, + OwnerRentAmountCent: &ownerRentAmountCent, + DepositAmountCent: row.DepositAmountCent, + DepositOriginalAmountCent: effectiveDepositOriginalAmountCent(row.RentalOrder), + DepositWaivedAmountCent: row.DepositWaivedAmountCent, + PlatformFeeCent: &platformFeeCent, + AccountSnapshot: row.AccountSnapshot, + Status: row.Status, + HandoffStatus: row.HandoffStatus, + SettlementStatus: row.SettlementStatus, + CreatedAt: row.CreatedAt, + UpdatedAt: row.UpdatedAt, } } @@ -1507,37 +1514,44 @@ func effectiveDepositOriginalAmount(order model.RentalOrder) float64 { 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 { - rentAmount := checkout.RentAmount - ownerRentAmount := checkout.OwnerRentAmount - platformFee := checkout.PlatformFee - renterRefundAmount := checkout.RenterRefundAmount - ownerIncomeAmount := checkout.OwnerIncomeAmount + rentAmountCent := int64(math.Round(checkout.RentAmount * 100)) + ownerRentAmountCent := int64(math.Round(checkout.OwnerRentAmount * 100)) + platformFeeCent := int64(math.Round(checkout.PlatformFee * 100)) + renterRefundAmountCent := int64(math.Round(checkout.RenterRefundAmount * 100)) + ownerIncomeAmountCent := int64(math.Round(checkout.OwnerIncomeAmount * 100)) return CheckoutDTO{ - ID: checkout.ID, - OrderID: checkout.OrderID, - InitiatedBy: checkout.InitiatedBy, - Status: checkout.Status, - PriceRole: "admin", - DisplayAmount: checkout.RentAmount, - RentAmount: &rentAmount, - OwnerRentAmount: &ownerRentAmount, - PlatformFee: &platformFee, - DepositAmount: checkout.DepositAmount, - ConsumableAmount: checkout.ConsumableAmount, - CoinConsumedM: checkout.CoinConsumedM, - OtherAmount: checkout.OtherAmount, - DepositDeductAmount: checkout.DepositDeductAmount, - RenterRefundAmount: &renterRefundAmount, - OwnerIncomeAmount: &ownerIncomeAmount, - Content: checkout.Content, - EvidenceURLS: decodeStringList(checkout.EvidenceURLS), - OwnerAdjustmentReason: checkout.OwnerAdjustmentReason, - OwnerAdjustedAt: checkout.OwnerAdjustedAt, - RenterConfirmedAt: checkout.RenterConfirmedAt, - RenterRejectedAt: checkout.RenterRejectedAt, - CreatedAt: checkout.CreatedAt, - UpdatedAt: checkout.UpdatedAt, + ID: checkout.ID, + OrderID: checkout.OrderID, + InitiatedBy: checkout.InitiatedBy, + Status: checkout.Status, + PriceRole: "admin", + DisplayAmountCent: rentAmountCent, + RentAmountCent: &rentAmountCent, + OwnerRentAmountCent: &ownerRentAmountCent, + PlatformFeeCent: &platformFeeCent, + DepositAmountCent: int64(math.Round(checkout.DepositAmount * 100)), + ConsumableAmountCent: int64(math.Round(checkout.ConsumableAmount * 100)), + CoinConsumedM: checkout.CoinConsumedM, + OtherAmountCent: int64(math.Round(checkout.OtherAmount * 100)), + DepositDeductAmountCent: int64(math.Round(checkout.DepositDeductAmount * 100)), + RenterRefundAmountCent: &renterRefundAmountCent, + OwnerIncomeAmountCent: &ownerIncomeAmountCent, + Content: checkout.Content, + EvidenceURLS: decodeStringList(checkout.EvidenceURLS), + OwnerAdjustmentReason: checkout.OwnerAdjustmentReason, + OwnerAdjustedAt: checkout.OwnerAdjustedAt, + RenterConfirmedAt: checkout.RenterConfirmedAt, + RenterRejectedAt: checkout.RenterRejectedAt, + CreatedAt: checkout.CreatedAt, + UpdatedAt: checkout.UpdatedAt, } } @@ -1551,30 +1565,30 @@ func applyOrderPriceView(dto *OrderDTO, order model.RentalOrder, userID uint64) if dto == nil { return } - dto.PlatformFee = nil + dto.PlatformFeeCent = nil switch { case userID == order.OwnerID: - ownerAmount := order.OwnerRentAmount - if ownerAmount <= 0 { - ownerAmount = order.RentAmount + ownerAmountCent := order.OwnerRentAmountCent + if ownerAmountCent <= 0 { + ownerAmountCent = order.RentAmountCent } dto.PriceRole = "owner" - dto.DisplayAmount = ownerAmount - dto.RentAmount = nil - dto.OwnerRentAmount = &ownerAmount + dto.DisplayAmountCent = ownerAmountCent + dto.RentAmountCent = nil + dto.OwnerRentAmountCent = &ownerAmountCent sanitizeOrderSnapshot(&dto.AccountSnapshot, "owner") case userID == order.RenterID: - rentAmount := order.RentAmount + rentAmountCent := order.RentAmountCent dto.PriceRole = "renter" - dto.DisplayAmount = rentAmount - dto.RentAmount = &rentAmount - dto.OwnerRentAmount = nil + dto.DisplayAmountCent = rentAmountCent + dto.RentAmountCent = &rentAmountCent + dto.OwnerRentAmountCent = nil sanitizeOrderSnapshot(&dto.AccountSnapshot, "renter") default: dto.PriceRole = "" - dto.DisplayAmount = 0 - dto.RentAmount = nil - dto.OwnerRentAmount = nil + dto.DisplayAmountCent = 0 + dto.RentAmountCent = nil + dto.OwnerRentAmountCent = nil sanitizeOrderSnapshot(&dto.AccountSnapshot, "") } } @@ -1583,43 +1597,43 @@ func applyCheckoutPriceView(dto *CheckoutDTO, order model.RentalOrder, userID ui if dto == nil { return } - ownerAmount := 0.0 - if dto.OwnerRentAmount != nil { - ownerAmount = *dto.OwnerRentAmount + ownerAmountCent := int64(0) + if dto.OwnerRentAmountCent != nil { + ownerAmountCent = *dto.OwnerRentAmountCent } - ownerIncomeAmount := 0.0 - if dto.OwnerIncomeAmount != nil { - ownerIncomeAmount = *dto.OwnerIncomeAmount + ownerIncomeAmountCent := int64(0) + if dto.OwnerIncomeAmountCent != nil { + ownerIncomeAmountCent = *dto.OwnerIncomeAmountCent } - rentAmount := 0.0 - if dto.RentAmount != nil { - rentAmount = *dto.RentAmount + rentAmountCent := int64(0) + if dto.RentAmountCent != nil { + rentAmountCent = *dto.RentAmountCent } - renterRefundAmount := 0.0 - if dto.RenterRefundAmount != nil { - renterRefundAmount = *dto.RenterRefundAmount + renterRefundAmountCent := int64(0) + if dto.RenterRefundAmountCent != nil { + renterRefundAmountCent = *dto.RenterRefundAmountCent } - dto.PlatformFee = nil - dto.RenterRefundAmount = nil - dto.OwnerIncomeAmount = nil + dto.PlatformFeeCent = nil + dto.RenterRefundAmountCent = nil + dto.OwnerIncomeAmountCent = nil switch { case userID == order.OwnerID: dto.PriceRole = "owner" - dto.DisplayAmount = ownerAmount - dto.RentAmount = nil - dto.OwnerRentAmount = &ownerAmount - dto.OwnerIncomeAmount = &ownerIncomeAmount + dto.DisplayAmountCent = ownerAmountCent + dto.RentAmountCent = nil + dto.OwnerRentAmountCent = &ownerAmountCent + dto.OwnerIncomeAmountCent = &ownerIncomeAmountCent case userID == order.RenterID: dto.PriceRole = "renter" - dto.DisplayAmount = rentAmount - dto.RentAmount = &rentAmount - dto.OwnerRentAmount = nil - dto.RenterRefundAmount = &renterRefundAmount + dto.DisplayAmountCent = rentAmountCent + dto.RentAmountCent = &rentAmountCent + dto.OwnerRentAmountCent = nil + dto.RenterRefundAmountCent = &renterRefundAmountCent default: dto.PriceRole = "" - dto.DisplayAmount = 0 - dto.RentAmount = nil - dto.OwnerRentAmount = nil + dto.DisplayAmountCent = 0 + dto.RentAmountCent = nil + dto.OwnerRentAmountCent = nil } } diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 90947ac..563e1ba 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -47,6 +47,7 @@ declare module 'vue' { ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] + ElSegmented: typeof import('element-plus/es')['ElSegmented'] ElSelect: typeof import('element-plus/es')['ElSelect'] ElStep: typeof import('element-plus/es')['ElStep'] ElSteps: typeof import('element-plus/es')['ElSteps']