优化后台商品审核价格调整
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -472,6 +473,97 @@ func (r *Repository) Approve(listingID uint64) (*ListingDTO, error) {
|
||||
return dto, err
|
||||
}
|
||||
|
||||
func (r *Repository) AdjustReviewPrice(adminID uint64, listingID uint64, req AdminPriceAdjustRequest, meta AuditMeta) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||
listing, account, err := r.findForReviewUpdate(tx, listingID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if listing.Status == "rented" || listing.InTransaction {
|
||||
return ErrListingLocked
|
||||
}
|
||||
summary := decodeAssetSummary(account.AssetSummary)
|
||||
if summary == nil {
|
||||
summary = map[string]any{}
|
||||
}
|
||||
breakdown := ensurePriceBreakdown(summary)
|
||||
coinWan := float64(account.HafCoinAmount) / 10000
|
||||
consumablePrice := readSummaryNumber(breakdown["consumable_price"])
|
||||
if consumablePrice <= 0 {
|
||||
consumablePrice = consumableValue(summary)
|
||||
}
|
||||
sellerTotalPrice := readSummaryNumber(breakdown["seller_total_price"])
|
||||
if sellerTotalPrice <= 0 {
|
||||
sellerTotalPrice = math.Max(0, listing.Price-consumablePrice)
|
||||
}
|
||||
sellerCoinBasePrice := readSummaryNumber(breakdown["seller_coin_base_price"])
|
||||
if sellerCoinBasePrice <= 0 {
|
||||
sellerCoinBasePrice = math.Max(0, sellerTotalPrice-consumablePrice)
|
||||
}
|
||||
sellerRatio := readSummaryNumber(breakdown["seller_ratio"])
|
||||
if sellerRatio <= 0 && sellerCoinBasePrice > 0 {
|
||||
sellerRatio = roundRatio(coinWan / sellerCoinBasePrice)
|
||||
}
|
||||
buyerCoinBasePrice, buyerTotalPrice, buyerRatio := calculateAdminAdjustedPrice(req, coinWan, consumablePrice)
|
||||
if buyerCoinBasePrice <= 0 || buyerTotalPrice <= 0 || buyerRatio <= 0 {
|
||||
return ErrInvalidPrice
|
||||
}
|
||||
|
||||
beforePrice := listing.Price
|
||||
beforeRatio := readSummaryNumber(breakdown["buyer_ratio"])
|
||||
if beforeRatio <= 0 && listing.Price > consumablePrice {
|
||||
beforeRatio = roundRatio(coinWan / (listing.Price - consumablePrice))
|
||||
}
|
||||
|
||||
listing.Price = buyerTotalPrice
|
||||
summary["publish_ratio"] = buyerRatio
|
||||
breakdown["seller_coin_base_price"] = roundMoney(sellerCoinBasePrice)
|
||||
breakdown["seller_total_price"] = roundMoney(sellerTotalPrice)
|
||||
breakdown["seller_ratio"] = sellerRatio
|
||||
breakdown["buyer_coin_base_price"] = buyerCoinBasePrice
|
||||
breakdown["buyer_total_price"] = buyerTotalPrice
|
||||
breakdown["buyer_ratio"] = buyerRatio
|
||||
breakdown["platform_markup_amount"] = roundMoney(buyerTotalPrice - sellerTotalPrice)
|
||||
breakdown["platform_rule_type"] = "admin_adjusted"
|
||||
breakdown["admin_adjust_reason"] = strings.TrimSpace(req.Reason)
|
||||
breakdown["admin_adjusted_at"] = time.Now().Format(time.RFC3339)
|
||||
breakdown["admin_adjusted_by"] = adminID
|
||||
summary["price_breakdown"] = breakdown
|
||||
|
||||
assetSummary, err := marshalAssetSummary(summary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
account.AssetSummary = assetSummary
|
||||
if err := tx.Save(account).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(listing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := appendAuditLog(tx, adminID, "listing.adjust_review_price", "listing", listing.ID, meta, map[string]any{
|
||||
"listing_id": listing.ID,
|
||||
"account_id": account.ID,
|
||||
"owner_id": listing.OwnerID,
|
||||
"before_price": beforePrice,
|
||||
"after_price": listing.Price,
|
||||
"before_buyer_ratio": beforeRatio,
|
||||
"after_buyer_ratio": buyerRatio,
|
||||
"platform_markup": breakdown["platform_markup_amount"],
|
||||
"adjust_reason": req.Reason,
|
||||
"buyer_coin_base": buyerCoinBasePrice,
|
||||
"consumable_price": consumablePrice,
|
||||
"seller_total_price": sellerTotalPrice,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
dto = toDTO(*account, *listing)
|
||||
return nil
|
||||
})
|
||||
return dto, err
|
||||
}
|
||||
|
||||
func (r *Repository) Reject(listingID uint64, req ReviewRequest) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||
@@ -1278,6 +1370,47 @@ func readSummaryNumber(value any) float64 {
|
||||
}
|
||||
}
|
||||
|
||||
func ensurePriceBreakdown(summary map[string]any) map[string]any {
|
||||
if summary == nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
breakdown, ok := summary["price_breakdown"].(map[string]any)
|
||||
if ok {
|
||||
return breakdown
|
||||
}
|
||||
breakdown = map[string]any{}
|
||||
if raw, ok := summary["price_breakdown"].(map[string]interface{}); ok {
|
||||
for key, value := range raw {
|
||||
breakdown[key] = value
|
||||
}
|
||||
}
|
||||
return breakdown
|
||||
}
|
||||
|
||||
func calculateAdminAdjustedPrice(req AdminPriceAdjustRequest, coinWan float64, consumablePrice float64) (float64, float64, float64) {
|
||||
if req.BuyerTotalPrice > 0 {
|
||||
buyerTotalPrice := roundMoney(req.BuyerTotalPrice)
|
||||
buyerCoinBasePrice := roundMoney(buyerTotalPrice - consumablePrice)
|
||||
if buyerCoinBasePrice <= 0 || coinWan <= 0 {
|
||||
return 0, 0, 0
|
||||
}
|
||||
return buyerCoinBasePrice, buyerTotalPrice, roundRatio(coinWan / buyerCoinBasePrice)
|
||||
}
|
||||
if req.BuyerRatio <= 0 || coinWan <= 0 {
|
||||
return 0, 0, 0
|
||||
}
|
||||
buyerCoinBasePrice := roundMoney(coinWan / req.BuyerRatio)
|
||||
buyerTotalPrice := roundMoney(buyerCoinBasePrice + consumablePrice)
|
||||
return buyerCoinBasePrice, buyerTotalPrice, roundRatio(coinWan / buyerCoinBasePrice)
|
||||
}
|
||||
|
||||
func roundRatio(value float64) float64 {
|
||||
if value <= 0 || math.IsNaN(value) || math.IsInf(value, 0) {
|
||||
return 0
|
||||
}
|
||||
return math.Round(value*10) / 10
|
||||
}
|
||||
|
||||
func cleanScreenshotURLs(urls []string) []string {
|
||||
cleaned := make([]string, 0, len(urls))
|
||||
seen := make(map[string]struct{}, len(urls))
|
||||
|
||||
Reference in New Issue
Block a user