Merge branch 'main' of http://1.117.67.95:3000/team/tyapi-server
This commit is contained in:
@@ -23,29 +23,18 @@ func ProcessJRZQ0L85Request(ctx context.Context, params []byte, deps *processors
|
||||
return nil, errors.Join(processors.ErrInvalidParam, err)
|
||||
}
|
||||
|
||||
encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
|
||||
if err != nil {
|
||||
return nil, errors.Join(processors.ErrSystem, err)
|
||||
}
|
||||
|
||||
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
|
||||
if err != nil {
|
||||
return nil, errors.Join(processors.ErrSystem, err)
|
||||
}
|
||||
|
||||
encryptedMobileNo, err := deps.ZhichaService.Encrypt(paramsDto.MobileNo)
|
||||
if err != nil {
|
||||
return nil, errors.Join(processors.ErrSystem, err)
|
||||
}
|
||||
md5Name := deps.ZhichaService.MD5(paramsDto.Name)
|
||||
md5IDCard := deps.ZhichaService.MD5(paramsDto.IDCard)
|
||||
md5MobileNo := deps.ZhichaService.MD5(paramsDto.MobileNo)
|
||||
|
||||
reqData := map[string]interface{}{
|
||||
"name": encryptedName,
|
||||
"idCard": encryptedIDCard,
|
||||
"phone": encryptedMobileNo,
|
||||
"name": md5Name,
|
||||
"idCard": md5IDCard,
|
||||
"phone": md5MobileNo,
|
||||
"authorized": "1",
|
||||
}
|
||||
|
||||
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI021", reqData)
|
||||
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI084", reqData)
|
||||
if err != nil {
|
||||
if errors.Is(err, zhicha.ErrDatasource) {
|
||||
return nil, errors.Join(processors.ErrDatasource, err)
|
||||
@@ -56,9 +45,9 @@ func ProcessJRZQ0L85Request(ctx context.Context, params []byte, deps *processors
|
||||
|
||||
score := "-1"
|
||||
if m, ok := respData.(map[string]interface{}); ok {
|
||||
if raw, exists := m["xyp_cpl0081"]; exists {
|
||||
if v, ok := parseToFloat64(raw); ok {
|
||||
score = mapXypToGeneralScore(v)
|
||||
if rawScore, exists := m["scoreywbase"]; exists {
|
||||
if v, ok := parseToFloat64(rawScore); ok {
|
||||
score = mapScoreAfywBaseToGeneralScore(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,17 +88,18 @@ func parseToFloat64(v interface{}) (float64, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func mapXypToGeneralScore(xyp float64) string {
|
||||
// xyp_cpl0081: 0~1,值越大风险越高;
|
||||
// score_120_General: 300~900,值越大信用越好。
|
||||
if xyp < 0 {
|
||||
xyp = 0
|
||||
func mapScoreAfywBaseToGeneralScore(scoreAfywBase float64) string {
|
||||
// scoreafywbase: 300~1000,分值越高违约概率越低。
|
||||
// score_120_General: 300~900,分值越高信用越好。
|
||||
if scoreAfywBase < 300 {
|
||||
scoreAfywBase = 300
|
||||
}
|
||||
if xyp > 1 {
|
||||
xyp = 1
|
||||
if scoreAfywBase > 1000 {
|
||||
scoreAfywBase = 1000
|
||||
}
|
||||
|
||||
score := 900 - xyp*600
|
||||
// 线性映射:300->300, 1000->900
|
||||
score := 300 + (scoreAfywBase-300)*600/700
|
||||
scoreInt := int(math.Round(score))
|
||||
if scoreInt < 300 {
|
||||
scoreInt = 300
|
||||
|
||||
46
internal/domains/subordinate/entities/invitation.go
Normal file
46
internal/domains/subordinate/entities/invitation.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// InvitationStatus 邀请状态
|
||||
type InvitationStatus string
|
||||
|
||||
const (
|
||||
InvitationStatusPending InvitationStatus = "pending"
|
||||
InvitationStatusConsumed InvitationStatus = "consumed"
|
||||
InvitationStatusRevoked InvitationStatus = "revoked"
|
||||
)
|
||||
|
||||
// SubordinateInvitation 主账号邀请记录(存 token 哈希)
|
||||
type SubordinateInvitation struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"唯一标识"`
|
||||
ParentUserID string `gorm:"type:varchar(36);not null;index" json:"parent_user_id" comment:"主账号用户ID"`
|
||||
TokenHash string `gorm:"type:varchar(64);not null;uniqueIndex" json:"-" comment:"邀请码的SHA256(十六进制)"`
|
||||
ExpiresAt time.Time `gorm:"not null;index" json:"expires_at" comment:"过期时间"`
|
||||
Status InvitationStatus `gorm:"type:varchar(20);not null;default:pending" json:"status" comment:"状态"`
|
||||
|
||||
ConsumedByUserID *string `gorm:"type:varchar(36);index" json:"consumed_by_user_id,omitempty" comment:"核销后的子账号用户ID"`
|
||||
ConsumedAt *time.Time `json:"consumed_at,omitempty" comment:"核销时间"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
// TableName 表名
|
||||
func (SubordinateInvitation) TableName() string {
|
||||
return "subordinate_invitations"
|
||||
}
|
||||
|
||||
// BeforeCreate 生成ID
|
||||
func (i *SubordinateInvitation) BeforeCreate(tx *gorm.DB) error {
|
||||
if i.ID == "" {
|
||||
i.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
42
internal/domains/subordinate/entities/link.go
Normal file
42
internal/domains/subordinate/entities/link.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// LinkStatus 主从关系状态
|
||||
type LinkStatus string
|
||||
|
||||
const (
|
||||
LinkStatusActive LinkStatus = "active"
|
||||
LinkStatusRevoked LinkStatus = "revoked"
|
||||
)
|
||||
|
||||
// UserSubordinateLink 主账号与下属关系
|
||||
type UserSubordinateLink struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"唯一标识"`
|
||||
ParentUserID string `gorm:"type:varchar(36);not null;index:idx_parent,priority:1" json:"parent_user_id" comment:"主账号用户ID"`
|
||||
ChildUserID string `gorm:"type:varchar(36);not null;uniqueIndex" json:"child_user_id" comment:"子账号用户ID(唯一)"`
|
||||
InvitationID *string `gorm:"type:varchar(36);index" json:"invitation_id,omitempty" comment:"关联的邀请ID"`
|
||||
Status LinkStatus `gorm:"type:varchar(20);not null;default:active" json:"status" comment:"状态"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
// TableName 表名
|
||||
func (UserSubordinateLink) TableName() string {
|
||||
return "user_subordinate_links"
|
||||
}
|
||||
|
||||
// BeforeCreate 生成ID
|
||||
func (l *UserSubordinateLink) BeforeCreate(tx *gorm.DB) error {
|
||||
if l.ID == "" {
|
||||
l.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
98
internal/domains/subordinate/entities/quota.go
Normal file
98
internal/domains/subordinate/entities/quota.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
// QuotaLedgerChangeTypePurchaseForSub 主账号为子账号购买额度
|
||||
QuotaLedgerChangeTypePurchaseForSub = "purchase_for_sub"
|
||||
// QuotaLedgerChangeTypeConsumeAPI 用户调用API消耗额度
|
||||
QuotaLedgerChangeTypeConsumeAPI = "api_consume"
|
||||
)
|
||||
|
||||
// SubordinateQuotaPurchase 主账号为子账号购买额度记录
|
||||
type SubordinateQuotaPurchase struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id"`
|
||||
ParentUserID string `gorm:"type:varchar(36);not null;index" json:"parent_user_id"`
|
||||
ChildUserID string `gorm:"type:varchar(36);not null;index" json:"child_user_id"`
|
||||
ProductID string `gorm:"type:varchar(36);not null;index" json:"product_id"`
|
||||
CallCount int64 `gorm:"type:bigint;not null" json:"call_count"`
|
||||
UnitPrice decimal.Decimal `gorm:"type:decimal(20,8);not null" json:"unit_price"`
|
||||
TotalAmount decimal.Decimal `gorm:"type:decimal(20,8);not null" json:"total_amount"`
|
||||
BusinessRef string `gorm:"type:varchar(64);not null;uniqueIndex" json:"business_ref"`
|
||||
OperatorUserID string `gorm:"type:varchar(36);not null" json:"operator_user_id"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
func (SubordinateQuotaPurchase) TableName() string {
|
||||
return "subordinate_quota_purchases"
|
||||
}
|
||||
|
||||
func (q *SubordinateQuotaPurchase) BeforeCreate(tx *gorm.DB) error {
|
||||
if q.ID == "" {
|
||||
q.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UserProductQuotaAccount 用户产品额度账户(通用模型,适配所有用户)
|
||||
type UserProductQuotaAccount struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id"`
|
||||
UserID string `gorm:"type:varchar(36);not null;index:idx_user_product,unique" json:"user_id"`
|
||||
ProductID string `gorm:"type:varchar(36);not null;index:idx_user_product,unique" json:"product_id"`
|
||||
TotalQuota int64 `gorm:"type:bigint;not null;default:0" json:"total_quota"`
|
||||
UsedQuota int64 `gorm:"type:bigint;not null;default:0" json:"used_quota"`
|
||||
AvailableQuota int64 `gorm:"type:bigint;not null;default:0" json:"available_quota"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
func (UserProductQuotaAccount) TableName() string {
|
||||
return "user_product_quota_accounts"
|
||||
}
|
||||
|
||||
func (a *UserProductQuotaAccount) BeforeCreate(tx *gorm.DB) error {
|
||||
if a.ID == "" {
|
||||
a.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UserProductQuotaLedger 用户产品额度流水(通用模型,适配所有用户)
|
||||
type UserProductQuotaLedger struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id"`
|
||||
UserID string `gorm:"type:varchar(36);not null;index" json:"user_id"`
|
||||
ProductID string `gorm:"type:varchar(36);not null;index" json:"product_id"`
|
||||
ChangeType string `gorm:"type:varchar(50);not null;index" json:"change_type"`
|
||||
DeltaQuota int64 `gorm:"type:bigint;not null" json:"delta_quota"`
|
||||
BeforeQuota int64 `gorm:"type:bigint;not null" json:"before_quota"`
|
||||
AfterQuota int64 `gorm:"type:bigint;not null" json:"after_quota"`
|
||||
SourceID string `gorm:"type:varchar(36);index" json:"source_id"`
|
||||
OperatorID string `gorm:"type:varchar(36);not null" json:"operator_id"`
|
||||
Remark string `gorm:"type:varchar(255)" json:"remark"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
func (UserProductQuotaLedger) TableName() string {
|
||||
return "user_product_quota_ledgers"
|
||||
}
|
||||
|
||||
func (l *UserProductQuotaLedger) BeforeCreate(tx *gorm.DB) error {
|
||||
if l.ID == "" {
|
||||
l.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
36
internal/domains/subordinate/entities/wallet_allocation.go
Normal file
36
internal/domains/subordinate/entities/wallet_allocation.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package entities
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// SubordinateWalletAllocation 主账号向下属余额划拨记录
|
||||
type SubordinateWalletAllocation struct {
|
||||
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"唯一标识"`
|
||||
FromUserID string `gorm:"type:varchar(36);not null;index" json:"from_user_id" comment:"主账号用户ID"`
|
||||
ToUserID string `gorm:"type:varchar(36);not null;index" json:"to_user_id" comment:"子账号用户ID"`
|
||||
Amount decimal.Decimal `gorm:"type:decimal(20,8);not null" json:"amount" comment:"金额"`
|
||||
BusinessRef string `gorm:"type:varchar(64);not null;index" json:"business_ref" comment:"业务单号(幂等/对账)"`
|
||||
OperatorUserID string `gorm:"type:varchar(36);not null" json:"operator_user_id" comment:"操作者(一般同主账号)"`
|
||||
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
// TableName 表名
|
||||
func (SubordinateWalletAllocation) TableName() string {
|
||||
return "subordinate_wallet_allocations"
|
||||
}
|
||||
|
||||
// BeforeCreate 生成ID
|
||||
func (a *SubordinateWalletAllocation) BeforeCreate(tx *gorm.DB) error {
|
||||
if a.ID == "" {
|
||||
a.ID = uuid.New().String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
"tyapi-server/internal/domains/subordinate/entities"
|
||||
)
|
||||
|
||||
// SubordinateRepository 下属模块仓储
|
||||
type SubordinateRepository interface {
|
||||
// 邀请
|
||||
CreateInvitation(ctx context.Context, inv *entities.SubordinateInvitation) error
|
||||
FindInvitationByTokenHash(ctx context.Context, tokenHash string) (*entities.SubordinateInvitation, error)
|
||||
FindInvitationByID(ctx context.Context, id string) (*entities.SubordinateInvitation, error)
|
||||
UpdateInvitation(ctx context.Context, inv *entities.SubordinateInvitation) error
|
||||
ConsumeInvitation(ctx context.Context, invitationID, childUserID string, consumedAt time.Time) (bool, error)
|
||||
ListInvitationsByParent(ctx context.Context, parentUserID string, limit, offset int) ([]*entities.SubordinateInvitation, int64, error)
|
||||
|
||||
// 主从
|
||||
CreateLink(ctx context.Context, link *entities.UserSubordinateLink) error
|
||||
FindLinkByChildUserID(ctx context.Context, childUserID string) (*entities.UserSubordinateLink, error)
|
||||
FindLinkByParentAndChild(ctx context.Context, parentUserID, childUserID string) (*entities.UserSubordinateLink, error)
|
||||
ListChildrenByParent(ctx context.Context, parentUserID string, limit, offset int) ([]*entities.UserSubordinateLink, int64, error)
|
||||
UpdateLink(ctx context.Context, link *entities.UserSubordinateLink) error
|
||||
// 是否存在子账号关系(任意子账号)
|
||||
IsUserSubordinate(ctx context.Context, userID string) (bool, error)
|
||||
|
||||
// 划拨
|
||||
CreateWalletAllocation(ctx context.Context, a *entities.SubordinateWalletAllocation) error
|
||||
ListWalletAllocationsByParentAndChild(ctx context.Context, parentUserID, childUserID string, limit, offset int) ([]*entities.SubordinateWalletAllocation, int64, error)
|
||||
|
||||
// 额度购买
|
||||
CreateQuotaPurchase(ctx context.Context, p *entities.SubordinateQuotaPurchase) error
|
||||
ListQuotaPurchasesByParentAndChild(ctx context.Context, parentUserID, childUserID string, limit, offset int) ([]*entities.SubordinateQuotaPurchase, int64, error)
|
||||
|
||||
// 额度账户
|
||||
FindQuotaAccount(ctx context.Context, userID, productID string) (*entities.UserProductQuotaAccount, error)
|
||||
CreateQuotaAccount(ctx context.Context, account *entities.UserProductQuotaAccount) error
|
||||
UpdateQuotaAccount(ctx context.Context, account *entities.UserProductQuotaAccount) error
|
||||
ListQuotaAccountsByUser(ctx context.Context, userID string) ([]*entities.UserProductQuotaAccount, error)
|
||||
CreateQuotaLedger(ctx context.Context, ledger *entities.UserProductQuotaLedger) error
|
||||
}
|
||||
Reference in New Issue
Block a user