| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | package entities | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"errors" | 
					
						
							|  |  |  |  | 	"time" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	"github.com/google/uuid" | 
					
						
							|  |  |  |  | 	"github.com/shopspring/decimal" | 
					
						
							|  |  |  |  | 	"gorm.io/gorm" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ApiCallStatus API调用状态 | 
					
						
							|  |  |  |  | const ( | 
					
						
							|  |  |  |  | 	ApiCallStatusPending = "pending" | 
					
						
							|  |  |  |  | 	ApiCallStatusSuccess = "success" | 
					
						
							|  |  |  |  | 	ApiCallStatusFailed  = "failed" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ApiCall错误类型常量定义,供各领域服务和应用层统一引用。 | 
					
						
							|  |  |  |  | // 使用时可通过 entities.ApiCallErrorInvalidAccess 方式获得,编辑器可自动补全和提示。 | 
					
						
							|  |  |  |  | // 错误类型与业务含义: | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | //	ApiCallErrorInvalidAccess   = "invalid_access"    // 无效AccessId | 
					
						
							|  |  |  |  | //	ApiCallErrorFrozenAccount   = "frozen_account"    // 账户冻结 | 
					
						
							|  |  |  |  | //	ApiCallErrorInvalidIP       = "invalid_ip"        // IP无效 | 
					
						
							|  |  |  |  | //	ApiCallErrorArrears         = "arrears"           // 账户欠费 | 
					
						
							|  |  |  |  | //	ApiCallErrorNotSubscribed   = "not_subscribed"    // 未订阅产品 | 
					
						
							|  |  |  |  | //	ApiCallErrorProductNotFound = "product_not_found" // 产品不存在 | 
					
						
							|  |  |  |  | //	ApiCallErrorProductDisabled = "product_disabled"  // 产品已停用 | 
					
						
							|  |  |  |  | //	ApiCallErrorSystem          = "system_error"      // 系统错误 | 
					
						
							|  |  |  |  | //	ApiCallErrorDatasource      = "datasource_error"  // 数据源异常 | 
					
						
							|  |  |  |  | //	ApiCallErrorInvalidParam    = "invalid_param"     // 参数不正确 | 
					
						
							|  |  |  |  | //	ApiCallErrorDecryptFail     = "decrypt_fail"      // 解密失败 | 
					
						
							|  |  |  |  | const ( | 
					
						
							|  |  |  |  | 	ApiCallErrorInvalidAccess   = "invalid_access"    // 无效AccessId | 
					
						
							|  |  |  |  | 	ApiCallErrorFrozenAccount   = "frozen_account"    // 账户冻结 | 
					
						
							|  |  |  |  | 	ApiCallErrorInvalidIP       = "invalid_ip"        // IP无效 | 
					
						
							|  |  |  |  | 	ApiCallErrorArrears         = "arrears"           // 账户欠费 | 
					
						
							|  |  |  |  | 	ApiCallErrorNotSubscribed   = "not_subscribed"    // 未订阅产品 | 
					
						
							|  |  |  |  | 	ApiCallErrorProductNotFound = "product_not_found" // 产品不存在 | 
					
						
							|  |  |  |  | 	ApiCallErrorProductDisabled = "product_disabled"  // 产品已停用 | 
					
						
							|  |  |  |  | 	ApiCallErrorSystem          = "system_error"      // 系统错误 | 
					
						
							|  |  |  |  | 	ApiCallErrorDatasource      = "datasource_error"  // 数据源异常 | 
					
						
							|  |  |  |  | 	ApiCallErrorInvalidParam    = "invalid_param"     // 参数不正确 | 
					
						
							|  |  |  |  | 	ApiCallErrorDecryptFail     = "decrypt_fail"      // 解密失败 | 
					
						
							|  |  |  |  | 	ApiCallErrorQueryEmpty      = "query_empty"       // 查询为空 | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ApiCall API调用(聚合根) | 
					
						
							|  |  |  |  | type ApiCall struct { | 
					
						
							|  |  |  |  | 	ID            string           `gorm:"type:varchar(64);primaryKey" json:"id"` | 
					
						
							|  |  |  |  | 	AccessId      string           `gorm:"type:varchar(64);not null;index" json:"access_id"` | 
					
						
							|  |  |  |  | 	UserId        *string          `gorm:"type:varchar(36);index" json:"user_id,omitempty"` | 
					
						
							|  |  |  |  | 	ProductId     *string          `gorm:"type:varchar(64);index" json:"product_id,omitempty"` | 
					
						
							| 
									
										
										
										
											2025-09-12 01:15:09 +08:00
										 |  |  |  | 	TransactionId string           `gorm:"type:varchar(36);not null;uniqueIndex" json:"transaction_id"` | 
					
						
							| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | 	ClientIp      string           `gorm:"type:varchar(64);not null;index" json:"client_ip"` | 
					
						
							|  |  |  |  | 	RequestParams string           `gorm:"type:text" json:"request_params"` | 
					
						
							|  |  |  |  | 	ResponseData  *string          `gorm:"type:text" json:"response_data,omitempty"` | 
					
						
							|  |  |  |  | 	Status        string           `gorm:"type:varchar(20);not null;default:'pending'" json:"status"` | 
					
						
							|  |  |  |  | 	StartAt       time.Time        `gorm:"not null;index" json:"start_at"` | 
					
						
							|  |  |  |  | 	EndAt         *time.Time       `gorm:"index" json:"end_at,omitempty"` | 
					
						
							|  |  |  |  | 	Cost          *decimal.Decimal `gorm:"default:0" json:"cost,omitempty"` | 
					
						
							|  |  |  |  | 	ErrorType     *string          `gorm:"type:varchar(32)" json:"error_type,omitempty"` | 
					
						
							|  |  |  |  | 	ErrorMsg      *string          `gorm:"type:varchar(256)" json:"error_msg,omitempty"` | 
					
						
							|  |  |  |  | 	CreatedAt     time.Time        `gorm:"autoCreateTime" json:"created_at"` | 
					
						
							|  |  |  |  | 	UpdatedAt     time.Time        `gorm:"autoUpdateTime" json:"updated_at"` | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // NewApiCall 工厂方法 | 
					
						
							|  |  |  |  | func NewApiCall(accessId, requestParams, clientIp string) (*ApiCall, error) { | 
					
						
							|  |  |  |  | 	if accessId == "" { | 
					
						
							|  |  |  |  | 		return nil, errors.New("AccessId不能为空") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if requestParams == "" { | 
					
						
							|  |  |  |  | 		return nil, errors.New("请求参数不能为空") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if clientIp == "" { | 
					
						
							|  |  |  |  | 		return nil, errors.New("ClientIp不能为空") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return &ApiCall{ | 
					
						
							|  |  |  |  | 		ID:            uuid.New().String(), | 
					
						
							|  |  |  |  | 		AccessId:      accessId, | 
					
						
							|  |  |  |  | 		TransactionId: GenerateTransactionID(), | 
					
						
							|  |  |  |  | 		ClientIp:      clientIp, | 
					
						
							|  |  |  |  | 		RequestParams: requestParams, | 
					
						
							|  |  |  |  | 		Status:        ApiCallStatusPending, | 
					
						
							|  |  |  |  | 		StartAt:       time.Now(), | 
					
						
							|  |  |  |  | 	}, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // MarkSuccess 标记为成功 | 
					
						
							| 
									
										
										
										
											2025-07-28 23:44:01 +08:00
										 |  |  |  | func (a *ApiCall) MarkSuccess(cost decimal.Decimal) error { | 
					
						
							| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | 	// 校验除ErrorMsg和ErrorType外所有字段不能为空 | 
					
						
							|  |  |  |  | 	if a.ID == "" || a.AccessId == "" || a.TransactionId == "" || a.RequestParams == "" || a.Status == "" || a.StartAt.IsZero() { | 
					
						
							|  |  |  |  | 		return errors.New("ApiCall字段不能为空(除ErrorMsg和ErrorType)") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	// 可选字段也要有值 | 
					
						
							| 
									
										
										
										
											2025-07-28 23:44:01 +08:00
										 |  |  |  | 	if a.UserId == nil || a.ProductId == nil  { | 
					
						
							|  |  |  |  | 		return errors.New("ApiCall标记成功时UserId、ProductId不能为空") | 
					
						
							| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	a.Status = ApiCallStatusSuccess | 
					
						
							|  |  |  |  | 	endAt := time.Now() | 
					
						
							|  |  |  |  | 	a.EndAt = &endAt | 
					
						
							|  |  |  |  | 	a.Cost = &cost | 
					
						
							|  |  |  |  | 	a.ErrorType = nil | 
					
						
							|  |  |  |  | 	a.ErrorMsg = nil | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // MarkFailed 标记为失败 | 
					
						
							|  |  |  |  | func (a *ApiCall) MarkFailed(errorType, errorMsg string) { | 
					
						
							|  |  |  |  | 	a.Status = ApiCallStatusFailed | 
					
						
							|  |  |  |  | 	a.ErrorType = &errorType | 
					
						
							|  |  |  |  | 	shortMsg := errorMsg | 
					
						
							|  |  |  |  | 	if len(shortMsg) > 120 { | 
					
						
							|  |  |  |  | 		shortMsg = shortMsg[:120] | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	a.ErrorMsg = &shortMsg | 
					
						
							|  |  |  |  | 	endAt := time.Now() | 
					
						
							|  |  |  |  | 	a.EndAt = &endAt | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Validate 校验ApiCall聚合根的业务规则 | 
					
						
							|  |  |  |  | func (a *ApiCall) Validate() error { | 
					
						
							|  |  |  |  | 	if a.ID == "" { | 
					
						
							|  |  |  |  | 		return errors.New("ID不能为空") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if a.AccessId == "" { | 
					
						
							|  |  |  |  | 		return errors.New("AccessId不能为空") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if a.TransactionId == "" { | 
					
						
							|  |  |  |  | 		return errors.New("TransactionId不能为空") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if a.RequestParams == "" { | 
					
						
							|  |  |  |  | 		return errors.New("请求参数不能为空") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if a.Status != ApiCallStatusPending && a.Status != ApiCallStatusSuccess && a.Status != ApiCallStatusFailed { | 
					
						
							|  |  |  |  | 		return errors.New("无效的调用状态") | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-12 01:15:09 +08:00
										 |  |  |  | // GenerateTransactionID 生成UUID格式的交易单号 | 
					
						
							| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | func GenerateTransactionID() string { | 
					
						
							| 
									
										
										
										
											2025-09-12 01:15:09 +08:00
										 |  |  |  | 	return uuid.New().String() | 
					
						
							| 
									
										
										
										
											2025-07-28 01:46:39 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // TableName 指定数据库表名 | 
					
						
							|  |  |  |  | func (ApiCall) TableName() string { | 
					
						
							|  |  |  |  | 	return "api_calls" | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // BeforeCreate GORM钩子:创建前自动生成UUID | 
					
						
							|  |  |  |  | func (c *ApiCall) BeforeCreate(tx *gorm.DB) error { | 
					
						
							|  |  |  |  | 	if c.ID == "" { | 
					
						
							|  |  |  |  | 		c.ID = uuid.New().String() | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } |