兼容接入商品固定价格字段

This commit is contained in:
yml
2026-05-24 18:13:20 +08:00
parent 14aafcf728
commit e69d08ca9f
15 changed files with 153 additions and 32 deletions
+1
View File
@@ -32,6 +32,7 @@ type RentalListing struct {
ID uint64 `gorm:"primaryKey" json:"id"`
AccountID uint64 `gorm:"not null;index" json:"account_id"`
OwnerID uint64 `gorm:"not null;index" json:"owner_id"`
Price float64 `gorm:"type:decimal(12,2);not null;default:0" json:"price"`
PriceHourly float64 `gorm:"type:decimal(12,2);not null;default:0" json:"price_hourly"`
PriceDaily float64 `gorm:"type:decimal(12,2);not null;default:0" json:"price_daily"`
PriceWeekly float64 `gorm:"type:decimal(12,2);not null;default:0" json:"price_weekly"`
+3
View File
@@ -18,11 +18,13 @@ type ListingDTO struct {
AssetSummary map[string]any `json:"asset_summary,omitempty"`
ScreenshotURLS []string `json:"screenshot_urls"`
CoverURL string `json:"cover_url"`
Price float64 `json:"price"`
PriceHourly float64 `json:"price_hourly"`
PriceDaily float64 `json:"price_daily"`
PriceWeekly float64 `json:"price_weekly"`
DepositAmount float64 `json:"deposit_amount"`
IsAccelerated bool `json:"is_accelerated_sale"`
InTransaction bool `json:"in_transaction"`
Status string `json:"status"`
ReviewStatus string `json:"review_status"`
ReviewReason string `json:"review_reason"`
@@ -40,6 +42,7 @@ type CreateRequest struct {
HafCoinAmount int64 `json:"haf_coin_amount"`
AssetSummary map[string]any `json:"asset_summary"`
ScreenshotURLS []string `json:"screenshot_urls"`
Price float64 `json:"price"`
PriceHourly float64 `json:"price_hourly"`
PriceDaily float64 `json:"price_daily"`
PriceWeekly float64 `json:"price_weekly"`
+88 -18
View File
@@ -60,12 +60,14 @@ func (r *Repository) Create(ownerID uint64, req CreateRequest, reviewRequired bo
if err := tx.Create(&account).Error; err != nil {
return err
}
price := normalizedListingPrice(req)
listing := model.RentalListing{
AccountID: account.ID,
OwnerID: ownerID,
PriceHourly: req.PriceHourly,
PriceDaily: req.PriceDaily,
PriceWeekly: req.PriceWeekly,
Price: price,
PriceHourly: listingHourlyPrice(req, price),
PriceDaily: listingDailyPrice(req, price),
PriceWeekly: listingWeeklyPrice(req, price),
DepositAmount: req.DepositAmount,
Status: listingStatus,
ReviewStatus: reviewStatus,
@@ -87,7 +89,7 @@ func (r *Repository) Update(ownerID uint64, listingID uint64, req UpdateRequest,
if err != nil {
return err
}
if listing.Status == "rented" {
if listing.Status == "rented" || listing.InTransaction {
return ErrListingLocked
}
@@ -108,9 +110,11 @@ func (r *Repository) Update(ownerID uint64, listingID uint64, req UpdateRequest,
}
account.ScreenshotURLS = screenshots
listing.PriceHourly = req.PriceHourly
listing.PriceDaily = req.PriceDaily
listing.PriceWeekly = req.PriceWeekly
price := normalizedListingPrice(req)
listing.Price = price
listing.PriceHourly = listingHourlyPrice(req, price)
listing.PriceDaily = listingDailyPrice(req, price)
listing.PriceWeekly = listingWeeklyPrice(req, price)
listing.DepositAmount = req.DepositAmount
listingStatus, reviewStatus, publishedAt := initialPublishState(reviewRequired)
listing.Status = listingStatus
@@ -137,7 +141,7 @@ func (r *Repository) SubmitReview(ownerID uint64, listingID uint64, reviewRequir
if err != nil {
return err
}
if listing.Status == "rented" {
if listing.Status == "rented" || listing.InTransaction {
return ErrListingLocked
}
listingStatus, reviewStatus, publishedAt := initialPublishState(reviewRequired)
@@ -215,7 +219,7 @@ func (r *Repository) adminUpdateStatus(adminID uint64, listingID uint64, req Adm
if err != nil {
return err
}
if listing.Status == "rented" {
if listing.Status == "rented" || listing.InTransaction {
return ErrListingLocked
}
beforeListingStatus := listing.Status
@@ -270,7 +274,7 @@ func (r *Repository) Approve(listingID uint64) (*ListingDTO, error) {
if err != nil {
return err
}
if listing.Status == "rented" {
if listing.Status == "rented" || listing.InTransaction {
return ErrListingLocked
}
now := time.Now()
@@ -309,7 +313,7 @@ func (r *Repository) Reject(listingID uint64, req ReviewRequest) (*ListingDTO, e
if err != nil {
return err
}
if listing.Status == "rented" {
if listing.Status == "rented" || listing.InTransaction {
return ErrListingLocked
}
listing.Status = "draft"
@@ -346,7 +350,7 @@ func (r *Repository) Offline(ownerID uint64, listingID uint64) error {
if err != nil {
return err
}
if listing.Status == "rented" {
if listing.Status == "rented" || listing.InTransaction {
return ErrListingLocked
}
listing.Status = "offline"
@@ -484,6 +488,66 @@ func rowsToDTO(rows []listingRow) []ListingDTO {
return items
}
func normalizedListingPrice(req CreateRequest) float64 {
if req.Price > 0 {
return req.Price
}
if req.PriceDaily > 0 {
return req.PriceDaily
}
if req.PriceHourly > 0 {
return req.PriceHourly * 24
}
if req.PriceWeekly > 0 {
return req.PriceWeekly / 7
}
return 0
}
func listingHourlyPrice(req CreateRequest, price float64) float64 {
if req.PriceHourly > 0 {
return req.PriceHourly
}
return price / 24
}
func listingDailyPrice(req CreateRequest, price float64) float64 {
if req.PriceDaily > 0 {
return req.PriceDaily
}
return price
}
func listingWeeklyPrice(req CreateRequest, price float64) float64 {
if req.PriceWeekly > 0 {
return req.PriceWeekly
}
return price * 7
}
func listingDisplayPrices(price float64, hourly float64, daily float64, weekly float64) (float64, float64, float64, float64) {
if price <= 0 {
switch {
case daily > 0:
price = daily
case hourly > 0:
price = hourly * 24
case weekly > 0:
price = weekly / 7
}
}
if daily <= 0 {
daily = price
}
if hourly <= 0 && price > 0 {
hourly = price / 24
}
if weekly <= 0 && price > 0 {
weekly = price * 7
}
return price, hourly, daily, weekly
}
func publicListings(items []ListingDTO) []ListingDTO {
for index := range items {
applyPublicListingURLs(&items[index])
@@ -501,6 +565,7 @@ func applyPublicListingURLs(item *ListingDTO) {
func (row listingRow) toDTO() ListingDTO {
assetSummary := decodeAssetSummary(row.AssetSummary)
screenshotURLS := cleanScreenshotURLs(decodeScreenshots(row.ScreenshotURLS))
price, priceHourly, priceDaily, priceWeekly := listingDisplayPrices(row.Price, row.PriceHourly, row.PriceDaily, row.PriceWeekly)
return ListingDTO{
ID: row.ID,
AccountID: row.AccountID,
@@ -517,11 +582,13 @@ func (row listingRow) toDTO() ListingDTO {
AssetSummary: assetSummary,
ScreenshotURLS: screenshotURLS,
CoverURL: publicCoverURL(row.ID, screenshotURLS, row.Status, row.ReviewStatus),
PriceHourly: row.PriceHourly,
PriceDaily: row.PriceDaily,
PriceWeekly: row.PriceWeekly,
Price: price,
PriceHourly: priceHourly,
PriceDaily: priceDaily,
PriceWeekly: priceWeekly,
DepositAmount: row.DepositAmount,
IsAccelerated: isAcceleratedSale(assetSummary),
InTransaction: row.InTransaction,
Status: row.Status,
ReviewStatus: row.ReviewStatus,
ReviewReason: row.ReviewReason,
@@ -534,6 +601,7 @@ func (row listingRow) toDTO() ListingDTO {
func toDTO(account model.GameAccount, listing model.RentalListing) *ListingDTO {
assetSummary := decodeAssetSummary(account.AssetSummary)
screenshotURLS := cleanScreenshotURLs(decodeScreenshots(account.ScreenshotURLS))
price, priceHourly, priceDaily, priceWeekly := listingDisplayPrices(listing.Price, listing.PriceHourly, listing.PriceDaily, listing.PriceWeekly)
return &ListingDTO{
ID: listing.ID,
AccountID: account.ID,
@@ -548,11 +616,13 @@ func toDTO(account model.GameAccount, listing model.RentalListing) *ListingDTO {
AssetSummary: assetSummary,
ScreenshotURLS: screenshotURLS,
CoverURL: publicCoverURL(listing.ID, screenshotURLS, listing.Status, listing.ReviewStatus),
PriceHourly: listing.PriceHourly,
PriceDaily: listing.PriceDaily,
PriceWeekly: listing.PriceWeekly,
Price: price,
PriceHourly: priceHourly,
PriceDaily: priceDaily,
PriceWeekly: priceWeekly,
DepositAmount: listing.DepositAmount,
IsAccelerated: isAcceleratedSale(assetSummary),
InTransaction: listing.InTransaction,
Status: listing.Status,
ReviewStatus: listing.ReviewStatus,
ReviewReason: listing.ReviewReason,
+1 -1
View File
@@ -211,7 +211,7 @@ func validateRequest(req CreateRequest, rules publishRules) error {
if strings.TrimSpace(req.ServerRegion) == "" {
return ErrMissingServerRegion
}
if req.PriceHourly <= 0 {
if normalizedListingPrice(req) <= 0 {
return ErrInvalidPrice
}
if req.DepositAmount < 0 {
+16 -1
View File
@@ -28,6 +28,21 @@ func NewRepository(db *gorm.DB) *Repository {
return &Repository{db: db}
}
func listingOrderPrice(listing model.RentalListing) float64 {
switch {
case listing.Price > 0:
return listing.Price
case listing.PriceDaily > 0:
return listing.PriceDaily
case listing.PriceHourly > 0:
return listing.PriceHourly * float64(internalOrderHours)
case listing.PriceWeekly > 0:
return listing.PriceWeekly / 7
default:
return 0
}
}
func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, error) {
var createdID uint64
err := r.db.Transaction(func(tx *gorm.DB) error {
@@ -62,7 +77,7 @@ func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, erro
OwnerID: listing.OwnerID,
RenterID: renterID,
RentHours: rentHours,
RentAmount: listing.PriceHourly * float64(rentHours),
RentAmount: listingOrderPrice(listing),
DepositAmount: listing.DepositAmount,
PlatformFee: 0,
AccountSnapshot: snapshot,
+3 -1
View File
@@ -53,6 +53,7 @@ CREATE TABLE rental_listings (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
account_id BIGINT UNSIGNED NOT NULL,
owner_id BIGINT UNSIGNED NOT NULL,
price DECIMAL(12,2) NOT NULL DEFAULT 0.00,
price_hourly DECIMAL(12,2) NOT NULL DEFAULT 0.00,
price_daily DECIMAL(12,2) NOT NULL DEFAULT 0.00,
price_weekly DECIMAL(12,2) NOT NULL DEFAULT 0.00,
@@ -66,7 +67,8 @@ CREATE TABLE rental_listings (
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_rental_listings_account_id (account_id),
KEY idx_rental_listings_owner_id (owner_id),
KEY idx_rental_listings_filter (status, review_status, price_hourly)
KEY idx_rental_listings_filter (status, review_status, price),
KEY idx_rental_listings_legacy_filter (status, review_status, price_hourly)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE rental_orders (
@@ -15,6 +15,32 @@ PREPARE add_listing_in_transaction_stmt FROM @add_listing_in_transaction_sql;
EXECUTE add_listing_in_transaction_stmt;
DEALLOCATE PREPARE add_listing_in_transaction_stmt;
SET @listing_price_exists := (
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'rental_listings'
AND column_name = 'price'
);
SET @add_listing_price_sql := IF(
@listing_price_exists = 0,
'ALTER TABLE rental_listings ADD COLUMN price DECIMAL(12,2) NOT NULL DEFAULT 0.00 AFTER owner_id',
'SELECT 1'
);
PREPARE add_listing_price_stmt FROM @add_listing_price_sql;
EXECUTE add_listing_price_stmt;
DEALLOCATE PREPARE add_listing_price_stmt;
UPDATE rental_listings
SET price = CASE
WHEN price_daily > 0 THEN price_daily
WHEN price_hourly > 0 THEN price_hourly * 24
WHEN price_weekly > 0 THEN price_weekly / 7
ELSE price
END
WHERE price <= 0;
INSERT INTO system_configs (`key`, `value`, description)
VALUES ('order.pending_payment_timeout_minutes', '15', '订单待支付超时取消分钟数')
ON DUPLICATE KEY UPDATE `key` = VALUES(`key`);