Files
affiliate_dash/backend/internal/model/merchant.go
T

298 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"time"
"gorm.io/gorm"
)
const (
MerchantStatusActive = "active"
MerchantStatusDisabled = "disabled"
// MerchantCodeSelfOperated 是平台自营商户编码,作为默认商品目录的模板来源。
MerchantCodeSelfOperated = "self-operated"
MerchantFeatureProducts = "products"
MerchantFeatureOrders = "orders"
MerchantFeatureWallet = "wallet"
MerchantFeatureAPI = "api"
MerchantFeatureCallbacks = "callbacks"
DefaultMerchantFeatures = "products,orders,wallet,api,callbacks"
MemberRoleOwner = "owner"
MemberRoleOperator = "operator"
MemberRoleFinance = "finance"
MemberRoleViewer = "viewer"
FeeTypeRate = "rate" // 手续费按百分比
FeeTypeFixed = "fixed" // 手续费按固定金额
APIClientStatusActive = "active"
APIClientStatusDisabled = "disabled"
ProductStatusActive = "active"
ProductStatusInactive = "inactive"
PaymentStatusPending = "pending"
PaymentStatusPaid = "paid"
PaymentStatusRefunded = "refunded"
PaymentStatusCancelled = "cancelled"
FulfillmentStatusPending = "pending"
FulfillmentStatusProcessing = "processing"
FulfillmentStatusSucceeded = "succeeded"
FulfillmentStatusFailed = "failed"
FulfillmentStatusCancelled = "cancelled"
WalletLedgerCredit = "credit"
WalletLedgerDebit = "debit"
WalletLedgerRefund = "refund"
WalletLedgerAdjust = "adjust"
CallbackStatusActive = "active"
CallbackStatusDisabled = "disabled"
CallbackDeliveryPending = "pending"
CallbackDeliverySending = "sending"
CallbackDeliveryDelivered = "delivered"
CallbackDeliveryFailed = "failed"
)
// Merchant 商户租户,是所有新业务数据的隔离边界。
type Merchant struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
Code string `gorm:"uniqueIndex;size:64;not null" json:"code"`
Name string `gorm:"size:128;not null" json:"name"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"`
ContactName string `gorm:"size:64" json:"contact_name"`
ContactInfo string `gorm:"size:128" json:"contact_info"`
Features string `gorm:"type:text;not null;default:'products,orders,wallet,api,callbacks'" json:"features"`
// 手续费按"百分比或固定"二选一:fee_type=rate 用 fee_rate_bpfee_type=fixed 用 fee_fixed_amount。
FeeType string `gorm:"size:16;not null;default:rate" json:"fee_type"`
FeeRateBP int64 `gorm:"not null;default:0" json:"fee_rate_bp"`
FeeFixedAmount int64 `gorm:"not null;default:0" json:"fee_fixed_amount"`
}
func (m *Merchant) BeforeCreate(tx *gorm.DB) error {
if m.Features == "" {
m.Features = DefaultMerchantFeatures
}
if m.FeeType == "" {
m.FeeType = FeeTypeRate
}
return nil
}
// MerchantMember 将系统账号和商户权限分离,账号可以属于多个商户。
type MerchantMember struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
MerchantID uint `gorm:"not null;uniqueIndex:idx_merchant_member;index" json:"merchant_id"`
UserID uint `gorm:"not null;uniqueIndex:idx_merchant_member;index" json:"user_id"`
Role string `gorm:"size:32;not null;default:operator" json:"role"`
Status int `gorm:"not null;default:1" json:"status"`
IsDefault bool `gorm:"not null;default:false" json:"is_default"`
Merchant *Merchant `gorm:"foreignKey:MerchantID" json:"merchant,omitempty"`
User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
}
// APIClient 为一个商户的外部系统集成凭证。SecretCiphertext 仅保存加密后的密钥。
type APIClient struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
MerchantID uint `gorm:"not null;index" json:"merchant_id"`
Name string `gorm:"size:128;not null" json:"name"`
AppKey string `gorm:"uniqueIndex;size:96;not null" json:"app_key"`
SecretCiphertext string `gorm:"type:text;not null" json:"-"`
SignatureVersion string `gorm:"size:16;not null;default:v1" json:"signature_version"`
Scopes string `gorm:"type:text;not null" json:"scopes"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"`
ExpiresAt *time.Time `json:"expires_at"`
LastUsedAt *time.Time `json:"last_used_at"`
Merchant *Merchant `gorm:"foreignKey:MerchantID" json:"merchant,omitempty"`
}
// Product 是平台通用商品目录;商品特性通过 Attributes 保存,避免把游戏、角色等字段写死。
type Product struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
Code string `gorm:"uniqueIndex;size:96;not null" json:"code"`
Name string `gorm:"size:160;not null" json:"name"`
Category string `gorm:"size:64;index" json:"category"`
Description string `gorm:"type:text" json:"description"`
Attributes string `gorm:"type:text" json:"attributes"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"`
}
// MerchantProduct 是商户可售商品及其价格、库存和履约配置。
type MerchantProduct struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
MerchantID uint `gorm:"not null;uniqueIndex:idx_merchant_product_sku;index" json:"merchant_id"`
ProductID uint `gorm:"not null;index" json:"product_id"`
SKU string `gorm:"size:96;not null;uniqueIndex:idx_merchant_product_sku" json:"sku"`
DisplayName string `gorm:"size:160" json:"display_name"`
PriceAmount int64 `gorm:"not null;default:0" json:"price_amount"`
CostAmount int64 `gorm:"not null;default:0" json:"cost_amount"`
Currency string `gorm:"size:12;not null;default:POINT" json:"currency"`
Stock int64 `gorm:"not null;default:-1" json:"stock"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"`
FulfillmentConfig string `gorm:"type:text" json:"fulfillment_config"`
Product *Product `gorm:"foreignKey:ProductID" json:"product,omitempty"`
Merchant *Merchant `gorm:"foreignKey:MerchantID" json:"merchant,omitempty"`
}
// WalletAccount 以最小货币单位记录商户余额,绝不使用 float64 做账。
type WalletAccount struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
MerchantID uint `gorm:"not null;uniqueIndex" json:"merchant_id"`
Currency string `gorm:"size:12;not null;default:POINT" json:"currency"`
AvailableBalance int64 `gorm:"not null;default:0" json:"available_balance"`
FrozenBalance int64 `gorm:"not null;default:0" json:"frozen_balance"`
}
// WalletLedgerEntry 记录每一笔余额变化,BalanceAfter 方便审计与对账。
type WalletLedgerEntry struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
MerchantID uint `gorm:"not null;index;uniqueIndex:idx_wallet_ledger_idempotency" json:"merchant_id"`
WalletAccountID uint `gorm:"not null;index" json:"wallet_account_id"`
EntryNo string `gorm:"uniqueIndex;size:64;not null" json:"entry_no"`
Type string `gorm:"size:24;not null;index" json:"type"`
Amount int64 `gorm:"not null" json:"amount"`
BalanceAfter int64 `gorm:"not null" json:"balance_after"`
ReferenceType string `gorm:"size:32;not null" json:"reference_type"`
ReferenceNo string `gorm:"size:96;not null;index" json:"reference_no"`
IdempotencyKey *string `gorm:"uniqueIndex:idx_wallet_ledger_idempotency;size:128" json:"-"`
Note string `gorm:"size:255" json:"note"`
}
// FulfillmentOrder 将支付和履约状态拆分,并保留商品及请求快照。
type FulfillmentOrder struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
MerchantID uint `gorm:"not null;index;uniqueIndex:idx_order_client_no" json:"merchant_id"`
OrderNo string `gorm:"uniqueIndex;size:64;not null" json:"order_no"`
ClientOrderNo string `gorm:"size:96;not null;uniqueIndex:idx_order_client_no" json:"client_order_no"`
MerchantProductID uint `gorm:"not null;index" json:"merchant_product_id"`
ProductSKU string `gorm:"size:96;not null" json:"product_sku"`
ProductName string `gorm:"size:160;not null" json:"product_name"`
Quantity int64 `gorm:"not null;default:1" json:"quantity"`
BaseAmount int64 `gorm:"not null;default:0" json:"base_amount"`
FeeType string `gorm:"size:16;not null;default:rate" json:"fee_type"`
FeeRateBP int64 `gorm:"not null;default:0" json:"fee_rate_bp"`
FeeFixedAmount int64 `gorm:"not null;default:0" json:"fee_fixed_amount"`
ServiceFeeAmount int64 `gorm:"not null;default:0" json:"service_fee_amount"`
Amount int64 `gorm:"not null" json:"amount"`
Currency string `gorm:"size:12;not null;default:POINT" json:"currency"`
PaymentStatus string `gorm:"size:16;not null;default:pending;index" json:"payment_status"`
FulfillmentStatus string `gorm:"size:16;not null;default:pending;index" json:"fulfillment_status"`
BuyerReference string `gorm:"size:128" json:"buyer_reference"`
RequestData string `gorm:"type:text" json:"request_data"`
ResultData string `gorm:"type:text" json:"result_data"`
ProviderOrderNo string `gorm:"size:96;index" json:"provider_order_no"`
FailureReason string `gorm:"size:512" json:"failure_reason"`
CancelledAt *time.Time `json:"cancelled_at"`
DeliveredAt *time.Time `json:"delivered_at"`
DeliveryLinkExpiresAt *time.Time `json:"delivery_link_expires_at"`
DeliveryLinkRevokedAt *time.Time `json:"delivery_link_revoked_at"`
MerchantProduct *MerchantProduct `gorm:"foreignKey:MerchantProductID" json:"merchant_product,omitempty"`
}
// CallbackSubscription 为商户提供独立、可禁用的事件订阅。
type CallbackSubscription struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
MerchantID uint `gorm:"not null;index" json:"merchant_id"`
Name string `gorm:"size:128;not null" json:"name"`
URL string `gorm:"size:1024;not null" json:"url"`
Events string `gorm:"type:text;not null" json:"events"`
SecretCiphertext string `gorm:"type:text;not null" json:"-"`
Status string `gorm:"size:16;not null;default:active;index" json:"status"`
}
// CallbackDelivery 是事务性 outbox 记录;事件 ID 可供接收方做幂等。
type CallbackDelivery struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
MerchantID uint `gorm:"not null;index" json:"merchant_id"`
CallbackSubscriptionID uint `gorm:"not null;index" json:"callback_subscription_id"`
EventID string `gorm:"uniqueIndex;size:64;not null" json:"event_id"`
Event string `gorm:"size:64;not null;index" json:"event"`
Payload string `gorm:"type:text;not null" json:"payload"`
Status string `gorm:"size:16;not null;default:pending;index" json:"status"`
Attempts int `gorm:"not null;default:0" json:"attempts"`
NextAttemptAt time.Time `gorm:"not null;index" json:"next_attempt_at"`
LastStatusCode int `gorm:"not null;default:0" json:"last_status_code"`
LastResponse string `gorm:"type:text" json:"last_response"`
DeliveredAt *time.Time `json:"delivered_at"`
CallbackSubscription *CallbackSubscription `gorm:"foreignKey:CallbackSubscriptionID" json:"callback_subscription,omitempty"`
}
// APIRequestNonce 使 API 重放保护跨进程、跨重启生效。
type APIRequestNonce struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
APIClientID uint `gorm:"not null;uniqueIndex:idx_api_nonce;index" json:"api_client_id"`
Nonce string `gorm:"size:96;not null;uniqueIndex:idx_api_nonce" json:"nonce"`
ExpiresAt time.Time `gorm:"not null;index" json:"expires_at"`
}
// SourceAPINonce 记录源头接口的请求 nonce,保证重放保护跨进程、跨重启生效。
type SourceAPINonce struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
APIKey string `gorm:"size:96;not null;uniqueIndex:idx_source_api_nonce" json:"-"`
Nonce string `gorm:"size:64;not null;uniqueIndex:idx_source_api_nonce" json:"-"`
ExpiresAt time.Time `gorm:"not null;index" json:"-"`
}
func (SourceAPINonce) TableName() string {
return "source_api_nonces"
}
// AuditLog 留存后台和开放接口的重要业务操作。
type AuditLog struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedAt time.Time `json:"created_at"`
MerchantID *uint `gorm:"index" json:"merchant_id"`
ActorUserID *uint `gorm:"index" json:"actor_user_id"`
APIClientID *uint `gorm:"index" json:"api_client_id"`
RequestID string `gorm:"size:64;index" json:"request_id"`
Action string `gorm:"size:96;not null;index" json:"action"`
EntityType string `gorm:"size:64;not null;index" json:"entity_type"`
EntityID string `gorm:"size:96;not null;index" json:"entity_id"`
Metadata string `gorm:"type:text" json:"metadata"`
}