feat(quality-owner): 增加优质号主、极品专区与无忧租号保险
- 支持保证金余额支付、在线支付开通及后台手动设置审计 - 新增极品专区发布权限、赔付方案与保险结算费率快照 - 优化首页、商品卡和个人中心的优质号主身份展示
This commit is contained in:
@@ -46,6 +46,7 @@ func (r *Repository) finalizeCheckout(tx *gorm.DB, order *model.RentalOrder, che
|
||||
order.ActualPureCoinAmountCent = settlement.PureCoinAmountCent
|
||||
order.ActualPureCoinDiscountCent = settlement.PureCoinDiscountCent
|
||||
order.ActualExtraItemAmountCent = settlement.ExtraItemAmountCent
|
||||
order.InsuranceFeeCent = settlement.InsuranceFeeCent
|
||||
if err := appendCheckoutCompletedNotifications(tx, order, renterContent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -140,6 +141,8 @@ func applyCheckoutSettlement(checkout *model.OrderCheckout, settlement checkoutS
|
||||
checkout.RentAmountCent = settlement.ActualRentAmountCent
|
||||
checkout.OwnerRentAmountCent = settlement.OwnerRentIncomeCent
|
||||
checkout.PlatformFeeCent = settlement.PlatformFeeCent
|
||||
checkout.InsuranceFeeBps = settlement.InsuranceFeeBps
|
||||
checkout.InsuranceFeeCent = settlement.InsuranceFeeCent
|
||||
checkout.PureCoinAmountCent = settlement.PureCoinAmountCent
|
||||
checkout.PureCoinDiscountCent = settlement.PureCoinDiscountCent
|
||||
checkout.PureCoinPayableCent = settlement.PureCoinPayableCent
|
||||
|
||||
@@ -58,6 +58,10 @@ type OrderDTO struct {
|
||||
AccountSnapshot datatypes.JSON `json:"account_snapshot"`
|
||||
AccountSource string `json:"account_source"`
|
||||
SourceChannel string `json:"source_channel,omitempty"`
|
||||
IsPremium bool `json:"is_premium"`
|
||||
CompensationPlan string `json:"compensation_plan"`
|
||||
InsuranceFeeBps int `json:"insurance_fee_bps"`
|
||||
InsuranceFeeCent int64 `json:"insurance_fee_cent"`
|
||||
Status string `json:"status"`
|
||||
HandoffStatus string `json:"handoff_status"`
|
||||
HandoffMode string `json:"handoff_mode"`
|
||||
@@ -330,6 +334,8 @@ type CheckoutDTO struct {
|
||||
RentAmountCent *int64 `json:"rent_amount_cent,omitempty"`
|
||||
OwnerRentAmountCent *int64 `json:"owner_rent_amount_cent,omitempty"`
|
||||
PlatformFeeCent *int64 `json:"platform_fee_cent,omitempty"`
|
||||
InsuranceFeeBps int `json:"insurance_fee_bps"`
|
||||
InsuranceFeeCent int64 `json:"insurance_fee_cent"`
|
||||
DepositAmountCent int64 `json:"deposit_amount_cent"`
|
||||
PureCoinAmountCent int64 `json:"pure_coin_amount_cent"`
|
||||
PureCoinDiscountCent int64 `json:"pure_coin_discount_cent"`
|
||||
|
||||
@@ -151,6 +151,9 @@ func (r *Repository) Create(ctx context.Context, renterID uint64, req CreateRequ
|
||||
AccountSnapshot: snapshot,
|
||||
AccountSource: accountSource,
|
||||
SourceChannel: sourceChannel,
|
||||
IsPremium: listing.IsPremium,
|
||||
CompensationPlan: normalizedCompensationPlan(listing.CompensationPlan),
|
||||
InsuranceFeeBps: listing.InsuranceFeeBps,
|
||||
Status: orderStatusPendingPayment,
|
||||
HandoffStatus: handoffStatusNone,
|
||||
HandoffMode: listingHandoffMode(listing),
|
||||
@@ -194,6 +197,13 @@ func (r *Repository) Create(ctx context.Context, renterID uint64, req CreateRequ
|
||||
return r.FindForUser(ctx, renterID, createdID, req.DistributionSiteCode)
|
||||
}
|
||||
|
||||
func normalizedCompensationPlan(plan string) string {
|
||||
if plan == "insurance" {
|
||||
return "insurance"
|
||||
}
|
||||
return "normal"
|
||||
}
|
||||
|
||||
func loadShelfRatioTx(tx *gorm.DB, siteCode string, listingID uint64) (float64, uint64, error) {
|
||||
siteCode = strings.TrimSpace(siteCode)
|
||||
if siteCode == "" || listingID == 0 {
|
||||
|
||||
@@ -115,6 +115,10 @@ func (row orderRow) toAdminDTO() OrderDTO {
|
||||
AccountSnapshot: row.AccountSnapshot,
|
||||
AccountSource: effectiveAccountSource(row.RentalOrder),
|
||||
SourceChannel: row.SourceChannel,
|
||||
IsPremium: row.IsPremium,
|
||||
CompensationPlan: normalizedCompensationPlan(row.CompensationPlan),
|
||||
InsuranceFeeBps: row.InsuranceFeeBps,
|
||||
InsuranceFeeCent: row.InsuranceFeeCent,
|
||||
Status: row.Status,
|
||||
HandoffStatus: row.HandoffStatus,
|
||||
HandoffMode: effectiveHandoffMode(row.RentalOrder),
|
||||
@@ -312,6 +316,8 @@ func toCheckoutAdminDTO(checkout model.OrderCheckout) CheckoutDTO {
|
||||
RentAmountCent: &rentAmountCent,
|
||||
OwnerRentAmountCent: &ownerRentAmountCent,
|
||||
PlatformFeeCent: &platformFeeCent,
|
||||
InsuranceFeeBps: checkout.InsuranceFeeBps,
|
||||
InsuranceFeeCent: checkout.InsuranceFeeCent,
|
||||
DepositAmountCent: checkout.DepositAmountCent,
|
||||
PureCoinAmountCent: checkout.PureCoinAmountCent,
|
||||
PureCoinDiscountCent: checkout.PureCoinDiscountCent,
|
||||
|
||||
@@ -32,6 +32,8 @@ type checkoutSettlement struct {
|
||||
DepositRefundCent int64
|
||||
RenterRefundCent int64
|
||||
PlatformFeeCent int64
|
||||
InsuranceFeeBps int
|
||||
InsuranceFeeCent int64
|
||||
ActualRentAmountCent int64
|
||||
PureCoinAmountCent int64
|
||||
PureCoinDiscountCent int64
|
||||
@@ -59,6 +61,8 @@ type ActualCheckoutSettlement struct {
|
||||
DepositRefundCent int64
|
||||
RenterRefundCent int64
|
||||
PlatformFeeCent int64
|
||||
InsuranceFeeBps int
|
||||
InsuranceFeeCent int64
|
||||
ActualRentAmountCent int64
|
||||
PureCoinAmountCent int64
|
||||
PureCoinDiscountCent int64
|
||||
@@ -94,6 +98,8 @@ func toActualCheckoutSettlement(settlement checkoutSettlement) ActualCheckoutSet
|
||||
DepositRefundCent: settlement.DepositRefundCent,
|
||||
RenterRefundCent: settlement.RenterRefundCent,
|
||||
PlatformFeeCent: settlement.PlatformFeeCent,
|
||||
InsuranceFeeBps: settlement.InsuranceFeeBps,
|
||||
InsuranceFeeCent: settlement.InsuranceFeeCent,
|
||||
ActualRentAmountCent: settlement.ActualRentAmountCent,
|
||||
PureCoinAmountCent: settlement.PureCoinAmountCent,
|
||||
PureCoinDiscountCent: settlement.PureCoinDiscountCent,
|
||||
@@ -273,6 +279,8 @@ func buildCheckout(order model.RentalOrder, initiatedBy uint64, status string, c
|
||||
RentAmountCent: settlement.ActualRentAmountCent,
|
||||
OwnerRentAmountCent: settlement.OwnerRentIncomeCent,
|
||||
PlatformFeeCent: settlement.PlatformFeeCent,
|
||||
InsuranceFeeBps: settlement.InsuranceFeeBps,
|
||||
InsuranceFeeCent: settlement.InsuranceFeeCent,
|
||||
DepositAmountCent: order.DepositAmountCent,
|
||||
PureCoinAmountCent: settlement.PureCoinAmountCent,
|
||||
PureCoinDiscountCent: settlement.PureCoinDiscountCent,
|
||||
@@ -398,6 +406,8 @@ func calculateCheckoutSettlement(order model.RentalOrder, consumableAmountCent i
|
||||
// 可完结时租客实际承担的租金向金额;有 shortfall 时仍展示完整应付便于协商
|
||||
actualRentAmountCent := actualBuyerRentCent
|
||||
ownerRentIncomeCent := actualOwnerRentCent
|
||||
insuranceFeeCent := calculateInsuranceFeeCent(ownerRentIncomeCent, order.InsuranceFeeBps)
|
||||
ownerRentIncomeCent = maxCent(ownerRentIncomeCent-insuranceFeeCent, 0)
|
||||
platformFeeCent := maxCent(actualRentAmountCent-ownerRentIncomeCent, 0)
|
||||
depositCompensationCent := damageAppliedCent
|
||||
|
||||
@@ -409,6 +419,8 @@ func calculateCheckoutSettlement(order model.RentalOrder, consumableAmountCent i
|
||||
DepositRefundCent: depositRefundCent,
|
||||
RenterRefundCent: rentRefundCent + depositRefundCent,
|
||||
PlatformFeeCent: platformFeeCent,
|
||||
InsuranceFeeBps: order.InsuranceFeeBps,
|
||||
InsuranceFeeCent: insuranceFeeCent,
|
||||
ActualRentAmountCent: actualRentAmountCent,
|
||||
PureCoinAmountCent: usedBuyerCoinPriceCent,
|
||||
PureCoinDiscountCent: pureCoinDiscountCent,
|
||||
@@ -420,6 +432,14 @@ func calculateCheckoutSettlement(order model.RentalOrder, consumableAmountCent i
|
||||
}
|
||||
}
|
||||
|
||||
func calculateInsuranceFeeCent(ownerRentIncomeCent int64, feeBps int) int64 {
|
||||
if ownerRentIncomeCent <= 0 || feeBps <= 0 {
|
||||
return 0
|
||||
}
|
||||
feeCent := (ownerRentIncomeCent*int64(feeBps) + 5_000) / 10_000
|
||||
return minCent(feeCent, ownerRentIncomeCent)
|
||||
}
|
||||
|
||||
func orderPureCoinOriginalAmountCent(order model.RentalOrder) int64 {
|
||||
originalRentCent := effectiveRentOriginalAmountCent(order)
|
||||
if order.PureCoinOriginalAmountCent > 0 {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"hfb_sys/backend/internal/model"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
func TestCalculateInsuranceFeeCent(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ownerCent int64
|
||||
bps int
|
||||
want int64
|
||||
}{
|
||||
{name: "普通赔付不收费", ownerCent: 10000, bps: 0, want: 0},
|
||||
{name: "普通保险百分之八", ownerCent: 10000, bps: 800, want: 800},
|
||||
{name: "极品保险百分之四", ownerCent: 10000, bps: 400, want: 400},
|
||||
{name: "四舍五入到分", ownerCent: 12345, bps: 800, want: 988},
|
||||
{name: "服务费不超过到手租金", ownerCent: 100, bps: 10000, want: 100},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := calculateInsuranceFeeCent(tt.ownerCent, tt.bps); got != tt.want {
|
||||
t.Fatalf("calculateInsuranceFeeCent() = %d, want %d", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateCheckoutSettlementDeductsPremiumInsuranceFee(t *testing.T) {
|
||||
order := model.RentalOrder{
|
||||
RentAmountCent: 38300,
|
||||
OwnerRentAmountCent: 35300,
|
||||
DepositAmountCent: 15000,
|
||||
InsuranceFeeBps: 400,
|
||||
AccountSnapshot: datatypes.JSON([]byte(`{
|
||||
"haf_coin_amount": 100000000,
|
||||
"asset_summary": {
|
||||
"price_breakdown": {
|
||||
"buyer_coin_base_price": 263,
|
||||
"seller_coin_base_price": 233,
|
||||
"consumable_price": 120
|
||||
}
|
||||
}
|
||||
}`)),
|
||||
}
|
||||
|
||||
settlement := calculateCheckoutSettlement(order, 12000, 100, 0)
|
||||
if settlement.InsuranceFeeBps != 400 || settlement.InsuranceFeeCent != 1412 {
|
||||
t.Fatalf("保险费用快照不正确: bps=%d fee=%d", settlement.InsuranceFeeBps, settlement.InsuranceFeeCent)
|
||||
}
|
||||
if settlement.OwnerRentIncomeCent != 33888 {
|
||||
t.Fatalf("号主净租金 = %d, want 33888", settlement.OwnerRentIncomeCent)
|
||||
}
|
||||
if settlement.PlatformFeeCent != 4412 {
|
||||
t.Fatalf("平台收入 = %d, want 4412", settlement.PlatformFeeCent)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user