[Snow Team] backend-fixer: auto-commit work
This commit is contained in:
@@ -25,7 +25,8 @@ type FreezeRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DepositFreeQuotaRequest struct {
|
type DepositFreeQuotaRequest struct {
|
||||||
Amount float64 `json:"amount"`
|
AmountCent int64 `json:"amount_cent"`
|
||||||
|
Amount float64 `json:"amount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaginatedResult struct {
|
type PaginatedResult struct {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package adminuser
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"math"
|
||||||
|
|
||||||
"hfb_sys/backend/internal/auditlog"
|
"hfb_sys/backend/internal/auditlog"
|
||||||
"hfb_sys/backend/internal/model"
|
"hfb_sys/backend/internal/model"
|
||||||
@@ -60,24 +61,29 @@ func (r *Repository) Unfreeze(adminID uint64, userID uint64, meta AuditMeta) (*U
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) SetDepositFreeQuota(adminID uint64, userID uint64, req DepositFreeQuotaRequest, meta AuditMeta) (*UserDTO, error) {
|
func (r *Repository) SetDepositFreeQuota(adminID uint64, userID uint64, req DepositFreeQuotaRequest, meta AuditMeta) (*UserDTO, error) {
|
||||||
amount := roundMoney(req.Amount)
|
amountCent := depositFreeQuotaAmountCent(req)
|
||||||
if amount < 0 {
|
if amountCent < 0 {
|
||||||
return nil, ErrInvalidUser
|
return nil, ErrInvalidUser
|
||||||
}
|
}
|
||||||
|
amount := float64(amountCent) / 100
|
||||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
err := r.db.Transaction(func(tx *gorm.DB) error {
|
||||||
var user model.User
|
var user model.User
|
||||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, userID).Error; err != nil {
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, userID).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
beforeAmount := user.DepositFreeQuota
|
beforeAmount := user.DepositFreeQuota
|
||||||
|
beforeAmountCent := user.DepositFreeQuotaCent
|
||||||
user.DepositFreeQuota = amount
|
user.DepositFreeQuota = amount
|
||||||
|
user.DepositFreeQuotaCent = amountCent
|
||||||
if err := tx.Save(&user).Error; err != nil {
|
if err := tx.Save(&user).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return appendAuditLog(tx, adminID, "admin_user.set_deposit_free_quota", user.ID, meta, map[string]any{
|
return appendAuditLog(tx, adminID, "admin_user.set_deposit_free_quota", user.ID, meta, map[string]any{
|
||||||
"user_id": user.ID,
|
"user_id": user.ID,
|
||||||
"before_amount": beforeAmount,
|
"before_amount": beforeAmount,
|
||||||
"after_amount": amount,
|
"after_amount": amount,
|
||||||
|
"before_amount_cent": beforeAmountCent,
|
||||||
|
"after_amount_cent": amountCent,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -172,6 +178,13 @@ func roundMoney(value float64) float64 {
|
|||||||
return money.Round(value)
|
return money.Round(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func depositFreeQuotaAmountCent(req DepositFreeQuotaRequest) int64 {
|
||||||
|
if req.AmountCent != 0 {
|
||||||
|
return req.AmountCent
|
||||||
|
}
|
||||||
|
return int64(math.Round(req.Amount * 100))
|
||||||
|
}
|
||||||
|
|
||||||
func appendAuditLog(tx *gorm.DB, actorID uint64, action string, bizID uint64, meta AuditMeta, detail map[string]any) error {
|
func appendAuditLog(tx *gorm.DB, actorID uint64, action string, bizID uint64, meta AuditMeta, detail map[string]any) error {
|
||||||
return auditlog.Append(tx, auditlog.Entry{
|
return auditlog.Append(tx, auditlog.Entry{
|
||||||
ActorType: "admin",
|
ActorType: "admin",
|
||||||
|
|||||||
@@ -345,11 +345,20 @@ type arbitrationSettlement struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest, renterFrozenBalance float64) (arbitrationSettlement, error) {
|
func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest, renterFrozenBalance float64) (arbitrationSettlement, error) {
|
||||||
total := roundMoney(order.RentAmount + order.DepositAmount)
|
rentAmount := float64(order.RentAmountCent) / 100
|
||||||
ownerRentAmount := roundMoney(order.OwnerRentAmount)
|
if rentAmount <= 0 {
|
||||||
if ownerRentAmount <= 0 || ownerRentAmount > order.RentAmount {
|
rentAmount = order.RentAmount
|
||||||
ownerRentAmount = roundMoney(order.RentAmount)
|
|
||||||
}
|
}
|
||||||
|
depositAmount := float64(order.DepositAmountCent) / 100
|
||||||
|
if depositAmount <= 0 {
|
||||||
|
depositAmount = order.DepositAmount
|
||||||
|
}
|
||||||
|
ownerRentAmount := float64(order.OwnerRentAmountCent) / 100
|
||||||
|
if ownerRentAmount <= 0 || ownerRentAmount > rentAmount {
|
||||||
|
ownerRentAmount = rentAmount
|
||||||
|
}
|
||||||
|
total := roundMoney(rentAmount + depositAmount)
|
||||||
|
ownerRentAmount = roundMoney(ownerRentAmount)
|
||||||
settlement := arbitrationSettlement{}
|
settlement := arbitrationSettlement{}
|
||||||
orderID := order.ID
|
orderID := order.ID
|
||||||
releaseFrozenAmount := minMoney(total, roundMoney(renterFrozenBalance))
|
releaseFrozenAmount := minMoney(total, roundMoney(renterFrozenBalance))
|
||||||
@@ -398,21 +407,21 @@ func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest, r
|
|||||||
return settlement, ErrInvalidDispute
|
return settlement, ErrInvalidDispute
|
||||||
}
|
}
|
||||||
addRenterRefund(req.Amount, "仲裁部分退款")
|
addRenterRefund(req.Amount, "仲裁部分退款")
|
||||||
addOwnerIncome(minMoney(total-req.Amount, ownerRentAmount+order.DepositAmount), "仲裁剩余金额结算给号主")
|
addOwnerIncome(minMoney(total-req.Amount, ownerRentAmount+depositAmount), "仲裁剩余金额结算给号主")
|
||||||
case "release_deposit":
|
case "release_deposit":
|
||||||
addOwnerIncome(ownerRentAmount, "仲裁确认订单金额结算给号主")
|
addOwnerIncome(ownerRentAmount, "仲裁确认订单金额结算给号主")
|
||||||
addRenterRefund(order.DepositAmount, "仲裁释放押金给租客")
|
addRenterRefund(depositAmount, "仲裁释放押金给租客")
|
||||||
case "deduct_deposit", "compensate_owner":
|
case "deduct_deposit", "compensate_owner":
|
||||||
deductAmount := roundMoney(req.Amount)
|
deductAmount := roundMoney(req.Amount)
|
||||||
if deductAmount <= 0 {
|
if deductAmount <= 0 {
|
||||||
deductAmount = order.DepositAmount
|
deductAmount = depositAmount
|
||||||
}
|
}
|
||||||
if deductAmount > order.DepositAmount {
|
if deductAmount > depositAmount {
|
||||||
return settlement, ErrInvalidDispute
|
return settlement, ErrInvalidDispute
|
||||||
}
|
}
|
||||||
settlement.DepositDeductAmount = deductAmount
|
settlement.DepositDeductAmount = deductAmount
|
||||||
addOwnerIncome(ownerRentAmount+deductAmount, "仲裁订单金额及押金赔付结算给号主")
|
addOwnerIncome(ownerRentAmount+deductAmount, "仲裁订单金额及押金赔付结算给号主")
|
||||||
addRenterRefund(order.DepositAmount-deductAmount, "仲裁退回剩余押金给租客")
|
addRenterRefund(depositAmount-deductAmount, "仲裁退回剩余押金给租客")
|
||||||
case "order_close":
|
case "order_close":
|
||||||
// Only release frozen funds. No available-balance settlement happens in development mode.
|
// Only release frozen funds. No available-balance settlement happens in development mode.
|
||||||
case "mark_abnormal":
|
case "mark_abnormal":
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import (
|
|||||||
|
|
||||||
func TestBuildArbitrationSettlementSkipsFrozenReleaseWhenNoFrozenBalance(t *testing.T) {
|
func TestBuildArbitrationSettlementSkipsFrozenReleaseWhenNoFrozenBalance(t *testing.T) {
|
||||||
order := model.RentalOrder{
|
order := model.RentalOrder{
|
||||||
ID: 11,
|
ID: 11,
|
||||||
OrderNo: "RO202606080001",
|
OrderNo: "RO202606080001",
|
||||||
RenterID: 101,
|
RenterID: 101,
|
||||||
OwnerID: 202,
|
OwnerID: 202,
|
||||||
RentAmount: 200,
|
RentAmountCent: 20000,
|
||||||
OwnerRentAmount: 180,
|
OwnerRentAmountCent: 18000,
|
||||||
DepositAmount: 100,
|
DepositAmountCent: 10000,
|
||||||
}
|
}
|
||||||
|
|
||||||
settlement, err := buildArbitrationSettlement(order, ArbitrateRequest{
|
settlement, err := buildArbitrationSettlement(order, ArbitrateRequest{
|
||||||
@@ -46,13 +46,13 @@ func TestBuildArbitrationSettlementSkipsFrozenReleaseWhenNoFrozenBalance(t *test
|
|||||||
|
|
||||||
func TestBuildArbitrationSettlementLimitsFrozenReleaseToExistingBalance(t *testing.T) {
|
func TestBuildArbitrationSettlementLimitsFrozenReleaseToExistingBalance(t *testing.T) {
|
||||||
order := model.RentalOrder{
|
order := model.RentalOrder{
|
||||||
ID: 12,
|
ID: 12,
|
||||||
OrderNo: "RO202606080002",
|
OrderNo: "RO202606080002",
|
||||||
RenterID: 101,
|
RenterID: 101,
|
||||||
OwnerID: 202,
|
OwnerID: 202,
|
||||||
RentAmount: 200,
|
RentAmountCent: 20000,
|
||||||
OwnerRentAmount: 180,
|
OwnerRentAmountCent: 18000,
|
||||||
DepositAmount: 100,
|
DepositAmountCent: 10000,
|
||||||
}
|
}
|
||||||
|
|
||||||
settlement, err := buildArbitrationSettlement(order, ArbitrateRequest{
|
settlement, err := buildArbitrationSettlement(order, ArbitrateRequest{
|
||||||
@@ -69,8 +69,8 @@ func TestBuildArbitrationSettlementLimitsFrozenReleaseToExistingBalance(t *testi
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
releaseEntryCount++
|
releaseEntryCount++
|
||||||
if entry.Amount != 120 {
|
if entry.AmountCent != 12000 {
|
||||||
t.Fatalf("release frozen amount = %.1f, want 120.0", entry.Amount)
|
t.Fatalf("release frozen amount cent = %d, want 12000", entry.AmountCent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if releaseEntryCount != 1 {
|
if releaseEntryCount != 1 {
|
||||||
|
|||||||
@@ -82,14 +82,16 @@ func (r *Repository) Create(ownerID uint64, req CreateRequest, reviewRequired bo
|
|||||||
price := normalizedListingPrice(req)
|
price := normalizedListingPrice(req)
|
||||||
depositAmount := roundMoney(req.DepositAmount)
|
depositAmount := roundMoney(req.DepositAmount)
|
||||||
listing := model.RentalListing{
|
listing := model.RentalListing{
|
||||||
ListingNo: listingNo,
|
ListingNo: listingNo,
|
||||||
AccountID: account.ID,
|
AccountID: account.ID,
|
||||||
OwnerID: ownerID,
|
OwnerID: ownerID,
|
||||||
Price: price,
|
Price: price,
|
||||||
DepositAmount: depositAmount,
|
PriceCent: int64(math.Round(price * 100)),
|
||||||
Status: listingStatus,
|
DepositAmount: depositAmount,
|
||||||
ReviewStatus: reviewStatus,
|
DepositAmountCent: int64(math.Round(depositAmount * 100)),
|
||||||
PublishedAt: publishedAt,
|
Status: listingStatus,
|
||||||
|
ReviewStatus: reviewStatus,
|
||||||
|
PublishedAt: publishedAt,
|
||||||
}
|
}
|
||||||
if err := tx.Create(&listing).Error; err != nil {
|
if err := tx.Create(&listing).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -147,14 +149,18 @@ func (r *Repository) CreateFromExternalUpload(upload externalUploadCreate, req C
|
|||||||
if err := tx.Create(&account).Error; err != nil {
|
if err := tx.Create(&account).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
price := normalizedListingPrice(req)
|
||||||
|
depositAmount := roundMoney(req.DepositAmount)
|
||||||
listing := model.RentalListing{
|
listing := model.RentalListing{
|
||||||
ListingNo: listingNo,
|
ListingNo: listingNo,
|
||||||
AccountID: account.ID,
|
AccountID: account.ID,
|
||||||
OwnerID: owner.ID,
|
OwnerID: owner.ID,
|
||||||
Price: normalizedListingPrice(req),
|
Price: price,
|
||||||
DepositAmount: roundMoney(req.DepositAmount),
|
PriceCent: int64(math.Round(price * 100)),
|
||||||
Status: "draft",
|
DepositAmount: depositAmount,
|
||||||
ReviewStatus: "pending",
|
DepositAmountCent: int64(math.Round(depositAmount * 100)),
|
||||||
|
Status: "draft",
|
||||||
|
ReviewStatus: "pending",
|
||||||
}
|
}
|
||||||
if err := tx.Create(&listing).Error; err != nil {
|
if err := tx.Create(&listing).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1439,14 +1445,14 @@ func (row listingRow) toDTO() ListingDTO {
|
|||||||
screenshotURLS := cleanScreenshotURLs(decodeScreenshots(row.ScreenshotURLS))
|
screenshotURLS := cleanScreenshotURLs(decodeScreenshots(row.ScreenshotURLS))
|
||||||
reviewStatus, reviewReason := normalizedReviewState(row.Status, row.ReviewStatus, row.ReviewReason)
|
reviewStatus, reviewReason := normalizedReviewState(row.Status, row.ReviewStatus, row.ReviewReason)
|
||||||
return ListingDTO{
|
return ListingDTO{
|
||||||
ID: row.ID,
|
ID: row.ID,
|
||||||
ListingNo: row.ListingNo,
|
ListingNo: row.ListingNo,
|
||||||
AccountID: row.AccountID,
|
AccountID: row.AccountID,
|
||||||
OwnerID: row.OwnerID,
|
OwnerID: row.OwnerID,
|
||||||
OwnerPhone: row.OwnerPhone,
|
OwnerPhone: row.OwnerPhone,
|
||||||
OwnerNickname: row.OwnerNickname,
|
OwnerNickname: row.OwnerNickname,
|
||||||
Title: row.Title,
|
Title: row.Title,
|
||||||
Description: row.Description,
|
Description: row.Description,
|
||||||
GameName: row.GameName,
|
GameName: row.GameName,
|
||||||
ServerRegion: row.ServerRegion,
|
ServerRegion: row.ServerRegion,
|
||||||
LoginPlatform: row.LoginPlatform,
|
LoginPlatform: row.LoginPlatform,
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func TestCreateRequiresPublishAgreements(t *testing.T) {
|
|||||||
|
|
||||||
func TestApplySellerListingPriceUsesSellerTotalPrice(t *testing.T) {
|
func TestApplySellerListingPriceUsesSellerTotalPrice(t *testing.T) {
|
||||||
item := &ListingDTO{
|
item := &ListingDTO{
|
||||||
Price: 238,
|
PriceCent: 23800,
|
||||||
AssetSummary: map[string]any{
|
AssetSummary: map[string]any{
|
||||||
"price_breakdown": map[string]any{
|
"price_breakdown": map[string]any{
|
||||||
"seller_total_price": 200,
|
"seller_total_price": 200,
|
||||||
@@ -79,14 +79,14 @@ func TestApplySellerListingPriceUsesSellerTotalPrice(t *testing.T) {
|
|||||||
|
|
||||||
applySellerListingPrice(item)
|
applySellerListingPrice(item)
|
||||||
|
|
||||||
if item.Price != 200 {
|
if item.PriceCent != 20000 {
|
||||||
t.Fatalf("expected seller price 200, got %.2f", item.Price)
|
t.Fatalf("expected seller price 20000, got %d", item.PriceCent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApplySellerListingPriceKeepsFallbackPrice(t *testing.T) {
|
func TestApplySellerListingPriceKeepsFallbackPrice(t *testing.T) {
|
||||||
item := &ListingDTO{
|
item := &ListingDTO{
|
||||||
Price: 238,
|
PriceCent: 23800,
|
||||||
AssetSummary: map[string]any{
|
AssetSummary: map[string]any{
|
||||||
"price_breakdown": map[string]any{
|
"price_breakdown": map[string]any{
|
||||||
"seller_total_price": 0,
|
"seller_total_price": 0,
|
||||||
@@ -96,8 +96,8 @@ func TestApplySellerListingPriceKeepsFallbackPrice(t *testing.T) {
|
|||||||
|
|
||||||
applySellerListingPrice(item)
|
applySellerListingPrice(item)
|
||||||
|
|
||||||
if item.Price != 238 {
|
if item.PriceCent != 23800 {
|
||||||
t.Fatalf("expected fallback price 238, got %.2f", item.Price)
|
t.Fatalf("expected fallback price 23800, got %d", item.PriceCent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -185,11 +185,17 @@ func (r *Repository) Create(renterID uint64, req CreateRequest) (*OrderDTO, erro
|
|||||||
OwnerID: listing.OwnerID,
|
OwnerID: listing.OwnerID,
|
||||||
RenterID: renterID,
|
RenterID: renterID,
|
||||||
EstimatedDurationHours: rentHours,
|
EstimatedDurationHours: rentHours,
|
||||||
|
RentAmount: float64(pricing.RentAmountCent) / 100,
|
||||||
RentAmountCent: pricing.RentAmountCent,
|
RentAmountCent: pricing.RentAmountCent,
|
||||||
|
OwnerRentAmount: float64(pricing.OwnerRentAmountCent) / 100,
|
||||||
OwnerRentAmountCent: pricing.OwnerRentAmountCent,
|
OwnerRentAmountCent: pricing.OwnerRentAmountCent,
|
||||||
|
DepositAmount: paidDepositAmount,
|
||||||
DepositAmountCent: int64(math.Round(paidDepositAmount * 100)),
|
DepositAmountCent: int64(math.Round(paidDepositAmount * 100)),
|
||||||
|
DepositOriginalAmount: depositOriginalAmount,
|
||||||
DepositOriginalAmountCent: int64(math.Round(depositOriginalAmount * 100)),
|
DepositOriginalAmountCent: int64(math.Round(depositOriginalAmount * 100)),
|
||||||
|
DepositWaivedAmount: waivedDepositAmount,
|
||||||
DepositWaivedAmountCent: int64(math.Round(waivedDepositAmount * 100)),
|
DepositWaivedAmountCent: int64(math.Round(waivedDepositAmount * 100)),
|
||||||
|
PlatformFee: float64(pricing.PlatformFeeCent) / 100,
|
||||||
PlatformFeeCent: pricing.PlatformFeeCent,
|
PlatformFeeCent: pricing.PlatformFeeCent,
|
||||||
AccountSnapshot: snapshot,
|
AccountSnapshot: snapshot,
|
||||||
Status: "pending_payment",
|
Status: "pending_payment",
|
||||||
@@ -690,10 +696,10 @@ func (r *Repository) CounterCheckout(userID uint64, orderID uint64, req CounterC
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dto := toCheckoutDTOForUser(*checkout, userID, model.RentalOrder{
|
dto := toCheckoutDTOForUser(*checkout, userID, model.RentalOrder{
|
||||||
OwnerID: userID,
|
OwnerID: userID,
|
||||||
RentAmountCent: int64(math.Round(checkout.RentAmount * 100)),
|
RentAmountCent: int64(math.Round(checkout.RentAmount * 100)),
|
||||||
OwnerRentAmountCent: int64(math.Round(checkout.OwnerRentAmount * 100)),
|
OwnerRentAmountCent: int64(math.Round(checkout.OwnerRentAmount * 100)),
|
||||||
DepositAmountCent: int64(math.Round(checkout.DepositAmount * 100)),
|
DepositAmountCent: int64(math.Round(checkout.DepositAmount * 100)),
|
||||||
})
|
})
|
||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
@@ -1244,21 +1250,30 @@ func buildCheckout(order model.RentalOrder, initiatedBy uint64, status string, c
|
|||||||
return model.OrderCheckout{}, err
|
return model.OrderCheckout{}, err
|
||||||
}
|
}
|
||||||
return model.OrderCheckout{
|
return model.OrderCheckout{
|
||||||
OrderID: order.ID,
|
OrderID: order.ID,
|
||||||
InitiatedBy: initiatedBy,
|
InitiatedBy: initiatedBy,
|
||||||
Status: status,
|
Status: status,
|
||||||
RentAmount: float64(settlement.ActualRentAmountCent) / 100,
|
RentAmount: float64(settlement.ActualRentAmountCent) / 100,
|
||||||
OwnerRentAmount: float64(settlement.OwnerRentIncomeCent) / 100,
|
RentAmountCent: settlement.ActualRentAmountCent,
|
||||||
PlatformFee: float64(settlement.PlatformFeeCent) / 100,
|
OwnerRentAmount: float64(settlement.OwnerRentIncomeCent) / 100,
|
||||||
DepositAmount: depositAmountFromCent,
|
OwnerRentAmountCent: settlement.OwnerRentIncomeCent,
|
||||||
ConsumableAmount: consumableAmount,
|
PlatformFee: float64(settlement.PlatformFeeCent) / 100,
|
||||||
CoinConsumedM: roundQuantity(coinConsumedM),
|
PlatformFeeCent: settlement.PlatformFeeCent,
|
||||||
OtherAmount: otherAmount,
|
DepositAmount: depositAmountFromCent,
|
||||||
DepositDeductAmount: roundMoney(deductAmount),
|
DepositAmountCent: order.DepositAmountCent,
|
||||||
RenterRefundAmount: float64(settlement.RenterRefundCent) / 100,
|
ConsumableAmount: consumableAmount,
|
||||||
OwnerIncomeAmount: float64(settlement.OwnerIncomeCent) / 100,
|
ConsumableAmountCent: int64(math.Round(consumableAmount * 100)),
|
||||||
Content: content,
|
CoinConsumedM: roundQuantity(coinConsumedM),
|
||||||
EvidenceURLS: evidence,
|
OtherAmount: otherAmount,
|
||||||
|
OtherAmountCent: int64(math.Round(otherAmount * 100)),
|
||||||
|
DepositDeductAmount: roundMoney(deductAmount),
|
||||||
|
DepositDeductAmountCent: settlement.DepositCompensationCent,
|
||||||
|
RenterRefundAmount: float64(settlement.RenterRefundCent) / 100,
|
||||||
|
RenterRefundAmountCent: settlement.RenterRefundCent,
|
||||||
|
OwnerIncomeAmount: float64(settlement.OwnerIncomeCent) / 100,
|
||||||
|
OwnerIncomeAmountCent: settlement.OwnerIncomeCent,
|
||||||
|
Content: content,
|
||||||
|
EvidenceURLS: evidence,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import (
|
|||||||
|
|
||||||
func TestCalculateCheckoutSettlementRefundsUnusedRent(t *testing.T) {
|
func TestCalculateCheckoutSettlementRefundsUnusedRent(t *testing.T) {
|
||||||
order := model.RentalOrder{
|
order := model.RentalOrder{
|
||||||
RentAmount: 383,
|
RentAmountCent: 38300,
|
||||||
OwnerRentAmount: 353,
|
OwnerRentAmountCent: 35300,
|
||||||
DepositAmount: 150,
|
DepositAmountCent: 15000,
|
||||||
AccountSnapshot: datatypes.JSON([]byte(`{
|
AccountSnapshot: datatypes.JSON([]byte(`{
|
||||||
"haf_coin_amount": 100000000,
|
"haf_coin_amount": 100000000,
|
||||||
"asset_summary": {
|
"asset_summary": {
|
||||||
@@ -30,35 +30,35 @@ func TestCalculateCheckoutSettlementRefundsUnusedRent(t *testing.T) {
|
|||||||
settlement := calculateCheckoutSettlement(order, 7, 90, 0)
|
settlement := calculateCheckoutSettlement(order, 7, 90, 0)
|
||||||
|
|
||||||
// 角精度:243.7 = roundMoney(236.7 + 7)
|
// 角精度:243.7 = roundMoney(236.7 + 7)
|
||||||
if settlement.ActualRentAmount != 243.7 {
|
if float64(settlement.ActualRentAmountCent)/100 != 243.7 {
|
||||||
t.Fatalf("ActualRentAmount = %.1f, want 243.7", settlement.ActualRentAmount)
|
t.Fatalf("ActualRentAmount = %.1f, want 243.7", float64(settlement.ActualRentAmountCent)/100)
|
||||||
}
|
}
|
||||||
// 角精度:216.7 = roundMoney(209.7 + 7) 卖家币价+消耗品
|
// 角精度:216.7 = roundMoney(209.7 + 7) 卖家币价+消耗品
|
||||||
if settlement.OwnerRentIncome != 216.7 {
|
if float64(settlement.OwnerRentIncomeCent)/100 != 216.7 {
|
||||||
t.Fatalf("OwnerRentIncome = %.1f, want 216.7", settlement.OwnerRentIncome)
|
t.Fatalf("OwnerRentIncome = %.1f, want 216.7", float64(settlement.OwnerRentIncomeCent)/100)
|
||||||
}
|
}
|
||||||
// 角精度:27.0 = roundMoney(27) 平台费
|
// 角精度:27.0 = roundMoney(27) 平台费
|
||||||
if settlement.PlatformFee != 27.0 {
|
if float64(settlement.PlatformFeeCent)/100 != 27.0 {
|
||||||
t.Fatalf("PlatformFee = %.1f, want 27.0", settlement.PlatformFee)
|
t.Fatalf("PlatformFee = %.1f, want 27.0", float64(settlement.PlatformFeeCent)/100)
|
||||||
}
|
}
|
||||||
// 角精度:139.3 = roundMoney(383 - 243.7)
|
// 角精度:139.3 = roundMoney(383 - 243.7)
|
||||||
if settlement.RentRefund != 139.3 {
|
if float64(settlement.RentRefundCent)/100 != 139.3 {
|
||||||
t.Fatalf("RentRefund = %.1f, want 139.3", settlement.RentRefund)
|
t.Fatalf("RentRefund = %.1f, want 139.3", float64(settlement.RentRefundCent)/100)
|
||||||
}
|
}
|
||||||
if settlement.DepositRefund != 150 {
|
if float64(settlement.DepositRefundCent)/100 != 150 {
|
||||||
t.Fatalf("DepositRefund = %.1f, want 150.0", settlement.DepositRefund)
|
t.Fatalf("DepositRefund = %.1f, want 150.0", float64(settlement.DepositRefundCent)/100)
|
||||||
}
|
}
|
||||||
// 角精度:289.3 = roundMoney(139.3 + 150)
|
// 角精度:289.3 = roundMoney(139.3 + 150)
|
||||||
if settlement.RenterRefund != 289.3 {
|
if float64(settlement.RenterRefundCent)/100 != 289.3 {
|
||||||
t.Fatalf("RenterRefund = %.1f, want 289.3", settlement.RenterRefund)
|
t.Fatalf("RenterRefund = %.1f, want 289.3", float64(settlement.RenterRefundCent)/100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalculateCheckoutSettlementUsesBuyerAndSellerRatiosSeparately(t *testing.T) {
|
func TestCalculateCheckoutSettlementUsesBuyerAndSellerRatiosSeparately(t *testing.T) {
|
||||||
order := model.RentalOrder{
|
order := model.RentalOrder{
|
||||||
RentAmount: 383,
|
RentAmountCent: 38300,
|
||||||
OwnerRentAmount: 353,
|
OwnerRentAmountCent: 35300,
|
||||||
DepositAmount: 150,
|
DepositAmountCent: 15000,
|
||||||
AccountSnapshot: datatypes.JSON([]byte(`{
|
AccountSnapshot: datatypes.JSON([]byte(`{
|
||||||
"haf_coin_amount": 100000000,
|
"haf_coin_amount": 100000000,
|
||||||
"asset_summary": {
|
"asset_summary": {
|
||||||
@@ -74,24 +74,24 @@ func TestCalculateCheckoutSettlementUsesBuyerAndSellerRatiosSeparately(t *testin
|
|||||||
settlement := calculateCheckoutSettlement(order, 0, 50, 0)
|
settlement := calculateCheckoutSettlement(order, 0, 50, 0)
|
||||||
|
|
||||||
// 角精度:131.5 = roundMoney(131.5)
|
// 角精度:131.5 = roundMoney(131.5)
|
||||||
if settlement.ActualRentAmount != 131.5 {
|
if float64(settlement.ActualRentAmountCent)/100 != 131.5 {
|
||||||
t.Fatalf("租客侧实际租金 = %.1f, want 131.5", settlement.ActualRentAmount)
|
t.Fatalf("租客侧实际租金 = %.1f, want 131.5", float64(settlement.ActualRentAmountCent)/100)
|
||||||
}
|
}
|
||||||
// 角精度:116.5 = roundMoney(116.5)
|
// 角精度:116.5 = roundMoney(116.5)
|
||||||
if settlement.OwnerRentIncome != 116.5 {
|
if float64(settlement.OwnerRentIncomeCent)/100 != 116.5 {
|
||||||
t.Fatalf("卖家侧租金收入 = %.1f, want 116.5", settlement.OwnerRentIncome)
|
t.Fatalf("卖家侧租金收入 = %.1f, want 116.5", float64(settlement.OwnerRentIncomeCent)/100)
|
||||||
}
|
}
|
||||||
// 角精度:15.0 = roundMoney(15)
|
// 角精度:15.0 = roundMoney(15)
|
||||||
if settlement.PlatformFee != 15.0 {
|
if float64(settlement.PlatformFeeCent)/100 != 15.0 {
|
||||||
t.Fatalf("平台差价 = %.1f, want 15.0", settlement.PlatformFee)
|
t.Fatalf("平台差价 = %.1f, want 15.0", float64(settlement.PlatformFeeCent)/100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalculateCheckoutSettlementAddsDepositCompensation(t *testing.T) {
|
func TestCalculateCheckoutSettlementAddsDepositCompensation(t *testing.T) {
|
||||||
order := model.RentalOrder{
|
order := model.RentalOrder{
|
||||||
RentAmount: 383,
|
RentAmountCent: 38300,
|
||||||
OwnerRentAmount: 353,
|
OwnerRentAmountCent: 35300,
|
||||||
DepositAmount: 150,
|
DepositAmountCent: 15000,
|
||||||
AccountSnapshot: datatypes.JSON([]byte(`{
|
AccountSnapshot: datatypes.JSON([]byte(`{
|
||||||
"haf_coin_amount": 100000000,
|
"haf_coin_amount": 100000000,
|
||||||
"asset_summary": {
|
"asset_summary": {
|
||||||
@@ -106,20 +106,20 @@ func TestCalculateCheckoutSettlementAddsDepositCompensation(t *testing.T) {
|
|||||||
|
|
||||||
settlement := calculateCheckoutSettlement(order, 120, 100, 30)
|
settlement := calculateCheckoutSettlement(order, 120, 100, 30)
|
||||||
|
|
||||||
if settlement.ActualRentAmount != 383 {
|
if float64(settlement.ActualRentAmountCent)/100 != 383 {
|
||||||
t.Fatalf("ActualRentAmount = %.2f, want 383.00", settlement.ActualRentAmount)
|
t.Fatalf("ActualRentAmount = %.2f, want 383.00", float64(settlement.ActualRentAmountCent)/100)
|
||||||
}
|
}
|
||||||
if settlement.OwnerRentIncome != 353 {
|
if float64(settlement.OwnerRentIncomeCent)/100 != 353 {
|
||||||
t.Fatalf("OwnerRentIncome = %.2f, want 353.00", settlement.OwnerRentIncome)
|
t.Fatalf("OwnerRentIncome = %.2f, want 353.00", float64(settlement.OwnerRentIncomeCent)/100)
|
||||||
}
|
}
|
||||||
if settlement.DepositCompensation != 30 {
|
if float64(settlement.DepositCompensationCent)/100 != 30 {
|
||||||
t.Fatalf("DepositCompensation = %.2f, want 30.00", settlement.DepositCompensation)
|
t.Fatalf("DepositCompensation = %.2f, want 30.00", float64(settlement.DepositCompensationCent)/100)
|
||||||
}
|
}
|
||||||
if settlement.OwnerIncome != 383 {
|
if float64(settlement.OwnerIncomeCent)/100 != 383 {
|
||||||
t.Fatalf("OwnerIncome = %.2f, want 383.00", settlement.OwnerIncome)
|
t.Fatalf("OwnerIncome = %.2f, want 383.00", float64(settlement.OwnerIncomeCent)/100)
|
||||||
}
|
}
|
||||||
if settlement.RenterRefund != 120 {
|
if float64(settlement.RenterRefundCent)/100 != 120 {
|
||||||
t.Fatalf("RenterRefund = %.2f, want 120.00", settlement.RenterRefund)
|
t.Fatalf("RenterRefund = %.2f, want 120.00", float64(settlement.RenterRefundCent)/100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import (
|
|||||||
|
|
||||||
func TestApplyEntryRoundsMoneyBeforeComparing(t *testing.T) {
|
func TestApplyEntryRoundsMoneyBeforeComparing(t *testing.T) {
|
||||||
account := model.WalletAccount{
|
account := model.WalletAccount{
|
||||||
UserID: 7,
|
UserID: 7,
|
||||||
FrozenBalance: 606.41,
|
FrozenBalanceCent: 60641,
|
||||||
}
|
}
|
||||||
entry := Entry{
|
entry := Entry{
|
||||||
UserID: 7,
|
UserID: 7,
|
||||||
Direction: "out",
|
Direction: "out",
|
||||||
Amount: 406.41 + 200.00,
|
AmountCent: 60641,
|
||||||
BalanceType: "frozen",
|
BalanceType: "frozen",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,20 +26,20 @@ func TestApplyEntryRoundsMoneyBeforeComparing(t *testing.T) {
|
|||||||
if balanceAfter != 0 {
|
if balanceAfter != 0 {
|
||||||
t.Fatalf("balanceAfter = %v, want 0", balanceAfter)
|
t.Fatalf("balanceAfter = %v, want 0", balanceAfter)
|
||||||
}
|
}
|
||||||
if account.FrozenBalance != 0 {
|
if account.FrozenBalanceCent != 0 {
|
||||||
t.Fatalf("FrozenBalance = %v, want 0", account.FrozenBalance)
|
t.Fatalf("FrozenBalanceCent = %d, want 0", account.FrozenBalanceCent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApplyEntryKeepsWalletMoneyAtJiaoPrecision(t *testing.T) {
|
func TestApplyEntryKeepsWalletMoneyAtJiaoPrecision(t *testing.T) {
|
||||||
account := model.WalletAccount{
|
account := model.WalletAccount{
|
||||||
UserID: 8,
|
UserID: 8,
|
||||||
AvailableBalance: 0,
|
AvailableBalanceCent: 0,
|
||||||
}
|
}
|
||||||
entry := Entry{
|
entry := Entry{
|
||||||
UserID: 8,
|
UserID: 8,
|
||||||
Direction: "in",
|
Direction: "in",
|
||||||
Amount: 2.30,
|
AmountCent: 230,
|
||||||
BalanceType: "available",
|
BalanceType: "available",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,11 +47,11 @@ func TestApplyEntryKeepsWalletMoneyAtJiaoPrecision(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("applyEntry() error = %v", err)
|
t.Fatalf("applyEntry() error = %v", err)
|
||||||
}
|
}
|
||||||
if balanceAfter != 2.3 {
|
if balanceAfter != 230 {
|
||||||
t.Fatalf("balanceAfter = %v, want 2.3", balanceAfter)
|
t.Fatalf("balanceAfter = %d, want 230", balanceAfter)
|
||||||
}
|
}
|
||||||
if account.AvailableBalance != 2.3 {
|
if account.AvailableBalanceCent != 230 {
|
||||||
t.Fatalf("AvailableBalance = %v, want 2.3", account.AvailableBalance)
|
t.Fatalf("AvailableBalanceCent = %d, want 230", account.AvailableBalanceCent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rounded := roundWalletMoney(2.36); rounded != 2.4 {
|
if rounded := roundWalletMoney(2.36); rounded != 2.4 {
|
||||||
|
|||||||
@@ -58,8 +58,11 @@ func (r *Repository) Create(userID uint64, req CreateWithdrawalRequest) (*Withdr
|
|||||||
withdrawal := model.WithdrawalRequest{
|
withdrawal := model.WithdrawalRequest{
|
||||||
WithdrawNo: withdrawNo,
|
WithdrawNo: withdrawNo,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
|
Amount: float64(req.AmountCent) / 100,
|
||||||
AmountCent: req.AmountCent,
|
AmountCent: req.AmountCent,
|
||||||
|
Fee: float64(feeCent) / 100,
|
||||||
FeeCent: feeCent,
|
FeeCent: feeCent,
|
||||||
|
ActualAmount: float64(actualAmountCent) / 100,
|
||||||
ActualAmountCent: actualAmountCent,
|
ActualAmountCent: actualAmountCent,
|
||||||
PaymentAccountID: &req.PaymentAccountID,
|
PaymentAccountID: &req.PaymentAccountID,
|
||||||
AccountType: paymentAccount.AccountType,
|
AccountType: paymentAccount.AccountType,
|
||||||
|
|||||||
@@ -8,49 +8,61 @@
|
|||||||
|
|
||||||
-- 用户表:免押额度
|
-- 用户表:免押额度
|
||||||
ALTER TABLE users
|
ALTER TABLE users
|
||||||
ADD COLUMN deposit_free_quota_cent BIGINT NOT NULL DEFAULT 0 COMMENT '免押总额度(分)' AFTER deposit_free_quota;
|
ADD COLUMN IF NOT EXISTS deposit_free_quota_cent BIGINT NOT NULL DEFAULT 0 COMMENT '免押总额度(分)' AFTER deposit_free_quota;
|
||||||
|
|
||||||
-- 商品表:价格和押金
|
-- 商品表:价格和押金
|
||||||
ALTER TABLE rental_listings
|
ALTER TABLE rental_listings
|
||||||
ADD COLUMN price_cent BIGINT NOT NULL DEFAULT 0 COMMENT '租金(分/小时)' AFTER price,
|
ADD COLUMN IF NOT EXISTS price_cent BIGINT NOT NULL DEFAULT 0 COMMENT '租金(分/小时)' AFTER price,
|
||||||
ADD COLUMN deposit_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '押金金额(分)' AFTER deposit_amount;
|
ADD COLUMN IF NOT EXISTS deposit_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '押金金额(分)' AFTER deposit_amount;
|
||||||
|
|
||||||
-- 订单表:租金、押金、平台费
|
-- 订单表:租金、押金、平台费
|
||||||
ALTER TABLE rental_orders
|
ALTER TABLE rental_orders
|
||||||
ADD COLUMN rent_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '租金总额(分)' AFTER rent_amount,
|
ADD COLUMN IF NOT EXISTS rent_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '租金总额(分)' AFTER rent_amount,
|
||||||
ADD COLUMN owner_rent_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '号主实得租金(分)' AFTER owner_rent_amount,
|
ADD COLUMN IF NOT EXISTS owner_rent_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '号主实得租金(分)' AFTER owner_rent_amount,
|
||||||
ADD COLUMN deposit_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '实际收取押金(分)' AFTER deposit_amount,
|
ADD COLUMN IF NOT EXISTS deposit_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '实际收取押金(分)' AFTER deposit_amount,
|
||||||
ADD COLUMN deposit_original_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '商品原始押金(分)' AFTER deposit_original_amount,
|
ADD COLUMN IF NOT EXISTS deposit_original_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '商品原始押金(分)' AFTER deposit_original_amount,
|
||||||
ADD COLUMN deposit_waived_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '免押抵扣金额(分)' AFTER deposit_waived_amount,
|
ADD COLUMN IF NOT EXISTS deposit_waived_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '免押抵扣金额(分)' AFTER deposit_waived_amount,
|
||||||
ADD COLUMN platform_fee_cent BIGINT NOT NULL DEFAULT 0 COMMENT '平台手续费(分)' AFTER platform_fee;
|
ADD COLUMN IF NOT EXISTS platform_fee_cent BIGINT NOT NULL DEFAULT 0 COMMENT '平台手续费(分)' AFTER platform_fee;
|
||||||
|
|
||||||
-- 结算记录表:所有金额字段
|
-- 结算记录表:所有金额字段
|
||||||
ALTER TABLE order_checkouts
|
ALTER TABLE order_checkouts
|
||||||
ADD COLUMN rent_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '租金(分)' AFTER rent_amount,
|
ADD COLUMN IF NOT EXISTS rent_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '租金(分)' AFTER rent_amount,
|
||||||
ADD COLUMN owner_rent_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '号主实得租金(分)' AFTER owner_rent_amount,
|
ADD COLUMN IF NOT EXISTS owner_rent_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '号主实得租金(分)' AFTER owner_rent_amount,
|
||||||
ADD COLUMN platform_fee_cent BIGINT NOT NULL DEFAULT 0 COMMENT '平台手续费(分)' AFTER platform_fee,
|
ADD COLUMN IF NOT EXISTS platform_fee_cent BIGINT NOT NULL DEFAULT 0 COMMENT '平台手续费(分)' AFTER platform_fee,
|
||||||
ADD COLUMN deposit_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '押金(分)' AFTER deposit_amount,
|
ADD COLUMN IF NOT EXISTS deposit_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '押金(分)' AFTER deposit_amount,
|
||||||
ADD COLUMN consumable_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '消耗品扣费(分)' AFTER consumable_amount,
|
ADD COLUMN IF NOT EXISTS consumable_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '消耗品扣费(分)' AFTER consumable_amount,
|
||||||
ADD COLUMN other_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '其他费用(分)' AFTER other_amount,
|
ADD COLUMN IF NOT EXISTS other_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '其他费用(分)' AFTER other_amount,
|
||||||
ADD COLUMN deposit_deduct_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '押金扣除金额(分)' AFTER deposit_deduct_amount,
|
ADD COLUMN IF NOT EXISTS deposit_deduct_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '押金扣除金额(分)' AFTER deposit_deduct_amount,
|
||||||
ADD COLUMN renter_refund_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '租客退款金额(分)' AFTER renter_refund_amount,
|
ADD COLUMN IF NOT EXISTS renter_refund_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '租客退款金额(分)' AFTER renter_refund_amount,
|
||||||
ADD COLUMN owner_income_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '号主收入金额(分)' AFTER owner_income_amount;
|
ADD COLUMN IF NOT EXISTS owner_income_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '号主收入金额(分)' AFTER owner_income_amount;
|
||||||
|
|
||||||
-- 钱包账户表:余额
|
-- 钱包账户表:余额
|
||||||
ALTER TABLE wallet_accounts
|
ALTER TABLE wallet_accounts
|
||||||
ADD COLUMN available_balance_cent BIGINT NOT NULL DEFAULT 0 COMMENT '可用余额(分)' AFTER available_balance,
|
ADD COLUMN IF NOT EXISTS available_balance_cent BIGINT NOT NULL DEFAULT 0 COMMENT '可用余额(分)' AFTER available_balance,
|
||||||
ADD COLUMN frozen_balance_cent BIGINT NOT NULL DEFAULT 0 COMMENT '冻结余额(分)' AFTER frozen_balance;
|
ADD COLUMN IF NOT EXISTS frozen_balance_cent BIGINT NOT NULL DEFAULT 0 COMMENT '冻结余额(分)' AFTER frozen_balance;
|
||||||
|
|
||||||
-- 钱包流水表:金额和余额
|
-- 钱包流水表:金额和余额
|
||||||
ALTER TABLE wallet_ledger
|
ALTER TABLE wallet_ledger
|
||||||
ADD COLUMN amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '金额(分)' AFTER amount,
|
ADD COLUMN IF NOT EXISTS amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '金额(分)' AFTER amount,
|
||||||
ADD COLUMN balance_after_cent BIGINT NOT NULL DEFAULT 0 COMMENT '变动后余额(分)' AFTER balance_after;
|
ADD COLUMN IF NOT EXISTS balance_after_cent BIGINT NOT NULL DEFAULT 0 COMMENT '变动后余额(分)' AFTER balance_after;
|
||||||
|
|
||||||
-- 提现表:如果存在的话
|
-- 提现表是可选模块;仅在表存在时修改,避免缺表环境迁移失败。
|
||||||
ALTER TABLE withdrawal_requests
|
SET @withdrawal_requests_exists := (
|
||||||
ADD COLUMN amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '提现金额(分)' AFTER amount,
|
SELECT COUNT(*)
|
||||||
ADD COLUMN fee_cent BIGINT NOT NULL DEFAULT 0 COMMENT '手续费(分)' AFTER fee,
|
FROM information_schema.tables
|
||||||
ADD COLUMN actual_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT '实际到账(分)' AFTER actual_amount;
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'withdrawal_requests'
|
||||||
|
);
|
||||||
|
SET @sql := IF(@withdrawal_requests_exists > 0,
|
||||||
|
'ALTER TABLE withdrawal_requests
|
||||||
|
ADD COLUMN IF NOT EXISTS amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT ''提现金额(分)'' AFTER amount,
|
||||||
|
ADD COLUMN IF NOT EXISTS fee_cent BIGINT NOT NULL DEFAULT 0 COMMENT ''手续费(分)'' AFTER fee,
|
||||||
|
ADD COLUMN IF NOT EXISTS actual_amount_cent BIGINT NOT NULL DEFAULT 0 COMMENT ''实际到账(分)'' AFTER actual_amount',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
-- ============================================
|
-- ============================================
|
||||||
-- 数据迁移:从 DECIMAL 复制到 BIGINT(分)
|
-- 数据迁移:从 DECIMAL 复制到 BIGINT(分)
|
||||||
@@ -58,59 +70,66 @@ ALTER TABLE withdrawal_requests
|
|||||||
-- ============================================
|
-- ============================================
|
||||||
|
|
||||||
-- 用户免押额度
|
-- 用户免押额度
|
||||||
UPDATE users SET deposit_free_quota_cent = ROUND(deposit_free_quota * 100) WHERE deposit_free_quota > 0;
|
UPDATE users
|
||||||
|
SET deposit_free_quota_cent = ROUND(deposit_free_quota * 100)
|
||||||
|
WHERE deposit_free_quota > 0;
|
||||||
|
|
||||||
-- 商品价格和押金
|
-- 商品价格和押金
|
||||||
UPDATE rental_listings SET
|
UPDATE rental_listings
|
||||||
price_cent = ROUND(price * 100),
|
SET price_cent = ROUND(price * 100),
|
||||||
deposit_amount_cent = ROUND(deposit_amount * 100)
|
deposit_amount_cent = ROUND(deposit_amount * 100)
|
||||||
WHERE price > 0 OR deposit_amount > 0;
|
WHERE price > 0 OR deposit_amount > 0;
|
||||||
|
|
||||||
-- 订单金额
|
-- 订单金额
|
||||||
UPDATE rental_orders SET
|
UPDATE rental_orders
|
||||||
rent_amount_cent = ROUND(rent_amount * 100),
|
SET rent_amount_cent = ROUND(rent_amount * 100),
|
||||||
owner_rent_amount_cent = ROUND(owner_rent_amount * 100),
|
owner_rent_amount_cent = ROUND(owner_rent_amount * 100),
|
||||||
deposit_amount_cent = ROUND(deposit_amount * 100),
|
deposit_amount_cent = ROUND(deposit_amount * 100),
|
||||||
deposit_original_amount_cent = ROUND(deposit_original_amount * 100),
|
deposit_original_amount_cent = ROUND(deposit_original_amount * 100),
|
||||||
deposit_waived_amount_cent = ROUND(deposit_waived_amount * 100),
|
deposit_waived_amount_cent = ROUND(deposit_waived_amount * 100),
|
||||||
platform_fee_cent = ROUND(platform_fee * 100)
|
platform_fee_cent = ROUND(platform_fee * 100)
|
||||||
WHERE rent_amount > 0 OR owner_rent_amount > 0 OR deposit_amount > 0
|
WHERE rent_amount > 0 OR owner_rent_amount > 0 OR deposit_amount > 0
|
||||||
OR deposit_original_amount > 0 OR deposit_waived_amount > 0 OR platform_fee > 0;
|
OR deposit_original_amount > 0 OR deposit_waived_amount > 0 OR platform_fee > 0;
|
||||||
|
|
||||||
-- 结算记录
|
-- 结算记录
|
||||||
UPDATE order_checkouts SET
|
UPDATE order_checkouts
|
||||||
rent_amount_cent = ROUND(rent_amount * 100),
|
SET rent_amount_cent = ROUND(rent_amount * 100),
|
||||||
owner_rent_amount_cent = ROUND(owner_rent_amount * 100),
|
owner_rent_amount_cent = ROUND(owner_rent_amount * 100),
|
||||||
platform_fee_cent = ROUND(platform_fee * 100),
|
platform_fee_cent = ROUND(platform_fee * 100),
|
||||||
deposit_amount_cent = ROUND(deposit_amount * 100),
|
deposit_amount_cent = ROUND(deposit_amount * 100),
|
||||||
consumable_amount_cent = ROUND(consumable_amount * 100),
|
consumable_amount_cent = ROUND(consumable_amount * 100),
|
||||||
other_amount_cent = ROUND(other_amount * 100),
|
other_amount_cent = ROUND(other_amount * 100),
|
||||||
deposit_deduct_amount_cent = ROUND(deposit_deduct_amount * 100),
|
deposit_deduct_amount_cent = ROUND(deposit_deduct_amount * 100),
|
||||||
renter_refund_amount_cent = ROUND(renter_refund_amount * 100),
|
renter_refund_amount_cent = ROUND(renter_refund_amount * 100),
|
||||||
owner_income_amount_cent = ROUND(owner_income_amount * 100)
|
owner_income_amount_cent = ROUND(owner_income_amount * 100)
|
||||||
WHERE rent_amount > 0 OR owner_rent_amount > 0 OR platform_fee > 0
|
WHERE rent_amount > 0 OR owner_rent_amount > 0 OR platform_fee > 0
|
||||||
OR deposit_amount > 0 OR consumable_amount > 0 OR other_amount > 0
|
OR deposit_amount > 0 OR consumable_amount > 0 OR other_amount > 0
|
||||||
OR deposit_deduct_amount > 0 OR renter_refund_amount > 0 OR owner_income_amount > 0;
|
OR deposit_deduct_amount > 0 OR renter_refund_amount > 0 OR owner_income_amount > 0;
|
||||||
|
|
||||||
-- 钱包余额
|
-- 钱包余额
|
||||||
UPDATE wallet_accounts SET
|
UPDATE wallet_accounts
|
||||||
available_balance_cent = ROUND(available_balance * 100),
|
SET available_balance_cent = ROUND(available_balance * 100),
|
||||||
frozen_balance_cent = ROUND(frozen_balance * 100)
|
frozen_balance_cent = ROUND(frozen_balance * 100)
|
||||||
WHERE available_balance > 0 OR frozen_balance > 0;
|
WHERE available_balance > 0 OR frozen_balance > 0;
|
||||||
|
|
||||||
-- 钱包流水
|
-- 钱包流水
|
||||||
UPDATE wallet_ledger SET
|
UPDATE wallet_ledger
|
||||||
amount_cent = ROUND(amount * 100),
|
SET amount_cent = ROUND(amount * 100),
|
||||||
balance_after_cent = ROUND(balance_after * 100)
|
balance_after_cent = ROUND(balance_after * 100)
|
||||||
WHERE amount != 0 OR balance_after != 0;
|
WHERE amount != 0 OR balance_after != 0;
|
||||||
|
|
||||||
-- 提现记录
|
-- 提现记录
|
||||||
UPDATE withdrawal_requests SET
|
SET @sql := IF(@withdrawal_requests_exists > 0,
|
||||||
amount_cent = ROUND(amount * 100),
|
'UPDATE withdrawal_requests
|
||||||
fee_cent = ROUND(fee * 100),
|
SET amount_cent = ROUND(amount * 100),
|
||||||
actual_amount_cent = ROUND(actual_amount * 100)
|
fee_cent = ROUND(fee * 100),
|
||||||
WHERE amount > 0 OR fee > 0 OR actual_amount > 0;
|
actual_amount_cent = ROUND(actual_amount * 100)
|
||||||
|
WHERE amount > 0 OR fee > 0 OR actual_amount > 0',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
-- +goose StatementEnd
|
-- +goose StatementEnd
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
@@ -119,42 +138,53 @@ WHERE amount > 0 OR fee > 0 OR actual_amount > 0;
|
|||||||
-- 回滚:删除所有新增的分字段
|
-- 回滚:删除所有新增的分字段
|
||||||
-- ============================================
|
-- ============================================
|
||||||
|
|
||||||
ALTER TABLE users DROP COLUMN deposit_free_quota_cent;
|
ALTER TABLE users DROP COLUMN IF EXISTS deposit_free_quota_cent;
|
||||||
|
|
||||||
ALTER TABLE rental_listings
|
ALTER TABLE rental_listings
|
||||||
DROP COLUMN price_cent,
|
DROP COLUMN IF EXISTS price_cent,
|
||||||
DROP COLUMN deposit_amount_cent;
|
DROP COLUMN IF EXISTS deposit_amount_cent;
|
||||||
|
|
||||||
ALTER TABLE rental_orders
|
ALTER TABLE rental_orders
|
||||||
DROP COLUMN rent_amount_cent,
|
DROP COLUMN IF EXISTS rent_amount_cent,
|
||||||
DROP COLUMN owner_rent_amount_cent,
|
DROP COLUMN IF EXISTS owner_rent_amount_cent,
|
||||||
DROP COLUMN deposit_amount_cent,
|
DROP COLUMN IF EXISTS deposit_amount_cent,
|
||||||
DROP COLUMN deposit_original_amount_cent,
|
DROP COLUMN IF EXISTS deposit_original_amount_cent,
|
||||||
DROP COLUMN deposit_waived_amount_cent,
|
DROP COLUMN IF EXISTS deposit_waived_amount_cent,
|
||||||
DROP COLUMN platform_fee_cent;
|
DROP COLUMN IF EXISTS platform_fee_cent;
|
||||||
|
|
||||||
ALTER TABLE order_checkouts
|
ALTER TABLE order_checkouts
|
||||||
DROP COLUMN rent_amount_cent,
|
DROP COLUMN IF EXISTS rent_amount_cent,
|
||||||
DROP COLUMN owner_rent_amount_cent,
|
DROP COLUMN IF EXISTS owner_rent_amount_cent,
|
||||||
DROP COLUMN platform_fee_cent,
|
DROP COLUMN IF EXISTS platform_fee_cent,
|
||||||
DROP COLUMN deposit_amount_cent,
|
DROP COLUMN IF EXISTS deposit_amount_cent,
|
||||||
DROP COLUMN consumable_amount_cent,
|
DROP COLUMN IF EXISTS consumable_amount_cent,
|
||||||
DROP COLUMN other_amount_cent,
|
DROP COLUMN IF EXISTS other_amount_cent,
|
||||||
DROP COLUMN deposit_deduct_amount_cent,
|
DROP COLUMN IF EXISTS deposit_deduct_amount_cent,
|
||||||
DROP COLUMN renter_refund_amount_cent,
|
DROP COLUMN IF EXISTS renter_refund_amount_cent,
|
||||||
DROP COLUMN owner_income_amount_cent;
|
DROP COLUMN IF EXISTS owner_income_amount_cent;
|
||||||
|
|
||||||
ALTER TABLE wallet_accounts
|
ALTER TABLE wallet_accounts
|
||||||
DROP COLUMN available_balance_cent,
|
DROP COLUMN IF EXISTS available_balance_cent,
|
||||||
DROP COLUMN frozen_balance_cent;
|
DROP COLUMN IF EXISTS frozen_balance_cent;
|
||||||
|
|
||||||
ALTER TABLE wallet_ledger
|
ALTER TABLE wallet_ledger
|
||||||
DROP COLUMN amount_cent,
|
DROP COLUMN IF EXISTS amount_cent,
|
||||||
DROP COLUMN balance_after_cent;
|
DROP COLUMN IF EXISTS balance_after_cent;
|
||||||
|
|
||||||
ALTER TABLE withdrawal_requests
|
|
||||||
DROP COLUMN amount_cent,
|
|
||||||
DROP COLUMN fee_cent,
|
|
||||||
DROP COLUMN actual_amount_cent;
|
|
||||||
|
|
||||||
|
SET @withdrawal_requests_exists := (
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM information_schema.tables
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'withdrawal_requests'
|
||||||
|
);
|
||||||
|
SET @sql := IF(@withdrawal_requests_exists > 0,
|
||||||
|
'ALTER TABLE withdrawal_requests
|
||||||
|
DROP COLUMN IF EXISTS amount_cent,
|
||||||
|
DROP COLUMN IF EXISTS fee_cent,
|
||||||
|
DROP COLUMN IF EXISTS actual_amount_cent',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
PREPARE stmt FROM @sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
-- +goose StatementEnd
|
-- +goose StatementEnd
|
||||||
|
|||||||
Reference in New Issue
Block a user