152 lines
8.0 KiB
Go
152 lines
8.0 KiB
Go
package wallet
|
||
|
||
import (
|
||
"context"
|
||
"hyapp/pkg/appcode"
|
||
"hyapp/pkg/xerr"
|
||
"hyapp/services/wallet-service/internal/domain/ledger"
|
||
"strings"
|
||
)
|
||
|
||
// AdminCreditCoinSellerStock 只给 COIN_SELLER_COIN 库存入账;USDT 进货和金币补偿使用不同账务类型。
|
||
func (s *Service) AdminCreditCoinSellerStock(ctx context.Context, command ledger.CoinSellerStockCreditCommand) (ledger.CoinSellerStockCreditReceipt, error) {
|
||
if command.CommandID == "" || command.SellerUserID <= 0 || command.OperatorUserID <= 0 {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.InvalidArgument, "coin seller stock command is incomplete")
|
||
}
|
||
if command.SellerCountryID <= 0 || command.SellerRegionID <= 0 {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.InvalidArgument, "seller country and region are required")
|
||
}
|
||
if len(command.CommandID) > 128 {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.InvalidArgument, "command_id is too long")
|
||
}
|
||
if command.CoinAmount <= 0 {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockAmountInvalid, "coin_amount must be positive")
|
||
}
|
||
command.StockType = ledger.NormalizeCoinSellerStockType(command.StockType)
|
||
if command.StockType == "" {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockTypeInvalid, "stock_type is invalid")
|
||
}
|
||
command.PaidCurrencyCode = strings.ToUpper(strings.TrimSpace(command.PaidCurrencyCode))
|
||
command.PaymentRef = strings.TrimSpace(command.PaymentRef)
|
||
command.EvidenceRef = strings.TrimSpace(command.EvidenceRef)
|
||
command.Reason = strings.TrimSpace(command.Reason)
|
||
if len(command.PaidCurrencyCode) > 8 || len(command.PaymentRef) > 128 || len(command.EvidenceRef) > 256 || len(command.Reason) > 512 {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.InvalidArgument, "coin seller stock text fields are too long")
|
||
}
|
||
switch command.StockType {
|
||
case ledger.StockTypeUSDTPurchase:
|
||
if command.PaidCurrencyCode == "" {
|
||
command.PaidCurrencyCode = ledger.PaidCurrencyUSDT
|
||
}
|
||
if command.PaidCurrencyCode != ledger.PaidCurrencyUSDT || command.PaidAmountMicro <= 0 {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockAmountInvalid, "usdt purchase requires paid amount")
|
||
}
|
||
case ledger.StockTypeCoinCompensation:
|
||
if command.PaidCurrencyCode != "" || command.PaidAmountMicro != 0 || command.PaymentRef != "" {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockAmountInvalid, "coin compensation must not include paid amount")
|
||
}
|
||
default:
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.CoinSellerStockTypeInvalid, "stock_type is invalid")
|
||
}
|
||
if s.repository == nil {
|
||
return ledger.CoinSellerStockCreditReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||
}
|
||
command.AppCode = appcode.Normalize(command.AppCode)
|
||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||
|
||
return s.repository.AdminCreditCoinSellerStock(ctx, command)
|
||
}
|
||
|
||
// TransferCoinFromSeller 执行币商专用金币转普通金币;身份和区域都由 gateway/user-service 校验并传入。
|
||
func (s *Service) TransferCoinFromSeller(ctx context.Context, command ledger.CoinSellerTransferCommand) (ledger.CoinSellerTransferReceipt, error) {
|
||
if command.CommandID == "" || command.SellerUserID <= 0 || command.TargetUserID <= 0 || command.Amount <= 0 {
|
||
return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.InvalidArgument, "coin seller transfer command is incomplete")
|
||
}
|
||
if command.SellerRegionID <= 0 || command.TargetRegionID <= 0 {
|
||
return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.InvalidArgument, "seller and target region are required")
|
||
}
|
||
if command.TargetCountryID <= 0 {
|
||
return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.InvalidArgument, "target country is required")
|
||
}
|
||
if command.SellerRegionID != command.TargetRegionID {
|
||
return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.Conflict, "seller and target region must match")
|
||
}
|
||
if strings.TrimSpace(command.Reason) == "" {
|
||
return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
|
||
}
|
||
if s.repository == nil {
|
||
return ledger.CoinSellerTransferReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||
}
|
||
command.AppCode = appcode.Normalize(command.AppCode)
|
||
command.Reason = strings.TrimSpace(command.Reason)
|
||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||
|
||
return s.repository.TransferCoinFromSeller(ctx, command)
|
||
}
|
||
|
||
// ListCoinSellerSalaryExchangeRateTiers 返回指定区域的工资转币商比例区间;gateway 用它给 H5 展示预计到账金币。
|
||
func (s *Service) ListCoinSellerSalaryExchangeRateTiers(ctx context.Context, appCode string, regionID int64, includeDisabled bool) ([]ledger.CoinSellerSalaryExchangeRateTier, error) {
|
||
if regionID <= 0 {
|
||
return nil, xerr.New(xerr.InvalidArgument, "region_id is required")
|
||
}
|
||
if s.repository == nil {
|
||
return nil, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||
}
|
||
appCode = appcode.Normalize(appCode)
|
||
ctx = appcode.WithContext(ctx, appCode)
|
||
return s.repository.ListCoinSellerSalaryExchangeRateTiers(ctx, appCode, regionID, includeDisabled)
|
||
}
|
||
|
||
// ExchangeSalaryToCoin 校验工资兑换命令;身份归属由 gateway 校验,wallet 只接受明确的工资资产和正向美分金额。
|
||
func (s *Service) ExchangeSalaryToCoin(ctx context.Context, command ledger.SalaryExchangeCommand) (ledger.SalaryExchangeReceipt, error) {
|
||
if command.CommandID == "" || command.UserID <= 0 || command.SalaryUSDMinor <= 0 {
|
||
return ledger.SalaryExchangeReceipt{}, xerr.New(xerr.InvalidArgument, "salary exchange command is incomplete")
|
||
}
|
||
command.SalaryAssetType = strings.ToUpper(strings.TrimSpace(command.SalaryAssetType))
|
||
if !ledger.ValidSalaryAssetType(command.SalaryAssetType) {
|
||
return ledger.SalaryExchangeReceipt{}, xerr.New(xerr.InvalidArgument, "salary_asset_type is invalid")
|
||
}
|
||
command.Reason = strings.TrimSpace(command.Reason)
|
||
if command.Reason == "" {
|
||
command.Reason = "salary exchange"
|
||
}
|
||
if len(command.CommandID) > 128 || len(command.Reason) > 512 {
|
||
return ledger.SalaryExchangeReceipt{}, xerr.New(xerr.InvalidArgument, "salary exchange text fields are too long")
|
||
}
|
||
if s.repository == nil {
|
||
return ledger.SalaryExchangeReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||
}
|
||
command.AppCode = appcode.Normalize(command.AppCode)
|
||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||
|
||
return s.repository.ExchangeSalaryToCoin(ctx, command)
|
||
}
|
||
|
||
// TransferSalaryToCoinSeller 校验工资转币商命令;比例区间命中和双边入账由 repository 在同一事务内完成。
|
||
func (s *Service) TransferSalaryToCoinSeller(ctx context.Context, command ledger.SalaryTransferToCoinSellerCommand) (ledger.SalaryTransferToCoinSellerReceipt, error) {
|
||
if command.CommandID == "" || command.SourceUserID <= 0 || command.SellerUserID <= 0 || command.SalaryUSDMinor <= 0 {
|
||
return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.InvalidArgument, "salary transfer command is incomplete")
|
||
}
|
||
if command.RegionID <= 0 {
|
||
return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.InvalidArgument, "region_id is required")
|
||
}
|
||
command.SalaryAssetType = strings.ToUpper(strings.TrimSpace(command.SalaryAssetType))
|
||
if !ledger.ValidSalaryAssetType(command.SalaryAssetType) {
|
||
return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.InvalidArgument, "salary_asset_type is invalid")
|
||
}
|
||
command.Reason = strings.TrimSpace(command.Reason)
|
||
if command.Reason == "" {
|
||
command.Reason = "salary transfer"
|
||
}
|
||
if len(command.CommandID) > 128 || len(command.Reason) > 512 {
|
||
return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.InvalidArgument, "salary transfer text fields are too long")
|
||
}
|
||
if s.repository == nil {
|
||
return ledger.SalaryTransferToCoinSellerReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||
}
|
||
command.AppCode = appcode.Normalize(command.AppCode)
|
||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||
|
||
return s.repository.TransferSalaryToCoinSeller(ctx, command)
|
||
}
|