拆分大型 Repository 文件职责
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
package listing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"hfb_sys/backend/internal/modules/notification"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func (r *Repository) ListPendingReview(ctx context.Context) ([]ListingDTO, error) {
|
||||
var rows []listingRow
|
||||
err := r.baseQuery(ctx).
|
||||
Where("l.review_status = ? AND l.status <> ?", "pending", "offline").
|
||||
Order("l.updated_at ASC, l.id ASC").
|
||||
Limit(200).
|
||||
Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rowsToDTO(rows), nil
|
||||
}
|
||||
|
||||
func (r *Repository) AdminOffline(ctx context.Context, adminID uint64, listingID uint64, req AdminActionRequest, meta AuditMeta) (*ListingDTO, error) {
|
||||
return r.adminUpdateStatus(ctx, adminID, listingID, req, meta, "offline", "offline", "listing.admin_offline", "商品已被后台下架", "你的租号商品已被后台下架,请查看原因后处理。")
|
||||
}
|
||||
|
||||
func (r *Repository) AdminMarkAbnormal(ctx context.Context, adminID uint64, listingID uint64, req AdminActionRequest, meta AuditMeta) (*ListingDTO, error) {
|
||||
return r.adminUpdateStatus(ctx, adminID, listingID, req, meta, "abnormal", "abnormal", "listing.mark_abnormal", "商品已被标记异常", "你的租号商品已被后台标记异常,请联系客服处理。")
|
||||
}
|
||||
|
||||
func (r *Repository) adminUpdateStatus(ctx context.Context, adminID uint64, listingID uint64, req AdminActionRequest, meta AuditMeta, listingStatus string, accountStatus string, action string, title string, content string) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.WithContext(ctx).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
|
||||
}
|
||||
beforeListingStatus := listing.Status
|
||||
beforeAccountStatus := account.Status
|
||||
beforeReviewReason := listing.ReviewReason
|
||||
listing.Status = listingStatus
|
||||
listing.ReviewReason = req.Reason
|
||||
if listingStatus != "published" {
|
||||
listing.PublishedAt = nil
|
||||
}
|
||||
account.Status = accountStatus
|
||||
if err := tx.Save(account).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(listing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := notification.Append(tx, notification.Entry{
|
||||
UserID: listing.OwnerID,
|
||||
Type: "listing_admin",
|
||||
Title: title,
|
||||
Content: content,
|
||||
BizType: "listing",
|
||||
BizID: &listingID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := appendAuditLog(tx, adminID, action, "listing", listing.ID, meta, map[string]any{
|
||||
"listing_id": listing.ID,
|
||||
"account_id": account.ID,
|
||||
"owner_id": listing.OwnerID,
|
||||
"reason": req.Reason,
|
||||
"before_listing_status": beforeListingStatus,
|
||||
"after_listing_status": listing.Status,
|
||||
"before_account_status": beforeAccountStatus,
|
||||
"after_account_status": account.Status,
|
||||
"before_review_reason": beforeReviewReason,
|
||||
"after_review_reason": listing.ReviewReason,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
dto = toDTO(*account, *listing)
|
||||
return nil
|
||||
})
|
||||
return dto, err
|
||||
}
|
||||
|
||||
func (r *Repository) Approve(ctx context.Context, listingID uint64) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.WithContext(ctx).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
|
||||
}
|
||||
now := time.Now()
|
||||
listing.Status = "published"
|
||||
listing.ReviewStatus = "approved"
|
||||
listing.ReviewReason = ""
|
||||
listing.PublishedAt = &now
|
||||
account.Status = "published"
|
||||
if err := tx.Save(account).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(listing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
listingID := listing.ID
|
||||
if err := notification.Append(tx, notification.Entry{
|
||||
UserID: listing.OwnerID,
|
||||
Type: "listing_review",
|
||||
Title: "发布审核通过",
|
||||
Content: "你的租号发布已审核通过并上架。",
|
||||
BizType: "listing",
|
||||
BizID: &listingID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
dto = toDTO(*account, *listing)
|
||||
return nil
|
||||
})
|
||||
return dto, err
|
||||
}
|
||||
|
||||
func (r *Repository) AdjustReviewPrice(ctx context.Context, adminID uint64, listingID uint64, req AdminPriceAdjustRequest, meta AuditMeta) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.WithContext(ctx).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, centToYuan(listing.PriceCent)-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
|
||||
}
|
||||
|
||||
beforePriceCent := listing.PriceCent
|
||||
beforeRatio := readSummaryNumber(breakdown["buyer_ratio"])
|
||||
if beforeRatio <= 0 && centToYuan(listing.PriceCent) > consumablePrice {
|
||||
beforeRatio = roundRatio(coinWan / (centToYuan(listing.PriceCent) - consumablePrice))
|
||||
}
|
||||
|
||||
listing.PriceCent = yuanToCent(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_cent": beforePriceCent,
|
||||
"after_price_cent": listing.PriceCent,
|
||||
"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(ctx context.Context, listingID uint64, req ReviewRequest) (*ListingDTO, error) {
|
||||
var dto *ListingDTO
|
||||
err := r.db.WithContext(ctx).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
|
||||
}
|
||||
listing.Status = "draft"
|
||||
listing.ReviewStatus = "rejected"
|
||||
listing.ReviewReason = req.Reason
|
||||
listing.PublishedAt = nil
|
||||
account.Status = "draft"
|
||||
if err := tx.Save(account).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Save(listing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
listingID := listing.ID
|
||||
if err := notification.Append(tx, notification.Entry{
|
||||
UserID: listing.OwnerID,
|
||||
Type: "listing_review",
|
||||
Title: "发布审核未通过",
|
||||
Content: "你的租号发布未通过审核,请根据原因修改后重新提交。",
|
||||
BizType: "listing",
|
||||
BizID: &listingID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
dto = toDTO(*account, *listing)
|
||||
return nil
|
||||
})
|
||||
return dto, err
|
||||
}
|
||||
Reference in New Issue
Block a user