mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-22 03:02:46 +00:00
Merge feature/payment into release/custom-0.1.108
集成支付系统(EasyPay、Alipay、WxPay、Stripe),包含完整的订单管理、 Webhook 回调、管理后台仪表盘和用户充值/订阅流程。
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/internal/repository"
|
||||
"github.com/Wei-Shaw/sub2api/internal/server"
|
||||
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
|
||||
"github.com/google/wire"
|
||||
@@ -35,6 +36,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
// Business layer ProviderSets
|
||||
repository.ProviderSet,
|
||||
service.ProviderSet,
|
||||
payment.ProviderSet,
|
||||
middleware.ProviderSet,
|
||||
handler.ProviderSet,
|
||||
|
||||
@@ -95,6 +97,7 @@ func provideCleanup(
|
||||
openAIGateway *service.OpenAIGatewayService,
|
||||
scheduledTestRunner *service.ScheduledTestRunnerService,
|
||||
backupSvc *service.BackupService,
|
||||
paymentOrderExpiry *service.PaymentOrderExpiryService,
|
||||
) func() {
|
||||
return func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
@@ -237,6 +240,12 @@ func provideCleanup(
|
||||
}
|
||||
return nil
|
||||
}},
|
||||
{"PaymentOrderExpiryService", func() error {
|
||||
if paymentOrderExpiry != nil {
|
||||
paymentOrderExpiry.Stop()
|
||||
}
|
||||
return nil
|
||||
}},
|
||||
}
|
||||
|
||||
infraSteps := []cleanupStep{
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||
"github.com/Wei-Shaw/sub2api/internal/handler"
|
||||
"github.com/Wei-Shaw/sub2api/internal/handler/admin"
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
"github.com/Wei-Shaw/sub2api/internal/repository"
|
||||
"github.com/Wei-Shaw/sub2api/internal/server"
|
||||
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
||||
@@ -49,7 +50,6 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
refreshTokenCache := repository.NewRefreshTokenCache(redisClient)
|
||||
settingRepository := repository.NewSettingRepository(client)
|
||||
groupRepository := repository.NewGroupRepository(client, db)
|
||||
channelRepository := repository.NewChannelRepository(db)
|
||||
settingService := service.ProvideSettingService(settingRepository, groupRepository, configConfig)
|
||||
emailCache := repository.NewEmailCache(redisClient)
|
||||
emailService := service.NewEmailService(settingRepository, emailCache)
|
||||
@@ -64,7 +64,6 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
userGroupRateRepository := repository.NewUserGroupRateRepository(db)
|
||||
apiKeyCache := repository.NewAPIKeyCache(redisClient)
|
||||
apiKeyService := service.NewAPIKeyService(apiKeyRepository, userRepository, groupRepository, userSubscriptionRepository, userGroupRateRepository, apiKeyCache, configConfig)
|
||||
apiKeyService.SetRateLimitCacheInvalidator(billingCache)
|
||||
apiKeyAuthCacheInvalidator := service.ProvideAPIKeyAuthCacheInvalidator(apiKeyService)
|
||||
promoService := service.NewPromoService(promoCodeRepository, userRepository, billingCacheService, client, apiKeyAuthCacheInvalidator)
|
||||
subscriptionService := service.NewSubscriptionService(groupRepository, userSubscriptionRepository, billingCacheService, client, configConfig)
|
||||
@@ -82,7 +81,6 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
userHandler := handler.NewUserHandler(userService)
|
||||
apiKeyHandler := handler.NewAPIKeyHandler(apiKeyService)
|
||||
usageLogRepository := repository.NewUsageLogRepository(client, db)
|
||||
usageBillingRepository := repository.NewUsageBillingRepository(client, db)
|
||||
usageService := service.NewUsageService(usageLogRepository, userRepository, client, apiKeyAuthCacheInvalidator)
|
||||
usageHandler := handler.NewUsageHandler(usageService, apiKeyService)
|
||||
redeemHandler := handler.NewRedeemHandler(redeemService)
|
||||
@@ -110,11 +108,14 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
concurrencyCache := repository.ProvideConcurrencyCache(redisClient, configConfig)
|
||||
concurrencyService := service.ProvideConcurrencyService(concurrencyCache, accountRepository, configConfig)
|
||||
adminUserHandler := admin.NewUserHandler(adminService, concurrencyService)
|
||||
sessionLimitCache := repository.ProvideSessionLimitCache(redisClient, configConfig)
|
||||
rpmCache := repository.NewRPMCache(redisClient)
|
||||
groupCapacityService := service.NewGroupCapacityService(accountRepository, groupRepository, concurrencyService, sessionLimitCache, rpmCache)
|
||||
groupHandler := admin.NewGroupHandler(adminService, dashboardService, groupCapacityService)
|
||||
claudeOAuthClient := repository.NewClaudeOAuthClient()
|
||||
oAuthService := service.NewOAuthService(proxyRepository, claudeOAuthClient)
|
||||
openAIOAuthClient := repository.NewOpenAIOAuthClient()
|
||||
openAIOAuthService := service.NewOpenAIOAuthService(proxyRepository, openAIOAuthClient)
|
||||
openAIOAuthService.SetPrivacyClientFactory(privacyClientFactory)
|
||||
geminiOAuthClient := repository.NewGeminiOAuthClient(configConfig)
|
||||
geminiCliCodeAssistClient := repository.NewGeminiCliCodeAssistClient()
|
||||
driveClient := repository.NewGeminiDriveClient()
|
||||
@@ -124,7 +125,6 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
tempUnschedCache := repository.NewTempUnschedCache(redisClient)
|
||||
timeoutCounterCache := repository.NewTimeoutCounterCache(redisClient)
|
||||
geminiTokenCache := repository.NewGeminiTokenCache(redisClient)
|
||||
oauthRefreshAPI := service.NewOAuthRefreshAPI(accountRepository, geminiTokenCache)
|
||||
compositeTokenCacheInvalidator := service.NewCompositeTokenCacheInvalidator(geminiTokenCache)
|
||||
rateLimitService := service.ProvideRateLimitService(accountRepository, usageLogRepository, configConfig, geminiQuotaService, tempUnschedCache, timeoutCounterCache, settingService, compositeTokenCacheInvalidator)
|
||||
httpUpstream := repository.NewHTTPUpstream(configConfig)
|
||||
@@ -132,23 +132,20 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
antigravityQuotaFetcher := service.NewAntigravityQuotaFetcher(proxyRepository)
|
||||
usageCache := service.NewUsageCache()
|
||||
identityCache := repository.NewIdentityCache(redisClient)
|
||||
geminiTokenProvider := service.ProvideGeminiTokenProvider(accountRepository, geminiTokenCache, geminiOAuthService, oauthRefreshAPI)
|
||||
gatewayCache := repository.NewGatewayCache(redisClient)
|
||||
schedulerOutboxRepository := repository.NewSchedulerOutboxRepository(db)
|
||||
schedulerSnapshotService := service.ProvideSchedulerSnapshotService(schedulerCache, schedulerOutboxRepository, accountRepository, groupRepository, configConfig)
|
||||
antigravityTokenProvider := service.ProvideAntigravityTokenProvider(accountRepository, geminiTokenCache, antigravityOAuthService, oauthRefreshAPI, tempUnschedCache)
|
||||
internal500CounterCache := repository.NewInternal500CounterCache(redisClient)
|
||||
tlsFingerprintProfileRepository := repository.NewTLSFingerprintProfileRepository(client)
|
||||
tlsFingerprintProfileCache := repository.NewTLSFingerprintProfileCache(redisClient)
|
||||
tlsFingerprintProfileService := service.NewTLSFingerprintProfileService(tlsFingerprintProfileRepository, tlsFingerprintProfileCache)
|
||||
accountUsageService := service.NewAccountUsageService(accountRepository, usageLogRepository, claudeUsageFetcher, geminiQuotaService, antigravityQuotaFetcher, usageCache, identityCache, tlsFingerprintProfileService)
|
||||
oAuthRefreshAPI := service.NewOAuthRefreshAPI(accountRepository, geminiTokenCache)
|
||||
geminiTokenProvider := service.ProvideGeminiTokenProvider(accountRepository, geminiTokenCache, geminiOAuthService, oAuthRefreshAPI)
|
||||
gatewayCache := repository.NewGatewayCache(redisClient)
|
||||
schedulerOutboxRepository := repository.NewSchedulerOutboxRepository(db)
|
||||
schedulerSnapshotService := service.ProvideSchedulerSnapshotService(schedulerCache, schedulerOutboxRepository, accountRepository, groupRepository, configConfig)
|
||||
antigravityTokenProvider := service.ProvideAntigravityTokenProvider(accountRepository, geminiTokenCache, antigravityOAuthService, oAuthRefreshAPI, tempUnschedCache)
|
||||
internal500CounterCache := repository.NewInternal500CounterCache(redisClient)
|
||||
antigravityGatewayService := service.NewAntigravityGatewayService(accountRepository, gatewayCache, schedulerSnapshotService, antigravityTokenProvider, rateLimitService, httpUpstream, settingService, internal500CounterCache, accountUsageService)
|
||||
accountTestService := service.NewAccountTestService(accountRepository, geminiTokenProvider, antigravityGatewayService, httpUpstream, configConfig, tlsFingerprintProfileService)
|
||||
crsSyncService := service.NewCRSSyncService(accountRepository, proxyRepository, oAuthService, openAIOAuthService, geminiOAuthService, configConfig)
|
||||
sessionLimitCache := repository.ProvideSessionLimitCache(redisClient, configConfig)
|
||||
rpmCache := repository.NewRPMCache(redisClient)
|
||||
groupCapacityService := service.NewGroupCapacityService(accountRepository, groupRepository, concurrencyService, sessionLimitCache, rpmCache)
|
||||
groupHandler := admin.NewGroupHandler(adminService, dashboardService, groupCapacityService)
|
||||
accountHandler := admin.NewAccountHandler(adminService, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, rateLimitService, accountUsageService, accountTestService, concurrencyService, crsSyncService, sessionLimitCache, rpmCache, compositeTokenCacheInvalidator)
|
||||
adminAnnouncementHandler := admin.NewAnnouncementHandler(announcementService)
|
||||
dataManagementService := service.NewDataManagementService()
|
||||
@@ -165,6 +162,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
adminRedeemHandler := admin.NewRedeemHandler(adminService, redeemService)
|
||||
promoHandler := admin.NewPromoHandler(promoService)
|
||||
opsRepository := repository.NewOpsRepository(db)
|
||||
usageBillingRepository := repository.NewUsageBillingRepository(client, db)
|
||||
pricingRemoteClient := repository.ProvidePricingRemoteClient(configConfig)
|
||||
pricingService, err := service.ProvidePricingService(configConfig, pricingRemoteClient)
|
||||
if err != nil {
|
||||
@@ -173,12 +171,13 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
billingService := service.NewBillingService(configConfig, pricingService)
|
||||
identityService := service.NewIdentityService(identityCache)
|
||||
deferredService := service.ProvideDeferredService(accountRepository, timingWheelService)
|
||||
claudeTokenProvider := service.ProvideClaudeTokenProvider(accountRepository, geminiTokenCache, oAuthService, oauthRefreshAPI)
|
||||
claudeTokenProvider := service.ProvideClaudeTokenProvider(accountRepository, geminiTokenCache, oAuthService, oAuthRefreshAPI)
|
||||
digestSessionStore := service.NewDigestSessionStore()
|
||||
channelRepository := repository.NewChannelRepository(db)
|
||||
channelService := service.NewChannelService(channelRepository, apiKeyAuthCacheInvalidator)
|
||||
modelPricingResolver := service.NewModelPricingResolver(channelService, billingService)
|
||||
gatewayService := service.NewGatewayService(accountRepository, groupRepository, usageLogRepository, usageBillingRepository, userRepository, userSubscriptionRepository, userGroupRateRepository, gatewayCache, configConfig, schedulerSnapshotService, concurrencyService, billingService, rateLimitService, billingCacheService, identityService, httpUpstream, deferredService, claudeTokenProvider, sessionLimitCache, rpmCache, digestSessionStore, settingService, tlsFingerprintProfileService, channelService, modelPricingResolver)
|
||||
openAITokenProvider := service.ProvideOpenAITokenProvider(accountRepository, geminiTokenCache, openAIOAuthService, oauthRefreshAPI)
|
||||
openAITokenProvider := service.ProvideOpenAITokenProvider(accountRepository, geminiTokenCache, openAIOAuthService, oAuthRefreshAPI)
|
||||
openAIGatewayService := service.NewOpenAIGatewayService(accountRepository, usageLogRepository, usageBillingRepository, userRepository, userSubscriptionRepository, userGroupRateRepository, gatewayCache, configConfig, schedulerSnapshotService, concurrencyService, billingService, rateLimitService, billingCacheService, httpUpstream, deferredService, openAITokenProvider, modelPricingResolver, channelService)
|
||||
geminiMessagesCompatService := service.NewGeminiMessagesCompatService(accountRepository, groupRepository, gatewayCache, schedulerSnapshotService, geminiTokenProvider, rateLimitService, httpUpstream, antigravityGatewayService, configConfig)
|
||||
opsSystemLogSink := service.ProvideOpsSystemLogSink(opsRepository)
|
||||
@@ -211,7 +210,14 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
scheduledTestService := service.ProvideScheduledTestService(scheduledTestPlanRepository, scheduledTestResultRepository)
|
||||
scheduledTestHandler := admin.NewScheduledTestHandler(scheduledTestService)
|
||||
channelHandler := admin.NewChannelHandler(channelService, billingService)
|
||||
adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, adminAnnouncementHandler, dataManagementHandler, backupHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, promoHandler, settingHandler, opsHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler, errorPassthroughHandler, tlsFingerprintProfileHandler, adminAPIKeyHandler, scheduledTestHandler, channelHandler)
|
||||
registry := payment.ProvideRegistry()
|
||||
encryptionKey := payment.ProvideEncryptionKey(configConfig)
|
||||
defaultLoadBalancer := payment.ProvideDefaultLoadBalancer(client, encryptionKey)
|
||||
paymentConfigService := service.ProvidePaymentConfigService(client, settingRepository, encryptionKey)
|
||||
paymentService := service.NewPaymentService(client, registry, defaultLoadBalancer, redeemService, subscriptionService, paymentConfigService, userRepository, groupRepository)
|
||||
paymentOrderExpiryService := service.ProvidePaymentOrderExpiryService(paymentService)
|
||||
paymentHandler := admin.NewPaymentHandler(paymentService, paymentConfigService)
|
||||
adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, adminAnnouncementHandler, dataManagementHandler, backupHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, promoHandler, settingHandler, opsHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler, errorPassthroughHandler, tlsFingerprintProfileHandler, adminAPIKeyHandler, scheduledTestHandler, channelHandler, paymentHandler)
|
||||
usageRecordWorkerPool := service.NewUsageRecordWorkerPool(configConfig)
|
||||
userMsgQueueCache := repository.NewUserMsgQueueCache(redisClient)
|
||||
userMessageQueueService := service.ProvideUserMessageQueueService(userMsgQueueCache, rpmCache, configConfig)
|
||||
@@ -219,9 +225,11 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
openAIGatewayHandler := handler.NewOpenAIGatewayHandler(openAIGatewayService, concurrencyService, billingCacheService, apiKeyService, usageRecordWorkerPool, errorPassthroughService, configConfig)
|
||||
handlerSettingHandler := handler.ProvideSettingHandler(settingService, buildInfo)
|
||||
totpHandler := handler.NewTotpHandler(totpService)
|
||||
handlerPaymentHandler := handler.NewPaymentHandler(paymentService, paymentConfigService, channelService)
|
||||
paymentWebhookHandler := handler.NewPaymentWebhookHandler(paymentService, registry)
|
||||
idempotencyCoordinator := service.ProvideIdempotencyCoordinator(idempotencyRepository, configConfig)
|
||||
idempotencyCleanupService := service.ProvideIdempotencyCleanupService(idempotencyRepository, configConfig)
|
||||
handlers := handler.ProvideHandlers(authHandler, userHandler, apiKeyHandler, usageHandler, redeemHandler, subscriptionHandler, announcementHandler, adminHandlers, gatewayHandler, openAIGatewayHandler, handlerSettingHandler, totpHandler, idempotencyCoordinator, idempotencyCleanupService)
|
||||
handlers := handler.ProvideHandlers(authHandler, userHandler, apiKeyHandler, usageHandler, redeemHandler, subscriptionHandler, announcementHandler, adminHandlers, gatewayHandler, openAIGatewayHandler, handlerSettingHandler, totpHandler, handlerPaymentHandler, paymentWebhookHandler, idempotencyCoordinator, idempotencyCleanupService)
|
||||
jwtAuthMiddleware := middleware.NewJWTAuthMiddleware(authService, userService)
|
||||
adminAuthMiddleware := middleware.NewAdminAuthMiddleware(authService, userService, settingService)
|
||||
apiKeyAuthMiddleware := middleware.NewAPIKeyAuthMiddleware(apiKeyService, subscriptionService, configConfig)
|
||||
@@ -232,11 +240,11 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
|
||||
opsAlertEvaluatorService := service.ProvideOpsAlertEvaluatorService(opsService, opsRepository, emailService, redisClient, configConfig)
|
||||
opsCleanupService := service.ProvideOpsCleanupService(opsRepository, db, redisClient, configConfig)
|
||||
opsScheduledReportService := service.ProvideOpsScheduledReportService(opsService, userService, emailService, redisClient, configConfig)
|
||||
tokenRefreshService := service.ProvideTokenRefreshService(accountRepository, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, compositeTokenCacheInvalidator, schedulerCache, configConfig, tempUnschedCache, privacyClientFactory, proxyRepository, oauthRefreshAPI)
|
||||
tokenRefreshService := service.ProvideTokenRefreshService(accountRepository, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, compositeTokenCacheInvalidator, schedulerCache, configConfig, tempUnschedCache, privacyClientFactory, proxyRepository, oAuthRefreshAPI)
|
||||
accountExpiryService := service.ProvideAccountExpiryService(accountRepository)
|
||||
subscriptionExpiryService := service.ProvideSubscriptionExpiryService(userSubscriptionRepository)
|
||||
scheduledTestRunnerService := service.ProvideScheduledTestRunnerService(scheduledTestPlanRepository, scheduledTestService, accountTestService, rateLimitService, configConfig)
|
||||
v := provideCleanup(client, redisClient, opsMetricsCollector, opsAggregationService, opsAlertEvaluatorService, opsCleanupService, opsScheduledReportService, opsSystemLogSink, schedulerSnapshotService, tokenRefreshService, accountExpiryService, subscriptionExpiryService, usageCleanupService, idempotencyCleanupService, pricingService, emailQueueService, billingCacheService, usageRecordWorkerPool, subscriptionService, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, openAIGatewayService, scheduledTestRunnerService, backupService)
|
||||
v := provideCleanup(client, redisClient, opsMetricsCollector, opsAggregationService, opsAlertEvaluatorService, opsCleanupService, opsScheduledReportService, opsSystemLogSink, schedulerSnapshotService, tokenRefreshService, accountExpiryService, subscriptionExpiryService, usageCleanupService, idempotencyCleanupService, pricingService, emailQueueService, billingCacheService, usageRecordWorkerPool, subscriptionService, oAuthService, openAIOAuthService, geminiOAuthService, antigravityOAuthService, openAIGatewayService, scheduledTestRunnerService, backupService, paymentOrderExpiryService)
|
||||
application := &Application{
|
||||
Server: httpServer,
|
||||
Cleanup: v,
|
||||
@@ -289,6 +297,7 @@ func provideCleanup(
|
||||
openAIGateway *service.OpenAIGatewayService,
|
||||
scheduledTestRunner *service.ScheduledTestRunnerService,
|
||||
backupSvc *service.BackupService,
|
||||
paymentOrderExpiry *service.PaymentOrderExpiryService,
|
||||
) func() {
|
||||
return func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
@@ -424,6 +433,12 @@ func provideCleanup(
|
||||
}
|
||||
return nil
|
||||
}},
|
||||
{"PaymentOrderExpiryService", func() error {
|
||||
if paymentOrderExpiry != nil {
|
||||
paymentOrderExpiry.Stop()
|
||||
}
|
||||
return nil
|
||||
}},
|
||||
}
|
||||
|
||||
infraSteps := []cleanupStep{
|
||||
|
||||
+614
-14
@@ -23,12 +23,16 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
|
||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocode"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
|
||||
"github.com/Wei-Shaw/sub2api/ent/proxy"
|
||||
"github.com/Wei-Shaw/sub2api/ent/redeemcode"
|
||||
"github.com/Wei-Shaw/sub2api/ent/securitysecret"
|
||||
"github.com/Wei-Shaw/sub2api/ent/setting"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
"github.com/Wei-Shaw/sub2api/ent/tlsfingerprintprofile"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagecleanuptask"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagelog"
|
||||
@@ -62,6 +66,12 @@ type Client struct {
|
||||
Group *GroupClient
|
||||
// IdempotencyRecord is the client for interacting with the IdempotencyRecord builders.
|
||||
IdempotencyRecord *IdempotencyRecordClient
|
||||
// PaymentAuditLog is the client for interacting with the PaymentAuditLog builders.
|
||||
PaymentAuditLog *PaymentAuditLogClient
|
||||
// PaymentOrder is the client for interacting with the PaymentOrder builders.
|
||||
PaymentOrder *PaymentOrderClient
|
||||
// PaymentProviderInstance is the client for interacting with the PaymentProviderInstance builders.
|
||||
PaymentProviderInstance *PaymentProviderInstanceClient
|
||||
// PromoCode is the client for interacting with the PromoCode builders.
|
||||
PromoCode *PromoCodeClient
|
||||
// PromoCodeUsage is the client for interacting with the PromoCodeUsage builders.
|
||||
@@ -74,6 +84,8 @@ type Client struct {
|
||||
SecuritySecret *SecuritySecretClient
|
||||
// Setting is the client for interacting with the Setting builders.
|
||||
Setting *SettingClient
|
||||
// SubscriptionPlan is the client for interacting with the SubscriptionPlan builders.
|
||||
SubscriptionPlan *SubscriptionPlanClient
|
||||
// TLSFingerprintProfile is the client for interacting with the TLSFingerprintProfile builders.
|
||||
TLSFingerprintProfile *TLSFingerprintProfileClient
|
||||
// UsageCleanupTask is the client for interacting with the UsageCleanupTask builders.
|
||||
@@ -109,12 +121,16 @@ func (c *Client) init() {
|
||||
c.ErrorPassthroughRule = NewErrorPassthroughRuleClient(c.config)
|
||||
c.Group = NewGroupClient(c.config)
|
||||
c.IdempotencyRecord = NewIdempotencyRecordClient(c.config)
|
||||
c.PaymentAuditLog = NewPaymentAuditLogClient(c.config)
|
||||
c.PaymentOrder = NewPaymentOrderClient(c.config)
|
||||
c.PaymentProviderInstance = NewPaymentProviderInstanceClient(c.config)
|
||||
c.PromoCode = NewPromoCodeClient(c.config)
|
||||
c.PromoCodeUsage = NewPromoCodeUsageClient(c.config)
|
||||
c.Proxy = NewProxyClient(c.config)
|
||||
c.RedeemCode = NewRedeemCodeClient(c.config)
|
||||
c.SecuritySecret = NewSecuritySecretClient(c.config)
|
||||
c.Setting = NewSettingClient(c.config)
|
||||
c.SubscriptionPlan = NewSubscriptionPlanClient(c.config)
|
||||
c.TLSFingerprintProfile = NewTLSFingerprintProfileClient(c.config)
|
||||
c.UsageCleanupTask = NewUsageCleanupTaskClient(c.config)
|
||||
c.UsageLog = NewUsageLogClient(c.config)
|
||||
@@ -223,12 +239,16 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
|
||||
ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg),
|
||||
Group: NewGroupClient(cfg),
|
||||
IdempotencyRecord: NewIdempotencyRecordClient(cfg),
|
||||
PaymentAuditLog: NewPaymentAuditLogClient(cfg),
|
||||
PaymentOrder: NewPaymentOrderClient(cfg),
|
||||
PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg),
|
||||
PromoCode: NewPromoCodeClient(cfg),
|
||||
PromoCodeUsage: NewPromoCodeUsageClient(cfg),
|
||||
Proxy: NewProxyClient(cfg),
|
||||
RedeemCode: NewRedeemCodeClient(cfg),
|
||||
SecuritySecret: NewSecuritySecretClient(cfg),
|
||||
Setting: NewSettingClient(cfg),
|
||||
SubscriptionPlan: NewSubscriptionPlanClient(cfg),
|
||||
TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg),
|
||||
UsageCleanupTask: NewUsageCleanupTaskClient(cfg),
|
||||
UsageLog: NewUsageLogClient(cfg),
|
||||
@@ -264,12 +284,16 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
|
||||
ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg),
|
||||
Group: NewGroupClient(cfg),
|
||||
IdempotencyRecord: NewIdempotencyRecordClient(cfg),
|
||||
PaymentAuditLog: NewPaymentAuditLogClient(cfg),
|
||||
PaymentOrder: NewPaymentOrderClient(cfg),
|
||||
PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg),
|
||||
PromoCode: NewPromoCodeClient(cfg),
|
||||
PromoCodeUsage: NewPromoCodeUsageClient(cfg),
|
||||
Proxy: NewProxyClient(cfg),
|
||||
RedeemCode: NewRedeemCodeClient(cfg),
|
||||
SecuritySecret: NewSecuritySecretClient(cfg),
|
||||
Setting: NewSettingClient(cfg),
|
||||
SubscriptionPlan: NewSubscriptionPlanClient(cfg),
|
||||
TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg),
|
||||
UsageCleanupTask: NewUsageCleanupTaskClient(cfg),
|
||||
UsageLog: NewUsageLogClient(cfg),
|
||||
@@ -308,10 +332,11 @@ func (c *Client) Close() error {
|
||||
func (c *Client) Use(hooks ...Hook) {
|
||||
for _, n := range []interface{ Use(...Hook) }{
|
||||
c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead,
|
||||
c.ErrorPassthroughRule, c.Group, c.IdempotencyRecord, c.PromoCode,
|
||||
c.ErrorPassthroughRule, c.Group, c.IdempotencyRecord, c.PaymentAuditLog,
|
||||
c.PaymentOrder, c.PaymentProviderInstance, c.PromoCode,
|
||||
c.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting,
|
||||
c.TLSFingerprintProfile, c.UsageCleanupTask, c.UsageLog, c.User,
|
||||
c.UserAllowedGroup, c.UserAttributeDefinition, c.UserAttributeValue,
|
||||
c.SubscriptionPlan, c.TLSFingerprintProfile, c.UsageCleanupTask, c.UsageLog,
|
||||
c.User, c.UserAllowedGroup, c.UserAttributeDefinition, c.UserAttributeValue,
|
||||
c.UserSubscription,
|
||||
} {
|
||||
n.Use(hooks...)
|
||||
@@ -323,10 +348,11 @@ func (c *Client) Use(hooks ...Hook) {
|
||||
func (c *Client) Intercept(interceptors ...Interceptor) {
|
||||
for _, n := range []interface{ Intercept(...Interceptor) }{
|
||||
c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead,
|
||||
c.ErrorPassthroughRule, c.Group, c.IdempotencyRecord, c.PromoCode,
|
||||
c.ErrorPassthroughRule, c.Group, c.IdempotencyRecord, c.PaymentAuditLog,
|
||||
c.PaymentOrder, c.PaymentProviderInstance, c.PromoCode,
|
||||
c.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting,
|
||||
c.TLSFingerprintProfile, c.UsageCleanupTask, c.UsageLog, c.User,
|
||||
c.UserAllowedGroup, c.UserAttributeDefinition, c.UserAttributeValue,
|
||||
c.SubscriptionPlan, c.TLSFingerprintProfile, c.UsageCleanupTask, c.UsageLog,
|
||||
c.User, c.UserAllowedGroup, c.UserAttributeDefinition, c.UserAttributeValue,
|
||||
c.UserSubscription,
|
||||
} {
|
||||
n.Intercept(interceptors...)
|
||||
@@ -352,6 +378,12 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
|
||||
return c.Group.mutate(ctx, m)
|
||||
case *IdempotencyRecordMutation:
|
||||
return c.IdempotencyRecord.mutate(ctx, m)
|
||||
case *PaymentAuditLogMutation:
|
||||
return c.PaymentAuditLog.mutate(ctx, m)
|
||||
case *PaymentOrderMutation:
|
||||
return c.PaymentOrder.mutate(ctx, m)
|
||||
case *PaymentProviderInstanceMutation:
|
||||
return c.PaymentProviderInstance.mutate(ctx, m)
|
||||
case *PromoCodeMutation:
|
||||
return c.PromoCode.mutate(ctx, m)
|
||||
case *PromoCodeUsageMutation:
|
||||
@@ -364,6 +396,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
|
||||
return c.SecuritySecret.mutate(ctx, m)
|
||||
case *SettingMutation:
|
||||
return c.Setting.mutate(ctx, m)
|
||||
case *SubscriptionPlanMutation:
|
||||
return c.SubscriptionPlan.mutate(ctx, m)
|
||||
case *TLSFingerprintProfileMutation:
|
||||
return c.TLSFingerprintProfile.mutate(ctx, m)
|
||||
case *UsageCleanupTaskMutation:
|
||||
@@ -1726,6 +1760,421 @@ func (c *IdempotencyRecordClient) mutate(ctx context.Context, m *IdempotencyReco
|
||||
}
|
||||
}
|
||||
|
||||
// PaymentAuditLogClient is a client for the PaymentAuditLog schema.
|
||||
type PaymentAuditLogClient struct {
|
||||
config
|
||||
}
|
||||
|
||||
// NewPaymentAuditLogClient returns a client for the PaymentAuditLog from the given config.
|
||||
func NewPaymentAuditLogClient(c config) *PaymentAuditLogClient {
|
||||
return &PaymentAuditLogClient{config: c}
|
||||
}
|
||||
|
||||
// Use adds a list of mutation hooks to the hooks stack.
|
||||
// A call to `Use(f, g, h)` equals to `paymentauditlog.Hooks(f(g(h())))`.
|
||||
func (c *PaymentAuditLogClient) Use(hooks ...Hook) {
|
||||
c.hooks.PaymentAuditLog = append(c.hooks.PaymentAuditLog, hooks...)
|
||||
}
|
||||
|
||||
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||
// A call to `Intercept(f, g, h)` equals to `paymentauditlog.Intercept(f(g(h())))`.
|
||||
func (c *PaymentAuditLogClient) Intercept(interceptors ...Interceptor) {
|
||||
c.inters.PaymentAuditLog = append(c.inters.PaymentAuditLog, interceptors...)
|
||||
}
|
||||
|
||||
// Create returns a builder for creating a PaymentAuditLog entity.
|
||||
func (c *PaymentAuditLogClient) Create() *PaymentAuditLogCreate {
|
||||
mutation := newPaymentAuditLogMutation(c.config, OpCreate)
|
||||
return &PaymentAuditLogCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// CreateBulk returns a builder for creating a bulk of PaymentAuditLog entities.
|
||||
func (c *PaymentAuditLogClient) CreateBulk(builders ...*PaymentAuditLogCreate) *PaymentAuditLogCreateBulk {
|
||||
return &PaymentAuditLogCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||
// a builder and applies setFunc on it.
|
||||
func (c *PaymentAuditLogClient) MapCreateBulk(slice any, setFunc func(*PaymentAuditLogCreate, int)) *PaymentAuditLogCreateBulk {
|
||||
rv := reflect.ValueOf(slice)
|
||||
if rv.Kind() != reflect.Slice {
|
||||
return &PaymentAuditLogCreateBulk{err: fmt.Errorf("calling to PaymentAuditLogClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||
}
|
||||
builders := make([]*PaymentAuditLogCreate, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
builders[i] = c.Create()
|
||||
setFunc(builders[i], i)
|
||||
}
|
||||
return &PaymentAuditLogCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// Update returns an update builder for PaymentAuditLog.
|
||||
func (c *PaymentAuditLogClient) Update() *PaymentAuditLogUpdate {
|
||||
mutation := newPaymentAuditLogMutation(c.config, OpUpdate)
|
||||
return &PaymentAuditLogUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOne returns an update builder for the given entity.
|
||||
func (c *PaymentAuditLogClient) UpdateOne(_m *PaymentAuditLog) *PaymentAuditLogUpdateOne {
|
||||
mutation := newPaymentAuditLogMutation(c.config, OpUpdateOne, withPaymentAuditLog(_m))
|
||||
return &PaymentAuditLogUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOneID returns an update builder for the given id.
|
||||
func (c *PaymentAuditLogClient) UpdateOneID(id int64) *PaymentAuditLogUpdateOne {
|
||||
mutation := newPaymentAuditLogMutation(c.config, OpUpdateOne, withPaymentAuditLogID(id))
|
||||
return &PaymentAuditLogUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// Delete returns a delete builder for PaymentAuditLog.
|
||||
func (c *PaymentAuditLogClient) Delete() *PaymentAuditLogDelete {
|
||||
mutation := newPaymentAuditLogMutation(c.config, OpDelete)
|
||||
return &PaymentAuditLogDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// DeleteOne returns a builder for deleting the given entity.
|
||||
func (c *PaymentAuditLogClient) DeleteOne(_m *PaymentAuditLog) *PaymentAuditLogDeleteOne {
|
||||
return c.DeleteOneID(_m.ID)
|
||||
}
|
||||
|
||||
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||
func (c *PaymentAuditLogClient) DeleteOneID(id int64) *PaymentAuditLogDeleteOne {
|
||||
builder := c.Delete().Where(paymentauditlog.ID(id))
|
||||
builder.mutation.id = &id
|
||||
builder.mutation.op = OpDeleteOne
|
||||
return &PaymentAuditLogDeleteOne{builder}
|
||||
}
|
||||
|
||||
// Query returns a query builder for PaymentAuditLog.
|
||||
func (c *PaymentAuditLogClient) Query() *PaymentAuditLogQuery {
|
||||
return &PaymentAuditLogQuery{
|
||||
config: c.config,
|
||||
ctx: &QueryContext{Type: TypePaymentAuditLog},
|
||||
inters: c.Interceptors(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a PaymentAuditLog entity by its id.
|
||||
func (c *PaymentAuditLogClient) Get(ctx context.Context, id int64) (*PaymentAuditLog, error) {
|
||||
return c.Query().Where(paymentauditlog.ID(id)).Only(ctx)
|
||||
}
|
||||
|
||||
// GetX is like Get, but panics if an error occurs.
|
||||
func (c *PaymentAuditLogClient) GetX(ctx context.Context, id int64) *PaymentAuditLog {
|
||||
obj, err := c.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *PaymentAuditLogClient) Hooks() []Hook {
|
||||
return c.hooks.PaymentAuditLog
|
||||
}
|
||||
|
||||
// Interceptors returns the client interceptors.
|
||||
func (c *PaymentAuditLogClient) Interceptors() []Interceptor {
|
||||
return c.inters.PaymentAuditLog
|
||||
}
|
||||
|
||||
func (c *PaymentAuditLogClient) mutate(ctx context.Context, m *PaymentAuditLogMutation) (Value, error) {
|
||||
switch m.Op() {
|
||||
case OpCreate:
|
||||
return (&PaymentAuditLogCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdate:
|
||||
return (&PaymentAuditLogUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdateOne:
|
||||
return (&PaymentAuditLogUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpDelete, OpDeleteOne:
|
||||
return (&PaymentAuditLogDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||
default:
|
||||
return nil, fmt.Errorf("ent: unknown PaymentAuditLog mutation op: %q", m.Op())
|
||||
}
|
||||
}
|
||||
|
||||
// PaymentOrderClient is a client for the PaymentOrder schema.
|
||||
type PaymentOrderClient struct {
|
||||
config
|
||||
}
|
||||
|
||||
// NewPaymentOrderClient returns a client for the PaymentOrder from the given config.
|
||||
func NewPaymentOrderClient(c config) *PaymentOrderClient {
|
||||
return &PaymentOrderClient{config: c}
|
||||
}
|
||||
|
||||
// Use adds a list of mutation hooks to the hooks stack.
|
||||
// A call to `Use(f, g, h)` equals to `paymentorder.Hooks(f(g(h())))`.
|
||||
func (c *PaymentOrderClient) Use(hooks ...Hook) {
|
||||
c.hooks.PaymentOrder = append(c.hooks.PaymentOrder, hooks...)
|
||||
}
|
||||
|
||||
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||
// A call to `Intercept(f, g, h)` equals to `paymentorder.Intercept(f(g(h())))`.
|
||||
func (c *PaymentOrderClient) Intercept(interceptors ...Interceptor) {
|
||||
c.inters.PaymentOrder = append(c.inters.PaymentOrder, interceptors...)
|
||||
}
|
||||
|
||||
// Create returns a builder for creating a PaymentOrder entity.
|
||||
func (c *PaymentOrderClient) Create() *PaymentOrderCreate {
|
||||
mutation := newPaymentOrderMutation(c.config, OpCreate)
|
||||
return &PaymentOrderCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// CreateBulk returns a builder for creating a bulk of PaymentOrder entities.
|
||||
func (c *PaymentOrderClient) CreateBulk(builders ...*PaymentOrderCreate) *PaymentOrderCreateBulk {
|
||||
return &PaymentOrderCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||
// a builder and applies setFunc on it.
|
||||
func (c *PaymentOrderClient) MapCreateBulk(slice any, setFunc func(*PaymentOrderCreate, int)) *PaymentOrderCreateBulk {
|
||||
rv := reflect.ValueOf(slice)
|
||||
if rv.Kind() != reflect.Slice {
|
||||
return &PaymentOrderCreateBulk{err: fmt.Errorf("calling to PaymentOrderClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||
}
|
||||
builders := make([]*PaymentOrderCreate, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
builders[i] = c.Create()
|
||||
setFunc(builders[i], i)
|
||||
}
|
||||
return &PaymentOrderCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// Update returns an update builder for PaymentOrder.
|
||||
func (c *PaymentOrderClient) Update() *PaymentOrderUpdate {
|
||||
mutation := newPaymentOrderMutation(c.config, OpUpdate)
|
||||
return &PaymentOrderUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOne returns an update builder for the given entity.
|
||||
func (c *PaymentOrderClient) UpdateOne(_m *PaymentOrder) *PaymentOrderUpdateOne {
|
||||
mutation := newPaymentOrderMutation(c.config, OpUpdateOne, withPaymentOrder(_m))
|
||||
return &PaymentOrderUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOneID returns an update builder for the given id.
|
||||
func (c *PaymentOrderClient) UpdateOneID(id int64) *PaymentOrderUpdateOne {
|
||||
mutation := newPaymentOrderMutation(c.config, OpUpdateOne, withPaymentOrderID(id))
|
||||
return &PaymentOrderUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// Delete returns a delete builder for PaymentOrder.
|
||||
func (c *PaymentOrderClient) Delete() *PaymentOrderDelete {
|
||||
mutation := newPaymentOrderMutation(c.config, OpDelete)
|
||||
return &PaymentOrderDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// DeleteOne returns a builder for deleting the given entity.
|
||||
func (c *PaymentOrderClient) DeleteOne(_m *PaymentOrder) *PaymentOrderDeleteOne {
|
||||
return c.DeleteOneID(_m.ID)
|
||||
}
|
||||
|
||||
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||
func (c *PaymentOrderClient) DeleteOneID(id int64) *PaymentOrderDeleteOne {
|
||||
builder := c.Delete().Where(paymentorder.ID(id))
|
||||
builder.mutation.id = &id
|
||||
builder.mutation.op = OpDeleteOne
|
||||
return &PaymentOrderDeleteOne{builder}
|
||||
}
|
||||
|
||||
// Query returns a query builder for PaymentOrder.
|
||||
func (c *PaymentOrderClient) Query() *PaymentOrderQuery {
|
||||
return &PaymentOrderQuery{
|
||||
config: c.config,
|
||||
ctx: &QueryContext{Type: TypePaymentOrder},
|
||||
inters: c.Interceptors(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a PaymentOrder entity by its id.
|
||||
func (c *PaymentOrderClient) Get(ctx context.Context, id int64) (*PaymentOrder, error) {
|
||||
return c.Query().Where(paymentorder.ID(id)).Only(ctx)
|
||||
}
|
||||
|
||||
// GetX is like Get, but panics if an error occurs.
|
||||
func (c *PaymentOrderClient) GetX(ctx context.Context, id int64) *PaymentOrder {
|
||||
obj, err := c.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// QueryUser queries the user edge of a PaymentOrder.
|
||||
func (c *PaymentOrderClient) QueryUser(_m *PaymentOrder) *UserQuery {
|
||||
query := (&UserClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(paymentorder.Table, paymentorder.FieldID, id),
|
||||
sqlgraph.To(user.Table, user.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, paymentorder.UserTable, paymentorder.UserColumn),
|
||||
)
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *PaymentOrderClient) Hooks() []Hook {
|
||||
return c.hooks.PaymentOrder
|
||||
}
|
||||
|
||||
// Interceptors returns the client interceptors.
|
||||
func (c *PaymentOrderClient) Interceptors() []Interceptor {
|
||||
return c.inters.PaymentOrder
|
||||
}
|
||||
|
||||
func (c *PaymentOrderClient) mutate(ctx context.Context, m *PaymentOrderMutation) (Value, error) {
|
||||
switch m.Op() {
|
||||
case OpCreate:
|
||||
return (&PaymentOrderCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdate:
|
||||
return (&PaymentOrderUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdateOne:
|
||||
return (&PaymentOrderUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpDelete, OpDeleteOne:
|
||||
return (&PaymentOrderDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||
default:
|
||||
return nil, fmt.Errorf("ent: unknown PaymentOrder mutation op: %q", m.Op())
|
||||
}
|
||||
}
|
||||
|
||||
// PaymentProviderInstanceClient is a client for the PaymentProviderInstance schema.
|
||||
type PaymentProviderInstanceClient struct {
|
||||
config
|
||||
}
|
||||
|
||||
// NewPaymentProviderInstanceClient returns a client for the PaymentProviderInstance from the given config.
|
||||
func NewPaymentProviderInstanceClient(c config) *PaymentProviderInstanceClient {
|
||||
return &PaymentProviderInstanceClient{config: c}
|
||||
}
|
||||
|
||||
// Use adds a list of mutation hooks to the hooks stack.
|
||||
// A call to `Use(f, g, h)` equals to `paymentproviderinstance.Hooks(f(g(h())))`.
|
||||
func (c *PaymentProviderInstanceClient) Use(hooks ...Hook) {
|
||||
c.hooks.PaymentProviderInstance = append(c.hooks.PaymentProviderInstance, hooks...)
|
||||
}
|
||||
|
||||
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||
// A call to `Intercept(f, g, h)` equals to `paymentproviderinstance.Intercept(f(g(h())))`.
|
||||
func (c *PaymentProviderInstanceClient) Intercept(interceptors ...Interceptor) {
|
||||
c.inters.PaymentProviderInstance = append(c.inters.PaymentProviderInstance, interceptors...)
|
||||
}
|
||||
|
||||
// Create returns a builder for creating a PaymentProviderInstance entity.
|
||||
func (c *PaymentProviderInstanceClient) Create() *PaymentProviderInstanceCreate {
|
||||
mutation := newPaymentProviderInstanceMutation(c.config, OpCreate)
|
||||
return &PaymentProviderInstanceCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// CreateBulk returns a builder for creating a bulk of PaymentProviderInstance entities.
|
||||
func (c *PaymentProviderInstanceClient) CreateBulk(builders ...*PaymentProviderInstanceCreate) *PaymentProviderInstanceCreateBulk {
|
||||
return &PaymentProviderInstanceCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||
// a builder and applies setFunc on it.
|
||||
func (c *PaymentProviderInstanceClient) MapCreateBulk(slice any, setFunc func(*PaymentProviderInstanceCreate, int)) *PaymentProviderInstanceCreateBulk {
|
||||
rv := reflect.ValueOf(slice)
|
||||
if rv.Kind() != reflect.Slice {
|
||||
return &PaymentProviderInstanceCreateBulk{err: fmt.Errorf("calling to PaymentProviderInstanceClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||
}
|
||||
builders := make([]*PaymentProviderInstanceCreate, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
builders[i] = c.Create()
|
||||
setFunc(builders[i], i)
|
||||
}
|
||||
return &PaymentProviderInstanceCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// Update returns an update builder for PaymentProviderInstance.
|
||||
func (c *PaymentProviderInstanceClient) Update() *PaymentProviderInstanceUpdate {
|
||||
mutation := newPaymentProviderInstanceMutation(c.config, OpUpdate)
|
||||
return &PaymentProviderInstanceUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOne returns an update builder for the given entity.
|
||||
func (c *PaymentProviderInstanceClient) UpdateOne(_m *PaymentProviderInstance) *PaymentProviderInstanceUpdateOne {
|
||||
mutation := newPaymentProviderInstanceMutation(c.config, OpUpdateOne, withPaymentProviderInstance(_m))
|
||||
return &PaymentProviderInstanceUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOneID returns an update builder for the given id.
|
||||
func (c *PaymentProviderInstanceClient) UpdateOneID(id int64) *PaymentProviderInstanceUpdateOne {
|
||||
mutation := newPaymentProviderInstanceMutation(c.config, OpUpdateOne, withPaymentProviderInstanceID(id))
|
||||
return &PaymentProviderInstanceUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// Delete returns a delete builder for PaymentProviderInstance.
|
||||
func (c *PaymentProviderInstanceClient) Delete() *PaymentProviderInstanceDelete {
|
||||
mutation := newPaymentProviderInstanceMutation(c.config, OpDelete)
|
||||
return &PaymentProviderInstanceDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// DeleteOne returns a builder for deleting the given entity.
|
||||
func (c *PaymentProviderInstanceClient) DeleteOne(_m *PaymentProviderInstance) *PaymentProviderInstanceDeleteOne {
|
||||
return c.DeleteOneID(_m.ID)
|
||||
}
|
||||
|
||||
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||
func (c *PaymentProviderInstanceClient) DeleteOneID(id int64) *PaymentProviderInstanceDeleteOne {
|
||||
builder := c.Delete().Where(paymentproviderinstance.ID(id))
|
||||
builder.mutation.id = &id
|
||||
builder.mutation.op = OpDeleteOne
|
||||
return &PaymentProviderInstanceDeleteOne{builder}
|
||||
}
|
||||
|
||||
// Query returns a query builder for PaymentProviderInstance.
|
||||
func (c *PaymentProviderInstanceClient) Query() *PaymentProviderInstanceQuery {
|
||||
return &PaymentProviderInstanceQuery{
|
||||
config: c.config,
|
||||
ctx: &QueryContext{Type: TypePaymentProviderInstance},
|
||||
inters: c.Interceptors(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a PaymentProviderInstance entity by its id.
|
||||
func (c *PaymentProviderInstanceClient) Get(ctx context.Context, id int64) (*PaymentProviderInstance, error) {
|
||||
return c.Query().Where(paymentproviderinstance.ID(id)).Only(ctx)
|
||||
}
|
||||
|
||||
// GetX is like Get, but panics if an error occurs.
|
||||
func (c *PaymentProviderInstanceClient) GetX(ctx context.Context, id int64) *PaymentProviderInstance {
|
||||
obj, err := c.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *PaymentProviderInstanceClient) Hooks() []Hook {
|
||||
return c.hooks.PaymentProviderInstance
|
||||
}
|
||||
|
||||
// Interceptors returns the client interceptors.
|
||||
func (c *PaymentProviderInstanceClient) Interceptors() []Interceptor {
|
||||
return c.inters.PaymentProviderInstance
|
||||
}
|
||||
|
||||
func (c *PaymentProviderInstanceClient) mutate(ctx context.Context, m *PaymentProviderInstanceMutation) (Value, error) {
|
||||
switch m.Op() {
|
||||
case OpCreate:
|
||||
return (&PaymentProviderInstanceCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdate:
|
||||
return (&PaymentProviderInstanceUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdateOne:
|
||||
return (&PaymentProviderInstanceUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpDelete, OpDeleteOne:
|
||||
return (&PaymentProviderInstanceDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||
default:
|
||||
return nil, fmt.Errorf("ent: unknown PaymentProviderInstance mutation op: %q", m.Op())
|
||||
}
|
||||
}
|
||||
|
||||
// PromoCodeClient is a client for the PromoCode schema.
|
||||
type PromoCodeClient struct {
|
||||
config
|
||||
@@ -2622,6 +3071,139 @@ func (c *SettingClient) mutate(ctx context.Context, m *SettingMutation) (Value,
|
||||
}
|
||||
}
|
||||
|
||||
// SubscriptionPlanClient is a client for the SubscriptionPlan schema.
|
||||
type SubscriptionPlanClient struct {
|
||||
config
|
||||
}
|
||||
|
||||
// NewSubscriptionPlanClient returns a client for the SubscriptionPlan from the given config.
|
||||
func NewSubscriptionPlanClient(c config) *SubscriptionPlanClient {
|
||||
return &SubscriptionPlanClient{config: c}
|
||||
}
|
||||
|
||||
// Use adds a list of mutation hooks to the hooks stack.
|
||||
// A call to `Use(f, g, h)` equals to `subscriptionplan.Hooks(f(g(h())))`.
|
||||
func (c *SubscriptionPlanClient) Use(hooks ...Hook) {
|
||||
c.hooks.SubscriptionPlan = append(c.hooks.SubscriptionPlan, hooks...)
|
||||
}
|
||||
|
||||
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||
// A call to `Intercept(f, g, h)` equals to `subscriptionplan.Intercept(f(g(h())))`.
|
||||
func (c *SubscriptionPlanClient) Intercept(interceptors ...Interceptor) {
|
||||
c.inters.SubscriptionPlan = append(c.inters.SubscriptionPlan, interceptors...)
|
||||
}
|
||||
|
||||
// Create returns a builder for creating a SubscriptionPlan entity.
|
||||
func (c *SubscriptionPlanClient) Create() *SubscriptionPlanCreate {
|
||||
mutation := newSubscriptionPlanMutation(c.config, OpCreate)
|
||||
return &SubscriptionPlanCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// CreateBulk returns a builder for creating a bulk of SubscriptionPlan entities.
|
||||
func (c *SubscriptionPlanClient) CreateBulk(builders ...*SubscriptionPlanCreate) *SubscriptionPlanCreateBulk {
|
||||
return &SubscriptionPlanCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||
// a builder and applies setFunc on it.
|
||||
func (c *SubscriptionPlanClient) MapCreateBulk(slice any, setFunc func(*SubscriptionPlanCreate, int)) *SubscriptionPlanCreateBulk {
|
||||
rv := reflect.ValueOf(slice)
|
||||
if rv.Kind() != reflect.Slice {
|
||||
return &SubscriptionPlanCreateBulk{err: fmt.Errorf("calling to SubscriptionPlanClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||
}
|
||||
builders := make([]*SubscriptionPlanCreate, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
builders[i] = c.Create()
|
||||
setFunc(builders[i], i)
|
||||
}
|
||||
return &SubscriptionPlanCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// Update returns an update builder for SubscriptionPlan.
|
||||
func (c *SubscriptionPlanClient) Update() *SubscriptionPlanUpdate {
|
||||
mutation := newSubscriptionPlanMutation(c.config, OpUpdate)
|
||||
return &SubscriptionPlanUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOne returns an update builder for the given entity.
|
||||
func (c *SubscriptionPlanClient) UpdateOne(_m *SubscriptionPlan) *SubscriptionPlanUpdateOne {
|
||||
mutation := newSubscriptionPlanMutation(c.config, OpUpdateOne, withSubscriptionPlan(_m))
|
||||
return &SubscriptionPlanUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOneID returns an update builder for the given id.
|
||||
func (c *SubscriptionPlanClient) UpdateOneID(id int64) *SubscriptionPlanUpdateOne {
|
||||
mutation := newSubscriptionPlanMutation(c.config, OpUpdateOne, withSubscriptionPlanID(id))
|
||||
return &SubscriptionPlanUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// Delete returns a delete builder for SubscriptionPlan.
|
||||
func (c *SubscriptionPlanClient) Delete() *SubscriptionPlanDelete {
|
||||
mutation := newSubscriptionPlanMutation(c.config, OpDelete)
|
||||
return &SubscriptionPlanDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// DeleteOne returns a builder for deleting the given entity.
|
||||
func (c *SubscriptionPlanClient) DeleteOne(_m *SubscriptionPlan) *SubscriptionPlanDeleteOne {
|
||||
return c.DeleteOneID(_m.ID)
|
||||
}
|
||||
|
||||
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||
func (c *SubscriptionPlanClient) DeleteOneID(id int64) *SubscriptionPlanDeleteOne {
|
||||
builder := c.Delete().Where(subscriptionplan.ID(id))
|
||||
builder.mutation.id = &id
|
||||
builder.mutation.op = OpDeleteOne
|
||||
return &SubscriptionPlanDeleteOne{builder}
|
||||
}
|
||||
|
||||
// Query returns a query builder for SubscriptionPlan.
|
||||
func (c *SubscriptionPlanClient) Query() *SubscriptionPlanQuery {
|
||||
return &SubscriptionPlanQuery{
|
||||
config: c.config,
|
||||
ctx: &QueryContext{Type: TypeSubscriptionPlan},
|
||||
inters: c.Interceptors(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a SubscriptionPlan entity by its id.
|
||||
func (c *SubscriptionPlanClient) Get(ctx context.Context, id int64) (*SubscriptionPlan, error) {
|
||||
return c.Query().Where(subscriptionplan.ID(id)).Only(ctx)
|
||||
}
|
||||
|
||||
// GetX is like Get, but panics if an error occurs.
|
||||
func (c *SubscriptionPlanClient) GetX(ctx context.Context, id int64) *SubscriptionPlan {
|
||||
obj, err := c.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *SubscriptionPlanClient) Hooks() []Hook {
|
||||
return c.hooks.SubscriptionPlan
|
||||
}
|
||||
|
||||
// Interceptors returns the client interceptors.
|
||||
func (c *SubscriptionPlanClient) Interceptors() []Interceptor {
|
||||
return c.inters.SubscriptionPlan
|
||||
}
|
||||
|
||||
func (c *SubscriptionPlanClient) mutate(ctx context.Context, m *SubscriptionPlanMutation) (Value, error) {
|
||||
switch m.Op() {
|
||||
case OpCreate:
|
||||
return (&SubscriptionPlanCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdate:
|
||||
return (&SubscriptionPlanUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdateOne:
|
||||
return (&SubscriptionPlanUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpDelete, OpDeleteOne:
|
||||
return (&SubscriptionPlanDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||
default:
|
||||
return nil, fmt.Errorf("ent: unknown SubscriptionPlan mutation op: %q", m.Op())
|
||||
}
|
||||
}
|
||||
|
||||
// TLSFingerprintProfileClient is a client for the TLSFingerprintProfile schema.
|
||||
type TLSFingerprintProfileClient struct {
|
||||
config
|
||||
@@ -3353,6 +3935,22 @@ func (c *UserClient) QueryPromoCodeUsages(_m *User) *PromoCodeUsageQuery {
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryPaymentOrders queries the payment_orders edge of a User.
|
||||
func (c *UserClient) QueryPaymentOrders(_m *User) *PaymentOrderQuery {
|
||||
query := (&PaymentOrderClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(user.Table, user.FieldID, id),
|
||||
sqlgraph.To(paymentorder.Table, paymentorder.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, user.PaymentOrdersTable, user.PaymentOrdersColumn),
|
||||
)
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryUserAllowedGroups queries the user_allowed_groups edge of a User.
|
||||
func (c *UserClient) QueryUserAllowedGroups(_m *User) *UserAllowedGroupQuery {
|
||||
query := (&UserAllowedGroupClient{config: c.config}).Query()
|
||||
@@ -4031,17 +4629,19 @@ func (c *UserSubscriptionClient) mutate(ctx context.Context, m *UserSubscription
|
||||
type (
|
||||
hooks struct {
|
||||
APIKey, Account, AccountGroup, Announcement, AnnouncementRead,
|
||||
ErrorPassthroughRule, Group, IdempotencyRecord, PromoCode, PromoCodeUsage,
|
||||
Proxy, RedeemCode, SecuritySecret, Setting, TLSFingerprintProfile,
|
||||
UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition,
|
||||
UserAttributeValue, UserSubscription []ent.Hook
|
||||
ErrorPassthroughRule, Group, IdempotencyRecord, PaymentAuditLog,
|
||||
PaymentOrder, PaymentProviderInstance, PromoCode,
|
||||
PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan,
|
||||
TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup,
|
||||
UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Hook
|
||||
}
|
||||
inters struct {
|
||||
APIKey, Account, AccountGroup, Announcement, AnnouncementRead,
|
||||
ErrorPassthroughRule, Group, IdempotencyRecord, PromoCode, PromoCodeUsage,
|
||||
Proxy, RedeemCode, SecuritySecret, Setting, TLSFingerprintProfile,
|
||||
UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition,
|
||||
UserAttributeValue, UserSubscription []ent.Interceptor
|
||||
ErrorPassthroughRule, Group, IdempotencyRecord, PaymentAuditLog,
|
||||
PaymentOrder, PaymentProviderInstance, PromoCode,
|
||||
PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan,
|
||||
TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup,
|
||||
UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Interceptor
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -20,12 +20,16 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
|
||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocode"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
|
||||
"github.com/Wei-Shaw/sub2api/ent/proxy"
|
||||
"github.com/Wei-Shaw/sub2api/ent/redeemcode"
|
||||
"github.com/Wei-Shaw/sub2api/ent/securitysecret"
|
||||
"github.com/Wei-Shaw/sub2api/ent/setting"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
"github.com/Wei-Shaw/sub2api/ent/tlsfingerprintprofile"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagecleanuptask"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagelog"
|
||||
@@ -102,12 +106,16 @@ func checkColumn(t, c string) error {
|
||||
errorpassthroughrule.Table: errorpassthroughrule.ValidColumn,
|
||||
group.Table: group.ValidColumn,
|
||||
idempotencyrecord.Table: idempotencyrecord.ValidColumn,
|
||||
paymentauditlog.Table: paymentauditlog.ValidColumn,
|
||||
paymentorder.Table: paymentorder.ValidColumn,
|
||||
paymentproviderinstance.Table: paymentproviderinstance.ValidColumn,
|
||||
promocode.Table: promocode.ValidColumn,
|
||||
promocodeusage.Table: promocodeusage.ValidColumn,
|
||||
proxy.Table: proxy.ValidColumn,
|
||||
redeemcode.Table: redeemcode.ValidColumn,
|
||||
securitysecret.Table: securitysecret.ValidColumn,
|
||||
setting.Table: setting.ValidColumn,
|
||||
subscriptionplan.Table: subscriptionplan.ValidColumn,
|
||||
tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn,
|
||||
usagecleanuptask.Table: usagecleanuptask.ValidColumn,
|
||||
usagelog.Table: usagelog.ValidColumn,
|
||||
|
||||
@@ -105,6 +105,42 @@ func (f IdempotencyRecordFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.IdempotencyRecordMutation", m)
|
||||
}
|
||||
|
||||
// The PaymentAuditLogFunc type is an adapter to allow the use of ordinary
|
||||
// function as PaymentAuditLog mutator.
|
||||
type PaymentAuditLogFunc func(context.Context, *ent.PaymentAuditLogMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f PaymentAuditLogFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.PaymentAuditLogMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PaymentAuditLogMutation", m)
|
||||
}
|
||||
|
||||
// The PaymentOrderFunc type is an adapter to allow the use of ordinary
|
||||
// function as PaymentOrder mutator.
|
||||
type PaymentOrderFunc func(context.Context, *ent.PaymentOrderMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f PaymentOrderFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.PaymentOrderMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PaymentOrderMutation", m)
|
||||
}
|
||||
|
||||
// The PaymentProviderInstanceFunc type is an adapter to allow the use of ordinary
|
||||
// function as PaymentProviderInstance mutator.
|
||||
type PaymentProviderInstanceFunc func(context.Context, *ent.PaymentProviderInstanceMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f PaymentProviderInstanceFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.PaymentProviderInstanceMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PaymentProviderInstanceMutation", m)
|
||||
}
|
||||
|
||||
// The PromoCodeFunc type is an adapter to allow the use of ordinary
|
||||
// function as PromoCode mutator.
|
||||
type PromoCodeFunc func(context.Context, *ent.PromoCodeMutation) (ent.Value, error)
|
||||
@@ -177,6 +213,18 @@ func (f SettingFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, err
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.SettingMutation", m)
|
||||
}
|
||||
|
||||
// The SubscriptionPlanFunc type is an adapter to allow the use of ordinary
|
||||
// function as SubscriptionPlan mutator.
|
||||
type SubscriptionPlanFunc func(context.Context, *ent.SubscriptionPlanMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f SubscriptionPlanFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.SubscriptionPlanMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.SubscriptionPlanMutation", m)
|
||||
}
|
||||
|
||||
// The TLSFingerprintProfileFunc type is an adapter to allow the use of ordinary
|
||||
// function as TLSFingerprintProfile mutator.
|
||||
type TLSFingerprintProfileFunc func(context.Context, *ent.TLSFingerprintProfileMutation) (ent.Value, error)
|
||||
|
||||
@@ -16,6 +16,9 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
|
||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocode"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
|
||||
@@ -23,6 +26,7 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/redeemcode"
|
||||
"github.com/Wei-Shaw/sub2api/ent/securitysecret"
|
||||
"github.com/Wei-Shaw/sub2api/ent/setting"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
"github.com/Wei-Shaw/sub2api/ent/tlsfingerprintprofile"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagecleanuptask"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagelog"
|
||||
@@ -305,6 +309,88 @@ func (f TraverseIdempotencyRecord) Traverse(ctx context.Context, q ent.Query) er
|
||||
return fmt.Errorf("unexpected query type %T. expect *ent.IdempotencyRecordQuery", q)
|
||||
}
|
||||
|
||||
// The PaymentAuditLogFunc type is an adapter to allow the use of ordinary function as a Querier.
|
||||
type PaymentAuditLogFunc func(context.Context, *ent.PaymentAuditLogQuery) (ent.Value, error)
|
||||
|
||||
// Query calls f(ctx, q).
|
||||
func (f PaymentAuditLogFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
|
||||
if q, ok := q.(*ent.PaymentAuditLogQuery); ok {
|
||||
return f(ctx, q)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected query type %T. expect *ent.PaymentAuditLogQuery", q)
|
||||
}
|
||||
|
||||
// The TraversePaymentAuditLog type is an adapter to allow the use of ordinary function as Traverser.
|
||||
type TraversePaymentAuditLog func(context.Context, *ent.PaymentAuditLogQuery) error
|
||||
|
||||
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
|
||||
func (f TraversePaymentAuditLog) Intercept(next ent.Querier) ent.Querier {
|
||||
return next
|
||||
}
|
||||
|
||||
// Traverse calls f(ctx, q).
|
||||
func (f TraversePaymentAuditLog) Traverse(ctx context.Context, q ent.Query) error {
|
||||
if q, ok := q.(*ent.PaymentAuditLogQuery); ok {
|
||||
return f(ctx, q)
|
||||
}
|
||||
return fmt.Errorf("unexpected query type %T. expect *ent.PaymentAuditLogQuery", q)
|
||||
}
|
||||
|
||||
|
||||
// The PaymentOrderFunc type is an adapter to allow the use of ordinary function as a Querier.
|
||||
type PaymentOrderFunc func(context.Context, *ent.PaymentOrderQuery) (ent.Value, error)
|
||||
|
||||
// Query calls f(ctx, q).
|
||||
func (f PaymentOrderFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
|
||||
if q, ok := q.(*ent.PaymentOrderQuery); ok {
|
||||
return f(ctx, q)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected query type %T. expect *ent.PaymentOrderQuery", q)
|
||||
}
|
||||
|
||||
// The TraversePaymentOrder type is an adapter to allow the use of ordinary function as Traverser.
|
||||
type TraversePaymentOrder func(context.Context, *ent.PaymentOrderQuery) error
|
||||
|
||||
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
|
||||
func (f TraversePaymentOrder) Intercept(next ent.Querier) ent.Querier {
|
||||
return next
|
||||
}
|
||||
|
||||
// Traverse calls f(ctx, q).
|
||||
func (f TraversePaymentOrder) Traverse(ctx context.Context, q ent.Query) error {
|
||||
if q, ok := q.(*ent.PaymentOrderQuery); ok {
|
||||
return f(ctx, q)
|
||||
}
|
||||
return fmt.Errorf("unexpected query type %T. expect *ent.PaymentOrderQuery", q)
|
||||
}
|
||||
|
||||
// The PaymentProviderInstanceFunc type is an adapter to allow the use of ordinary function as a Querier.
|
||||
type PaymentProviderInstanceFunc func(context.Context, *ent.PaymentProviderInstanceQuery) (ent.Value, error)
|
||||
|
||||
// Query calls f(ctx, q).
|
||||
func (f PaymentProviderInstanceFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
|
||||
if q, ok := q.(*ent.PaymentProviderInstanceQuery); ok {
|
||||
return f(ctx, q)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected query type %T. expect *ent.PaymentProviderInstanceQuery", q)
|
||||
}
|
||||
|
||||
// The TraversePaymentProviderInstance type is an adapter to allow the use of ordinary function as Traverser.
|
||||
type TraversePaymentProviderInstance func(context.Context, *ent.PaymentProviderInstanceQuery) error
|
||||
|
||||
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
|
||||
func (f TraversePaymentProviderInstance) Intercept(next ent.Querier) ent.Querier {
|
||||
return next
|
||||
}
|
||||
|
||||
// Traverse calls f(ctx, q).
|
||||
func (f TraversePaymentProviderInstance) Traverse(ctx context.Context, q ent.Query) error {
|
||||
if q, ok := q.(*ent.PaymentProviderInstanceQuery); ok {
|
||||
return f(ctx, q)
|
||||
}
|
||||
return fmt.Errorf("unexpected query type %T. expect *ent.PaymentProviderInstanceQuery", q)
|
||||
}
|
||||
|
||||
// The PromoCodeFunc type is an adapter to allow the use of ordinary function as a Querier.
|
||||
type PromoCodeFunc func(context.Context, *ent.PromoCodeQuery) (ent.Value, error)
|
||||
|
||||
@@ -467,6 +553,33 @@ func (f TraverseSetting) Traverse(ctx context.Context, q ent.Query) error {
|
||||
return fmt.Errorf("unexpected query type %T. expect *ent.SettingQuery", q)
|
||||
}
|
||||
|
||||
// The SubscriptionPlanFunc type is an adapter to allow the use of ordinary function as a Querier.
|
||||
type SubscriptionPlanFunc func(context.Context, *ent.SubscriptionPlanQuery) (ent.Value, error)
|
||||
|
||||
// Query calls f(ctx, q).
|
||||
func (f SubscriptionPlanFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
|
||||
if q, ok := q.(*ent.SubscriptionPlanQuery); ok {
|
||||
return f(ctx, q)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected query type %T. expect *ent.SubscriptionPlanQuery", q)
|
||||
}
|
||||
|
||||
// The TraverseSubscriptionPlan type is an adapter to allow the use of ordinary function as Traverser.
|
||||
type TraverseSubscriptionPlan func(context.Context, *ent.SubscriptionPlanQuery) error
|
||||
|
||||
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
|
||||
func (f TraverseSubscriptionPlan) Intercept(next ent.Querier) ent.Querier {
|
||||
return next
|
||||
}
|
||||
|
||||
// Traverse calls f(ctx, q).
|
||||
func (f TraverseSubscriptionPlan) Traverse(ctx context.Context, q ent.Query) error {
|
||||
if q, ok := q.(*ent.SubscriptionPlanQuery); ok {
|
||||
return f(ctx, q)
|
||||
}
|
||||
return fmt.Errorf("unexpected query type %T. expect *ent.SubscriptionPlanQuery", q)
|
||||
}
|
||||
|
||||
// The TLSFingerprintProfileFunc type is an adapter to allow the use of ordinary function as a Querier.
|
||||
type TLSFingerprintProfileFunc func(context.Context, *ent.TLSFingerprintProfileQuery) (ent.Value, error)
|
||||
|
||||
@@ -702,6 +815,12 @@ func NewQuery(q ent.Query) (Query, error) {
|
||||
return &query[*ent.GroupQuery, predicate.Group, group.OrderOption]{typ: ent.TypeGroup, tq: q}, nil
|
||||
case *ent.IdempotencyRecordQuery:
|
||||
return &query[*ent.IdempotencyRecordQuery, predicate.IdempotencyRecord, idempotencyrecord.OrderOption]{typ: ent.TypeIdempotencyRecord, tq: q}, nil
|
||||
case *ent.PaymentAuditLogQuery:
|
||||
return &query[*ent.PaymentAuditLogQuery, predicate.PaymentAuditLog, paymentauditlog.OrderOption]{typ: ent.TypePaymentAuditLog, tq: q}, nil
|
||||
case *ent.PaymentOrderQuery:
|
||||
return &query[*ent.PaymentOrderQuery, predicate.PaymentOrder, paymentorder.OrderOption]{typ: ent.TypePaymentOrder, tq: q}, nil
|
||||
case *ent.PaymentProviderInstanceQuery:
|
||||
return &query[*ent.PaymentProviderInstanceQuery, predicate.PaymentProviderInstance, paymentproviderinstance.OrderOption]{typ: ent.TypePaymentProviderInstance, tq: q}, nil
|
||||
case *ent.PromoCodeQuery:
|
||||
return &query[*ent.PromoCodeQuery, predicate.PromoCode, promocode.OrderOption]{typ: ent.TypePromoCode, tq: q}, nil
|
||||
case *ent.PromoCodeUsageQuery:
|
||||
@@ -714,6 +833,8 @@ func NewQuery(q ent.Query) (Query, error) {
|
||||
return &query[*ent.SecuritySecretQuery, predicate.SecuritySecret, securitysecret.OrderOption]{typ: ent.TypeSecuritySecret, tq: q}, nil
|
||||
case *ent.SettingQuery:
|
||||
return &query[*ent.SettingQuery, predicate.Setting, setting.OrderOption]{typ: ent.TypeSetting, tq: q}, nil
|
||||
case *ent.SubscriptionPlanQuery:
|
||||
return &query[*ent.SubscriptionPlanQuery, predicate.SubscriptionPlan, subscriptionplan.OrderOption]{typ: ent.TypeSubscriptionPlan, tq: q}, nil
|
||||
case *ent.TLSFingerprintProfileQuery:
|
||||
return &query[*ent.TLSFingerprintProfileQuery, predicate.TLSFingerprintProfile, tlsfingerprintprofile.OrderOption]{typ: ent.TypeTLSFingerprintProfile, tq: q}, nil
|
||||
case *ent.UsageCleanupTaskQuery:
|
||||
|
||||
@@ -484,6 +484,151 @@ var (
|
||||
},
|
||||
},
|
||||
}
|
||||
// PaymentAuditLogsColumns holds the columns for the "payment_audit_logs" table.
|
||||
PaymentAuditLogsColumns = []*schema.Column{
|
||||
{Name: "id", Type: field.TypeInt64, Increment: true},
|
||||
{Name: "order_id", Type: field.TypeString, Size: 64},
|
||||
{Name: "action", Type: field.TypeString, Size: 50},
|
||||
{Name: "detail", Type: field.TypeString, Default: "", SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "operator", Type: field.TypeString, Size: 100, Default: "system"},
|
||||
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
}
|
||||
// PaymentAuditLogsTable holds the schema information for the "payment_audit_logs" table.
|
||||
PaymentAuditLogsTable = &schema.Table{
|
||||
Name: "payment_audit_logs",
|
||||
Columns: PaymentAuditLogsColumns,
|
||||
PrimaryKey: []*schema.Column{PaymentAuditLogsColumns[0]},
|
||||
Indexes: []*schema.Index{
|
||||
{
|
||||
Name: "paymentauditlog_order_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentAuditLogsColumns[1]},
|
||||
},
|
||||
},
|
||||
}
|
||||
// PaymentOrdersColumns holds the columns for the "payment_orders" table.
|
||||
PaymentOrdersColumns = []*schema.Column{
|
||||
{Name: "id", Type: field.TypeInt64, Increment: true},
|
||||
{Name: "user_email", Type: field.TypeString, Size: 255},
|
||||
{Name: "user_name", Type: field.TypeString, Size: 100},
|
||||
{Name: "user_notes", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "amount", Type: field.TypeFloat64, SchemaType: map[string]string{"postgres": "decimal(20,2)"}},
|
||||
{Name: "pay_amount", Type: field.TypeFloat64, SchemaType: map[string]string{"postgres": "decimal(20,2)"}},
|
||||
{Name: "fee_rate", Type: field.TypeFloat64, Default: 0, SchemaType: map[string]string{"postgres": "decimal(10,4)"}},
|
||||
{Name: "recharge_code", Type: field.TypeString, Size: 64},
|
||||
{Name: "payment_type", Type: field.TypeString, Size: 30},
|
||||
{Name: "payment_trade_no", Type: field.TypeString, Size: 128},
|
||||
{Name: "pay_url", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "qr_code", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "qr_code_img", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "order_type", Type: field.TypeString, Size: 20, Default: "balance"},
|
||||
{Name: "plan_id", Type: field.TypeInt64, Nullable: true},
|
||||
{Name: "subscription_group_id", Type: field.TypeInt64, Nullable: true},
|
||||
{Name: "subscription_days", Type: field.TypeInt, Nullable: true},
|
||||
{Name: "provider_instance_id", Type: field.TypeString, Nullable: true, Size: 64},
|
||||
{Name: "status", Type: field.TypeString, Size: 30, Default: "PENDING"},
|
||||
{Name: "refund_amount", Type: field.TypeFloat64, Default: 0, SchemaType: map[string]string{"postgres": "decimal(20,2)"}},
|
||||
{Name: "refund_reason", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "refund_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "force_refund", Type: field.TypeBool, Default: false},
|
||||
{Name: "refund_requested_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "refund_request_reason", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "refund_requested_by", Type: field.TypeString, Nullable: true, Size: 20},
|
||||
{Name: "expires_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "paid_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "completed_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "failed_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "failed_reason", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "client_ip", Type: field.TypeString, Size: 50},
|
||||
{Name: "src_host", Type: field.TypeString, Size: 255},
|
||||
{Name: "src_url", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "user_id", Type: field.TypeInt64},
|
||||
}
|
||||
// PaymentOrdersTable holds the schema information for the "payment_orders" table.
|
||||
PaymentOrdersTable = &schema.Table{
|
||||
Name: "payment_orders",
|
||||
Columns: PaymentOrdersColumns,
|
||||
PrimaryKey: []*schema.Column{PaymentOrdersColumns[0]},
|
||||
ForeignKeys: []*schema.ForeignKey{
|
||||
{
|
||||
Symbol: "payment_orders_users_payment_orders",
|
||||
Columns: []*schema.Column{PaymentOrdersColumns[36]},
|
||||
RefColumns: []*schema.Column{UsersColumns[0]},
|
||||
OnDelete: schema.NoAction,
|
||||
},
|
||||
},
|
||||
Indexes: []*schema.Index{
|
||||
{
|
||||
Name: "paymentorder_user_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentOrdersColumns[36]},
|
||||
},
|
||||
{
|
||||
Name: "paymentorder_status",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentOrdersColumns[18]},
|
||||
},
|
||||
{
|
||||
Name: "paymentorder_expires_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentOrdersColumns[26]},
|
||||
},
|
||||
{
|
||||
Name: "paymentorder_created_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentOrdersColumns[34]},
|
||||
},
|
||||
{
|
||||
Name: "paymentorder_paid_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentOrdersColumns[27]},
|
||||
},
|
||||
{
|
||||
Name: "paymentorder_payment_type_paid_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentOrdersColumns[8], PaymentOrdersColumns[27]},
|
||||
},
|
||||
{
|
||||
Name: "paymentorder_order_type",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentOrdersColumns[13]},
|
||||
},
|
||||
},
|
||||
}
|
||||
// PaymentProviderInstancesColumns holds the columns for the "payment_provider_instances" table.
|
||||
PaymentProviderInstancesColumns = []*schema.Column{
|
||||
{Name: "id", Type: field.TypeInt64, Increment: true},
|
||||
{Name: "provider_key", Type: field.TypeString, Size: 30},
|
||||
{Name: "name", Type: field.TypeString, Size: 100, Default: ""},
|
||||
{Name: "config", Type: field.TypeString, SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "supported_types", Type: field.TypeString, Size: 200, Default: ""},
|
||||
{Name: "enabled", Type: field.TypeBool, Default: true},
|
||||
{Name: "sort_order", Type: field.TypeInt, Default: 0},
|
||||
{Name: "limits", Type: field.TypeString, Default: "", SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "refund_enabled", Type: field.TypeBool, Default: false},
|
||||
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
}
|
||||
// PaymentProviderInstancesTable holds the schema information for the "payment_provider_instances" table.
|
||||
PaymentProviderInstancesTable = &schema.Table{
|
||||
Name: "payment_provider_instances",
|
||||
Columns: PaymentProviderInstancesColumns,
|
||||
PrimaryKey: []*schema.Column{PaymentProviderInstancesColumns[0]},
|
||||
Indexes: []*schema.Index{
|
||||
{
|
||||
Name: "paymentproviderinstance_provider_key",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentProviderInstancesColumns[1]},
|
||||
},
|
||||
{
|
||||
Name: "paymentproviderinstance_enabled",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{PaymentProviderInstancesColumns[5]},
|
||||
},
|
||||
},
|
||||
}
|
||||
// PromoCodesColumns holds the columns for the "promo_codes" table.
|
||||
PromoCodesColumns = []*schema.Column{
|
||||
{Name: "id", Type: field.TypeInt64, Increment: true},
|
||||
@@ -670,6 +815,41 @@ var (
|
||||
Columns: SettingsColumns,
|
||||
PrimaryKey: []*schema.Column{SettingsColumns[0]},
|
||||
}
|
||||
// SubscriptionPlansColumns holds the columns for the "subscription_plans" table.
|
||||
SubscriptionPlansColumns = []*schema.Column{
|
||||
{Name: "id", Type: field.TypeInt64, Increment: true},
|
||||
{Name: "group_id", Type: field.TypeInt64},
|
||||
{Name: "name", Type: field.TypeString, Size: 100},
|
||||
{Name: "description", Type: field.TypeString, Default: "", SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "price", Type: field.TypeFloat64, SchemaType: map[string]string{"postgres": "decimal(20,2)"}},
|
||||
{Name: "original_price", Type: field.TypeFloat64, Nullable: true, SchemaType: map[string]string{"postgres": "decimal(20,2)"}},
|
||||
{Name: "validity_days", Type: field.TypeInt, Default: 30},
|
||||
{Name: "validity_unit", Type: field.TypeString, Size: 10, Default: "day"},
|
||||
{Name: "features", Type: field.TypeString, Default: "", SchemaType: map[string]string{"postgres": "text"}},
|
||||
{Name: "product_name", Type: field.TypeString, Size: 100, Default: ""},
|
||||
{Name: "for_sale", Type: field.TypeBool, Default: true},
|
||||
{Name: "sort_order", Type: field.TypeInt, Default: 0},
|
||||
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
{Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
|
||||
}
|
||||
// SubscriptionPlansTable holds the schema information for the "subscription_plans" table.
|
||||
SubscriptionPlansTable = &schema.Table{
|
||||
Name: "subscription_plans",
|
||||
Columns: SubscriptionPlansColumns,
|
||||
PrimaryKey: []*schema.Column{SubscriptionPlansColumns[0]},
|
||||
Indexes: []*schema.Index{
|
||||
{
|
||||
Name: "subscriptionplan_group_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{SubscriptionPlansColumns[1]},
|
||||
},
|
||||
{
|
||||
Name: "subscriptionplan_for_sale",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{SubscriptionPlansColumns[10]},
|
||||
},
|
||||
},
|
||||
}
|
||||
// TLSFingerprintProfilesColumns holds the columns for the "tls_fingerprint_profiles" table.
|
||||
TLSFingerprintProfilesColumns = []*schema.Column{
|
||||
{Name: "id", Type: field.TypeInt64, Increment: true},
|
||||
@@ -1127,12 +1307,16 @@ var (
|
||||
ErrorPassthroughRulesTable,
|
||||
GroupsTable,
|
||||
IdempotencyRecordsTable,
|
||||
PaymentAuditLogsTable,
|
||||
PaymentOrdersTable,
|
||||
PaymentProviderInstancesTable,
|
||||
PromoCodesTable,
|
||||
PromoCodeUsagesTable,
|
||||
ProxiesTable,
|
||||
RedeemCodesTable,
|
||||
SecuritySecretsTable,
|
||||
SettingsTable,
|
||||
SubscriptionPlansTable,
|
||||
TLSFingerprintProfilesTable,
|
||||
UsageCleanupTasksTable,
|
||||
UsageLogsTable,
|
||||
@@ -1176,6 +1360,16 @@ func init() {
|
||||
IdempotencyRecordsTable.Annotation = &entsql.Annotation{
|
||||
Table: "idempotency_records",
|
||||
}
|
||||
PaymentAuditLogsTable.Annotation = &entsql.Annotation{
|
||||
Table: "payment_audit_logs",
|
||||
}
|
||||
PaymentOrdersTable.ForeignKeys[0].RefTable = UsersTable
|
||||
PaymentOrdersTable.Annotation = &entsql.Annotation{
|
||||
Table: "payment_orders",
|
||||
}
|
||||
PaymentProviderInstancesTable.Annotation = &entsql.Annotation{
|
||||
Table: "payment_provider_instances",
|
||||
}
|
||||
PromoCodesTable.Annotation = &entsql.Annotation{
|
||||
Table: "promo_codes",
|
||||
}
|
||||
@@ -1198,6 +1392,9 @@ func init() {
|
||||
SettingsTable.Annotation = &entsql.Annotation{
|
||||
Table: "settings",
|
||||
}
|
||||
SubscriptionPlansTable.Annotation = &entsql.Annotation{
|
||||
Table: "subscription_plans",
|
||||
}
|
||||
TLSFingerprintProfilesTable.Annotation = &entsql.Annotation{
|
||||
Table: "tls_fingerprint_profiles",
|
||||
}
|
||||
|
||||
+5501
-3
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,150 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
)
|
||||
|
||||
// PaymentAuditLog is the model entity for the PaymentAuditLog schema.
|
||||
type PaymentAuditLog struct {
|
||||
config `json:"-"`
|
||||
// ID of the ent.
|
||||
ID int64 `json:"id,omitempty"`
|
||||
// OrderID holds the value of the "order_id" field.
|
||||
OrderID string `json:"order_id,omitempty"`
|
||||
// Action holds the value of the "action" field.
|
||||
Action string `json:"action,omitempty"`
|
||||
// Detail holds the value of the "detail" field.
|
||||
Detail string `json:"detail,omitempty"`
|
||||
// Operator holds the value of the "operator" field.
|
||||
Operator string `json:"operator,omitempty"`
|
||||
// CreatedAt holds the value of the "created_at" field.
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
selectValues sql.SelectValues
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*PaymentAuditLog) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case paymentauditlog.FieldID:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case paymentauditlog.FieldOrderID, paymentauditlog.FieldAction, paymentauditlog.FieldDetail, paymentauditlog.FieldOperator:
|
||||
values[i] = new(sql.NullString)
|
||||
case paymentauditlog.FieldCreatedAt:
|
||||
values[i] = new(sql.NullTime)
|
||||
default:
|
||||
values[i] = new(sql.UnknownType)
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the PaymentAuditLog fields.
|
||||
func (_m *PaymentAuditLog) assignValues(columns []string, values []any) error {
|
||||
if m, n := len(values), len(columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case paymentauditlog.FieldID:
|
||||
value, ok := values[i].(*sql.NullInt64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field id", value)
|
||||
}
|
||||
_m.ID = int64(value.Int64)
|
||||
case paymentauditlog.FieldOrderID:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field order_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.OrderID = value.String
|
||||
}
|
||||
case paymentauditlog.FieldAction:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field action", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Action = value.String
|
||||
}
|
||||
case paymentauditlog.FieldDetail:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field detail", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Detail = value.String
|
||||
}
|
||||
case paymentauditlog.FieldOperator:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field operator", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Operator = value.String
|
||||
}
|
||||
case paymentauditlog.FieldCreatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.CreatedAt = value.Time
|
||||
}
|
||||
default:
|
||||
_m.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns the ent.Value that was dynamically selected and assigned to the PaymentAuditLog.
|
||||
// This includes values selected through modifiers, order, etc.
|
||||
func (_m *PaymentAuditLog) Value(name string) (ent.Value, error) {
|
||||
return _m.selectValues.Get(name)
|
||||
}
|
||||
|
||||
// Update returns a builder for updating this PaymentAuditLog.
|
||||
// Note that you need to call PaymentAuditLog.Unwrap() before calling this method if this PaymentAuditLog
|
||||
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||
func (_m *PaymentAuditLog) Update() *PaymentAuditLogUpdateOne {
|
||||
return NewPaymentAuditLogClient(_m.config).UpdateOne(_m)
|
||||
}
|
||||
|
||||
// Unwrap unwraps the PaymentAuditLog entity that was returned from a transaction after it was closed,
|
||||
// so that all future queries will be executed through the driver which created the transaction.
|
||||
func (_m *PaymentAuditLog) Unwrap() *PaymentAuditLog {
|
||||
_tx, ok := _m.config.driver.(*txDriver)
|
||||
if !ok {
|
||||
panic("ent: PaymentAuditLog is not a transactional entity")
|
||||
}
|
||||
_m.config.driver = _tx.drv
|
||||
return _m
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer.
|
||||
func (_m *PaymentAuditLog) String() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("PaymentAuditLog(")
|
||||
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
|
||||
builder.WriteString("order_id=")
|
||||
builder.WriteString(_m.OrderID)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("action=")
|
||||
builder.WriteString(_m.Action)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("detail=")
|
||||
builder.WriteString(_m.Detail)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("operator=")
|
||||
builder.WriteString(_m.Operator)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("created_at=")
|
||||
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// PaymentAuditLogs is a parsable slice of PaymentAuditLog.
|
||||
type PaymentAuditLogs []*PaymentAuditLog
|
||||
@@ -0,0 +1,96 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package paymentauditlog
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
)
|
||||
|
||||
const (
|
||||
// Label holds the string label denoting the paymentauditlog type in the database.
|
||||
Label = "payment_audit_log"
|
||||
// FieldID holds the string denoting the id field in the database.
|
||||
FieldID = "id"
|
||||
// FieldOrderID holds the string denoting the order_id field in the database.
|
||||
FieldOrderID = "order_id"
|
||||
// FieldAction holds the string denoting the action field in the database.
|
||||
FieldAction = "action"
|
||||
// FieldDetail holds the string denoting the detail field in the database.
|
||||
FieldDetail = "detail"
|
||||
// FieldOperator holds the string denoting the operator field in the database.
|
||||
FieldOperator = "operator"
|
||||
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
||||
FieldCreatedAt = "created_at"
|
||||
// Table holds the table name of the paymentauditlog in the database.
|
||||
Table = "payment_audit_logs"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns for paymentauditlog fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldOrderID,
|
||||
FieldAction,
|
||||
FieldDetail,
|
||||
FieldOperator,
|
||||
FieldCreatedAt,
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
func ValidColumn(column string) bool {
|
||||
for i := range Columns {
|
||||
if column == Columns[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
// OrderIDValidator is a validator for the "order_id" field. It is called by the builders before save.
|
||||
OrderIDValidator func(string) error
|
||||
// ActionValidator is a validator for the "action" field. It is called by the builders before save.
|
||||
ActionValidator func(string) error
|
||||
// DefaultDetail holds the default value on creation for the "detail" field.
|
||||
DefaultDetail string
|
||||
// DefaultOperator holds the default value on creation for the "operator" field.
|
||||
DefaultOperator string
|
||||
// OperatorValidator is a validator for the "operator" field. It is called by the builders before save.
|
||||
OperatorValidator func(string) error
|
||||
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
||||
DefaultCreatedAt func() time.Time
|
||||
)
|
||||
|
||||
// OrderOption defines the ordering options for the PaymentAuditLog queries.
|
||||
type OrderOption func(*sql.Selector)
|
||||
|
||||
// ByID orders the results by the id field.
|
||||
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByOrderID orders the results by the order_id field.
|
||||
func ByOrderID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldOrderID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByAction orders the results by the action field.
|
||||
func ByAction(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldAction, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByDetail orders the results by the detail field.
|
||||
func ByDetail(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldDetail, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByOperator orders the results by the operator field.
|
||||
func ByOperator(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldOperator, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCreatedAt orders the results by the created_at field.
|
||||
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package paymentauditlog
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// ID filters vertices based on their ID field.
|
||||
func ID(id int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDEQ applies the EQ predicate on the ID field.
|
||||
func IDEQ(id int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDNEQ applies the NEQ predicate on the ID field.
|
||||
func IDNEQ(id int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDIn applies the In predicate on the ID field.
|
||||
func IDIn(ids ...int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDNotIn applies the NotIn predicate on the ID field.
|
||||
func IDNotIn(ids ...int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNotIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDGT applies the GT predicate on the ID field.
|
||||
func IDGT(id int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDGTE applies the GTE predicate on the ID field.
|
||||
func IDGTE(id int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGTE(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLT applies the LT predicate on the ID field.
|
||||
func IDLT(id int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLTE applies the LTE predicate on the ID field.
|
||||
func IDLTE(id int64) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLTE(FieldID, id))
|
||||
}
|
||||
|
||||
// OrderID applies equality check predicate on the "order_id" field. It's identical to OrderIDEQ.
|
||||
func OrderID(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// Action applies equality check predicate on the "action" field. It's identical to ActionEQ.
|
||||
func Action(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldAction, v))
|
||||
}
|
||||
|
||||
// Detail applies equality check predicate on the "detail" field. It's identical to DetailEQ.
|
||||
func Detail(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldDetail, v))
|
||||
}
|
||||
|
||||
// Operator applies equality check predicate on the "operator" field. It's identical to OperatorEQ.
|
||||
func Operator(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldOperator, v))
|
||||
}
|
||||
|
||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||
func CreatedAt(v time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// OrderIDEQ applies the EQ predicate on the "order_id" field.
|
||||
func OrderIDEQ(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDNEQ applies the NEQ predicate on the "order_id" field.
|
||||
func OrderIDNEQ(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNEQ(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDIn applies the In predicate on the "order_id" field.
|
||||
func OrderIDIn(vs ...string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldIn(FieldOrderID, vs...))
|
||||
}
|
||||
|
||||
// OrderIDNotIn applies the NotIn predicate on the "order_id" field.
|
||||
func OrderIDNotIn(vs ...string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNotIn(FieldOrderID, vs...))
|
||||
}
|
||||
|
||||
// OrderIDGT applies the GT predicate on the "order_id" field.
|
||||
func OrderIDGT(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGT(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDGTE applies the GTE predicate on the "order_id" field.
|
||||
func OrderIDGTE(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGTE(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDLT applies the LT predicate on the "order_id" field.
|
||||
func OrderIDLT(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLT(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDLTE applies the LTE predicate on the "order_id" field.
|
||||
func OrderIDLTE(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLTE(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDContains applies the Contains predicate on the "order_id" field.
|
||||
func OrderIDContains(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldContains(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDHasPrefix applies the HasPrefix predicate on the "order_id" field.
|
||||
func OrderIDHasPrefix(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldHasPrefix(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDHasSuffix applies the HasSuffix predicate on the "order_id" field.
|
||||
func OrderIDHasSuffix(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldHasSuffix(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDEqualFold applies the EqualFold predicate on the "order_id" field.
|
||||
func OrderIDEqualFold(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEqualFold(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// OrderIDContainsFold applies the ContainsFold predicate on the "order_id" field.
|
||||
func OrderIDContainsFold(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldContainsFold(FieldOrderID, v))
|
||||
}
|
||||
|
||||
// ActionEQ applies the EQ predicate on the "action" field.
|
||||
func ActionEQ(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionNEQ applies the NEQ predicate on the "action" field.
|
||||
func ActionNEQ(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNEQ(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionIn applies the In predicate on the "action" field.
|
||||
func ActionIn(vs ...string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldIn(FieldAction, vs...))
|
||||
}
|
||||
|
||||
// ActionNotIn applies the NotIn predicate on the "action" field.
|
||||
func ActionNotIn(vs ...string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNotIn(FieldAction, vs...))
|
||||
}
|
||||
|
||||
// ActionGT applies the GT predicate on the "action" field.
|
||||
func ActionGT(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGT(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionGTE applies the GTE predicate on the "action" field.
|
||||
func ActionGTE(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGTE(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionLT applies the LT predicate on the "action" field.
|
||||
func ActionLT(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLT(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionLTE applies the LTE predicate on the "action" field.
|
||||
func ActionLTE(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLTE(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionContains applies the Contains predicate on the "action" field.
|
||||
func ActionContains(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldContains(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionHasPrefix applies the HasPrefix predicate on the "action" field.
|
||||
func ActionHasPrefix(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldHasPrefix(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionHasSuffix applies the HasSuffix predicate on the "action" field.
|
||||
func ActionHasSuffix(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldHasSuffix(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionEqualFold applies the EqualFold predicate on the "action" field.
|
||||
func ActionEqualFold(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEqualFold(FieldAction, v))
|
||||
}
|
||||
|
||||
// ActionContainsFold applies the ContainsFold predicate on the "action" field.
|
||||
func ActionContainsFold(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldContainsFold(FieldAction, v))
|
||||
}
|
||||
|
||||
// DetailEQ applies the EQ predicate on the "detail" field.
|
||||
func DetailEQ(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailNEQ applies the NEQ predicate on the "detail" field.
|
||||
func DetailNEQ(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNEQ(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailIn applies the In predicate on the "detail" field.
|
||||
func DetailIn(vs ...string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldIn(FieldDetail, vs...))
|
||||
}
|
||||
|
||||
// DetailNotIn applies the NotIn predicate on the "detail" field.
|
||||
func DetailNotIn(vs ...string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNotIn(FieldDetail, vs...))
|
||||
}
|
||||
|
||||
// DetailGT applies the GT predicate on the "detail" field.
|
||||
func DetailGT(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGT(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailGTE applies the GTE predicate on the "detail" field.
|
||||
func DetailGTE(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGTE(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailLT applies the LT predicate on the "detail" field.
|
||||
func DetailLT(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLT(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailLTE applies the LTE predicate on the "detail" field.
|
||||
func DetailLTE(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLTE(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailContains applies the Contains predicate on the "detail" field.
|
||||
func DetailContains(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldContains(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailHasPrefix applies the HasPrefix predicate on the "detail" field.
|
||||
func DetailHasPrefix(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldHasPrefix(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailHasSuffix applies the HasSuffix predicate on the "detail" field.
|
||||
func DetailHasSuffix(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldHasSuffix(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailEqualFold applies the EqualFold predicate on the "detail" field.
|
||||
func DetailEqualFold(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEqualFold(FieldDetail, v))
|
||||
}
|
||||
|
||||
// DetailContainsFold applies the ContainsFold predicate on the "detail" field.
|
||||
func DetailContainsFold(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldContainsFold(FieldDetail, v))
|
||||
}
|
||||
|
||||
// OperatorEQ applies the EQ predicate on the "operator" field.
|
||||
func OperatorEQ(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorNEQ applies the NEQ predicate on the "operator" field.
|
||||
func OperatorNEQ(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNEQ(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorIn applies the In predicate on the "operator" field.
|
||||
func OperatorIn(vs ...string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldIn(FieldOperator, vs...))
|
||||
}
|
||||
|
||||
// OperatorNotIn applies the NotIn predicate on the "operator" field.
|
||||
func OperatorNotIn(vs ...string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNotIn(FieldOperator, vs...))
|
||||
}
|
||||
|
||||
// OperatorGT applies the GT predicate on the "operator" field.
|
||||
func OperatorGT(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGT(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorGTE applies the GTE predicate on the "operator" field.
|
||||
func OperatorGTE(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGTE(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorLT applies the LT predicate on the "operator" field.
|
||||
func OperatorLT(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLT(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorLTE applies the LTE predicate on the "operator" field.
|
||||
func OperatorLTE(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLTE(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorContains applies the Contains predicate on the "operator" field.
|
||||
func OperatorContains(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldContains(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorHasPrefix applies the HasPrefix predicate on the "operator" field.
|
||||
func OperatorHasPrefix(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldHasPrefix(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorHasSuffix applies the HasSuffix predicate on the "operator" field.
|
||||
func OperatorHasSuffix(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldHasSuffix(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorEqualFold applies the EqualFold predicate on the "operator" field.
|
||||
func OperatorEqualFold(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEqualFold(FieldOperator, v))
|
||||
}
|
||||
|
||||
// OperatorContainsFold applies the ContainsFold predicate on the "operator" field.
|
||||
func OperatorContainsFold(v string) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldContainsFold(FieldOperator, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||
func CreatedAtNEQ(v time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||
func CreatedAtIn(vs ...time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||
func CreatedAtNotIn(vs ...time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||
func CreatedAtGT(v time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||
func CreatedAtGTE(v time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldGTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||
func CreatedAtLT(v time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||
func CreatedAtLTE(v time.Time) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.FieldLTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// And groups predicates with the AND operator between them.
|
||||
func And(predicates ...predicate.PaymentAuditLog) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.AndPredicates(predicates...))
|
||||
}
|
||||
|
||||
// Or groups predicates with the OR operator between them.
|
||||
func Or(predicates ...predicate.PaymentAuditLog) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.OrPredicates(predicates...))
|
||||
}
|
||||
|
||||
// Not applies the not operator on the given predicate.
|
||||
func Not(p predicate.PaymentAuditLog) predicate.PaymentAuditLog {
|
||||
return predicate.PaymentAuditLog(sql.NotPredicates(p))
|
||||
}
|
||||
@@ -0,0 +1,696 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
)
|
||||
|
||||
// PaymentAuditLogCreate is the builder for creating a PaymentAuditLog entity.
|
||||
type PaymentAuditLogCreate struct {
|
||||
config
|
||||
mutation *PaymentAuditLogMutation
|
||||
hooks []Hook
|
||||
conflict []sql.ConflictOption
|
||||
}
|
||||
|
||||
// SetOrderID sets the "order_id" field.
|
||||
func (_c *PaymentAuditLogCreate) SetOrderID(v string) *PaymentAuditLogCreate {
|
||||
_c.mutation.SetOrderID(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetAction sets the "action" field.
|
||||
func (_c *PaymentAuditLogCreate) SetAction(v string) *PaymentAuditLogCreate {
|
||||
_c.mutation.SetAction(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetDetail sets the "detail" field.
|
||||
func (_c *PaymentAuditLogCreate) SetDetail(v string) *PaymentAuditLogCreate {
|
||||
_c.mutation.SetDetail(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableDetail sets the "detail" field if the given value is not nil.
|
||||
func (_c *PaymentAuditLogCreate) SetNillableDetail(v *string) *PaymentAuditLogCreate {
|
||||
if v != nil {
|
||||
_c.SetDetail(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetOperator sets the "operator" field.
|
||||
func (_c *PaymentAuditLogCreate) SetOperator(v string) *PaymentAuditLogCreate {
|
||||
_c.mutation.SetOperator(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableOperator sets the "operator" field if the given value is not nil.
|
||||
func (_c *PaymentAuditLogCreate) SetNillableOperator(v *string) *PaymentAuditLogCreate {
|
||||
if v != nil {
|
||||
_c.SetOperator(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetCreatedAt sets the "created_at" field.
|
||||
func (_c *PaymentAuditLogCreate) SetCreatedAt(v time.Time) *PaymentAuditLogCreate {
|
||||
_c.mutation.SetCreatedAt(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
||||
func (_c *PaymentAuditLogCreate) SetNillableCreatedAt(v *time.Time) *PaymentAuditLogCreate {
|
||||
if v != nil {
|
||||
_c.SetCreatedAt(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// Mutation returns the PaymentAuditLogMutation object of the builder.
|
||||
func (_c *PaymentAuditLogCreate) Mutation() *PaymentAuditLogMutation {
|
||||
return _c.mutation
|
||||
}
|
||||
|
||||
// Save creates the PaymentAuditLog in the database.
|
||||
func (_c *PaymentAuditLogCreate) Save(ctx context.Context) (*PaymentAuditLog, error) {
|
||||
_c.defaults()
|
||||
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)
|
||||
}
|
||||
|
||||
// SaveX calls Save and panics if Save returns an error.
|
||||
func (_c *PaymentAuditLogCreate) SaveX(ctx context.Context) *PaymentAuditLog {
|
||||
v, err := _c.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (_c *PaymentAuditLogCreate) Exec(ctx context.Context) error {
|
||||
_, err := _c.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_c *PaymentAuditLogCreate) ExecX(ctx context.Context) {
|
||||
if err := _c.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// defaults sets the default values of the builder before save.
|
||||
func (_c *PaymentAuditLogCreate) defaults() {
|
||||
if _, ok := _c.mutation.Detail(); !ok {
|
||||
v := paymentauditlog.DefaultDetail
|
||||
_c.mutation.SetDetail(v)
|
||||
}
|
||||
if _, ok := _c.mutation.Operator(); !ok {
|
||||
v := paymentauditlog.DefaultOperator
|
||||
_c.mutation.SetOperator(v)
|
||||
}
|
||||
if _, ok := _c.mutation.CreatedAt(); !ok {
|
||||
v := paymentauditlog.DefaultCreatedAt()
|
||||
_c.mutation.SetCreatedAt(v)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (_c *PaymentAuditLogCreate) check() error {
|
||||
if _, ok := _c.mutation.OrderID(); !ok {
|
||||
return &ValidationError{Name: "order_id", err: errors.New(`ent: missing required field "PaymentAuditLog.order_id"`)}
|
||||
}
|
||||
if v, ok := _c.mutation.OrderID(); ok {
|
||||
if err := paymentauditlog.OrderIDValidator(v); err != nil {
|
||||
return &ValidationError{Name: "order_id", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.order_id": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _, ok := _c.mutation.Action(); !ok {
|
||||
return &ValidationError{Name: "action", err: errors.New(`ent: missing required field "PaymentAuditLog.action"`)}
|
||||
}
|
||||
if v, ok := _c.mutation.Action(); ok {
|
||||
if err := paymentauditlog.ActionValidator(v); err != nil {
|
||||
return &ValidationError{Name: "action", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.action": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _, ok := _c.mutation.Detail(); !ok {
|
||||
return &ValidationError{Name: "detail", err: errors.New(`ent: missing required field "PaymentAuditLog.detail"`)}
|
||||
}
|
||||
if _, ok := _c.mutation.Operator(); !ok {
|
||||
return &ValidationError{Name: "operator", err: errors.New(`ent: missing required field "PaymentAuditLog.operator"`)}
|
||||
}
|
||||
if v, ok := _c.mutation.Operator(); ok {
|
||||
if err := paymentauditlog.OperatorValidator(v); err != nil {
|
||||
return &ValidationError{Name: "operator", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.operator": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _, ok := _c.mutation.CreatedAt(); !ok {
|
||||
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "PaymentAuditLog.created_at"`)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_c *PaymentAuditLogCreate) sqlSave(ctx context.Context) (*PaymentAuditLog, error) {
|
||||
if err := _c.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_node, _spec := _c.createSpec()
|
||||
if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil {
|
||||
if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
id := _spec.ID.Value.(int64)
|
||||
_node.ID = int64(id)
|
||||
_c.mutation.id = &_node.ID
|
||||
_c.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
func (_c *PaymentAuditLogCreate) createSpec() (*PaymentAuditLog, *sqlgraph.CreateSpec) {
|
||||
var (
|
||||
_node = &PaymentAuditLog{config: _c.config}
|
||||
_spec = sqlgraph.NewCreateSpec(paymentauditlog.Table, sqlgraph.NewFieldSpec(paymentauditlog.FieldID, field.TypeInt64))
|
||||
)
|
||||
_spec.OnConflict = _c.conflict
|
||||
if value, ok := _c.mutation.OrderID(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldOrderID, field.TypeString, value)
|
||||
_node.OrderID = value
|
||||
}
|
||||
if value, ok := _c.mutation.Action(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldAction, field.TypeString, value)
|
||||
_node.Action = value
|
||||
}
|
||||
if value, ok := _c.mutation.Detail(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldDetail, field.TypeString, value)
|
||||
_node.Detail = value
|
||||
}
|
||||
if value, ok := _c.mutation.Operator(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldOperator, field.TypeString, value)
|
||||
_node.Operator = value
|
||||
}
|
||||
if value, ok := _c.mutation.CreatedAt(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldCreatedAt, field.TypeTime, value)
|
||||
_node.CreatedAt = value
|
||||
}
|
||||
return _node, _spec
|
||||
}
|
||||
|
||||
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
|
||||
// of the `INSERT` statement. For example:
|
||||
//
|
||||
// client.PaymentAuditLog.Create().
|
||||
// SetOrderID(v).
|
||||
// OnConflict(
|
||||
// // Update the row with the new values
|
||||
// // the was proposed for insertion.
|
||||
// sql.ResolveWithNewValues(),
|
||||
// ).
|
||||
// // Override some of the fields with custom
|
||||
// // update values.
|
||||
// Update(func(u *ent.PaymentAuditLogUpsert) {
|
||||
// SetOrderID(v+v).
|
||||
// }).
|
||||
// Exec(ctx)
|
||||
func (_c *PaymentAuditLogCreate) OnConflict(opts ...sql.ConflictOption) *PaymentAuditLogUpsertOne {
|
||||
_c.conflict = opts
|
||||
return &PaymentAuditLogUpsertOne{
|
||||
create: _c,
|
||||
}
|
||||
}
|
||||
|
||||
// OnConflictColumns calls `OnConflict` and configures the columns
|
||||
// as conflict target. Using this option is equivalent to using:
|
||||
//
|
||||
// client.PaymentAuditLog.Create().
|
||||
// OnConflict(sql.ConflictColumns(columns...)).
|
||||
// Exec(ctx)
|
||||
func (_c *PaymentAuditLogCreate) OnConflictColumns(columns ...string) *PaymentAuditLogUpsertOne {
|
||||
_c.conflict = append(_c.conflict, sql.ConflictColumns(columns...))
|
||||
return &PaymentAuditLogUpsertOne{
|
||||
create: _c,
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
// PaymentAuditLogUpsertOne is the builder for "upsert"-ing
|
||||
// one PaymentAuditLog node.
|
||||
PaymentAuditLogUpsertOne struct {
|
||||
create *PaymentAuditLogCreate
|
||||
}
|
||||
|
||||
// PaymentAuditLogUpsert is the "OnConflict" setter.
|
||||
PaymentAuditLogUpsert struct {
|
||||
*sql.UpdateSet
|
||||
}
|
||||
)
|
||||
|
||||
// SetOrderID sets the "order_id" field.
|
||||
func (u *PaymentAuditLogUpsert) SetOrderID(v string) *PaymentAuditLogUpsert {
|
||||
u.Set(paymentauditlog.FieldOrderID, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateOrderID sets the "order_id" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsert) UpdateOrderID() *PaymentAuditLogUpsert {
|
||||
u.SetExcluded(paymentauditlog.FieldOrderID)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetAction sets the "action" field.
|
||||
func (u *PaymentAuditLogUpsert) SetAction(v string) *PaymentAuditLogUpsert {
|
||||
u.Set(paymentauditlog.FieldAction, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateAction sets the "action" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsert) UpdateAction() *PaymentAuditLogUpsert {
|
||||
u.SetExcluded(paymentauditlog.FieldAction)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetDetail sets the "detail" field.
|
||||
func (u *PaymentAuditLogUpsert) SetDetail(v string) *PaymentAuditLogUpsert {
|
||||
u.Set(paymentauditlog.FieldDetail, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateDetail sets the "detail" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsert) UpdateDetail() *PaymentAuditLogUpsert {
|
||||
u.SetExcluded(paymentauditlog.FieldDetail)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetOperator sets the "operator" field.
|
||||
func (u *PaymentAuditLogUpsert) SetOperator(v string) *PaymentAuditLogUpsert {
|
||||
u.Set(paymentauditlog.FieldOperator, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateOperator sets the "operator" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsert) UpdateOperator() *PaymentAuditLogUpsert {
|
||||
u.SetExcluded(paymentauditlog.FieldOperator)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateNewValues updates the mutable fields using the new values that were set on create.
|
||||
// Using this option is equivalent to using:
|
||||
//
|
||||
// client.PaymentAuditLog.Create().
|
||||
// OnConflict(
|
||||
// sql.ResolveWithNewValues(),
|
||||
// ).
|
||||
// Exec(ctx)
|
||||
func (u *PaymentAuditLogUpsertOne) UpdateNewValues() *PaymentAuditLogUpsertOne {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
|
||||
if _, exists := u.create.mutation.CreatedAt(); exists {
|
||||
s.SetIgnore(paymentauditlog.FieldCreatedAt)
|
||||
}
|
||||
}))
|
||||
return u
|
||||
}
|
||||
|
||||
// Ignore sets each column to itself in case of conflict.
|
||||
// Using this option is equivalent to using:
|
||||
//
|
||||
// client.PaymentAuditLog.Create().
|
||||
// OnConflict(sql.ResolveWithIgnore()).
|
||||
// Exec(ctx)
|
||||
func (u *PaymentAuditLogUpsertOne) Ignore() *PaymentAuditLogUpsertOne {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
|
||||
return u
|
||||
}
|
||||
|
||||
// DoNothing configures the conflict_action to `DO NOTHING`.
|
||||
// Supported only by SQLite and PostgreSQL.
|
||||
func (u *PaymentAuditLogUpsertOne) DoNothing() *PaymentAuditLogUpsertOne {
|
||||
u.create.conflict = append(u.create.conflict, sql.DoNothing())
|
||||
return u
|
||||
}
|
||||
|
||||
// Update allows overriding fields `UPDATE` values. See the PaymentAuditLogCreate.OnConflict
|
||||
// documentation for more info.
|
||||
func (u *PaymentAuditLogUpsertOne) Update(set func(*PaymentAuditLogUpsert)) *PaymentAuditLogUpsertOne {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
|
||||
set(&PaymentAuditLogUpsert{UpdateSet: update})
|
||||
}))
|
||||
return u
|
||||
}
|
||||
|
||||
// SetOrderID sets the "order_id" field.
|
||||
func (u *PaymentAuditLogUpsertOne) SetOrderID(v string) *PaymentAuditLogUpsertOne {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.SetOrderID(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateOrderID sets the "order_id" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsertOne) UpdateOrderID() *PaymentAuditLogUpsertOne {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.UpdateOrderID()
|
||||
})
|
||||
}
|
||||
|
||||
// SetAction sets the "action" field.
|
||||
func (u *PaymentAuditLogUpsertOne) SetAction(v string) *PaymentAuditLogUpsertOne {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.SetAction(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateAction sets the "action" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsertOne) UpdateAction() *PaymentAuditLogUpsertOne {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.UpdateAction()
|
||||
})
|
||||
}
|
||||
|
||||
// SetDetail sets the "detail" field.
|
||||
func (u *PaymentAuditLogUpsertOne) SetDetail(v string) *PaymentAuditLogUpsertOne {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.SetDetail(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateDetail sets the "detail" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsertOne) UpdateDetail() *PaymentAuditLogUpsertOne {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.UpdateDetail()
|
||||
})
|
||||
}
|
||||
|
||||
// SetOperator sets the "operator" field.
|
||||
func (u *PaymentAuditLogUpsertOne) SetOperator(v string) *PaymentAuditLogUpsertOne {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.SetOperator(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateOperator sets the "operator" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsertOne) UpdateOperator() *PaymentAuditLogUpsertOne {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.UpdateOperator()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *PaymentAuditLogUpsertOne) Exec(ctx context.Context) error {
|
||||
if len(u.create.conflict) == 0 {
|
||||
return errors.New("ent: missing options for PaymentAuditLogCreate.OnConflict")
|
||||
}
|
||||
return u.create.Exec(ctx)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (u *PaymentAuditLogUpsertOne) ExecX(ctx context.Context) {
|
||||
if err := u.create.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Exec executes the UPSERT query and returns the inserted/updated ID.
|
||||
func (u *PaymentAuditLogUpsertOne) ID(ctx context.Context) (id int64, err error) {
|
||||
node, err := u.create.Save(ctx)
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
return node.ID, nil
|
||||
}
|
||||
|
||||
// IDX is like ID, but panics if an error occurs.
|
||||
func (u *PaymentAuditLogUpsertOne) IDX(ctx context.Context) int64 {
|
||||
id, err := u.ID(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// PaymentAuditLogCreateBulk is the builder for creating many PaymentAuditLog entities in bulk.
|
||||
type PaymentAuditLogCreateBulk struct {
|
||||
config
|
||||
err error
|
||||
builders []*PaymentAuditLogCreate
|
||||
conflict []sql.ConflictOption
|
||||
}
|
||||
|
||||
// Save creates the PaymentAuditLog entities in the database.
|
||||
func (_c *PaymentAuditLogCreateBulk) Save(ctx context.Context) ([]*PaymentAuditLog, error) {
|
||||
if _c.err != nil {
|
||||
return nil, _c.err
|
||||
}
|
||||
specs := make([]*sqlgraph.CreateSpec, len(_c.builders))
|
||||
nodes := make([]*PaymentAuditLog, len(_c.builders))
|
||||
mutators := make([]Mutator, len(_c.builders))
|
||||
for i := range _c.builders {
|
||||
func(i int, root context.Context) {
|
||||
builder := _c.builders[i]
|
||||
builder.defaults()
|
||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||
mutation, ok := m.(*PaymentAuditLogMutation)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||
}
|
||||
if err := builder.check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
builder.mutation = mutation
|
||||
var err error
|
||||
nodes[i], specs[i] = builder.createSpec()
|
||||
if i < len(mutators)-1 {
|
||||
_, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation)
|
||||
} else {
|
||||
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
|
||||
spec.OnConflict = _c.conflict
|
||||
// Invoke the actual operation on the latest mutation in the chain.
|
||||
if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil {
|
||||
if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mutation.id = &nodes[i].ID
|
||||
if specs[i].ID.Value != nil {
|
||||
id := specs[i].ID.Value.(int64)
|
||||
nodes[i].ID = int64(id)
|
||||
}
|
||||
mutation.done = true
|
||||
return nodes[i], nil
|
||||
})
|
||||
for i := len(builder.hooks) - 1; i >= 0; i-- {
|
||||
mut = builder.hooks[i](mut)
|
||||
}
|
||||
mutators[i] = mut
|
||||
}(i, ctx)
|
||||
}
|
||||
if len(mutators) > 0 {
|
||||
if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (_c *PaymentAuditLogCreateBulk) SaveX(ctx context.Context) []*PaymentAuditLog {
|
||||
v, err := _c.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (_c *PaymentAuditLogCreateBulk) Exec(ctx context.Context) error {
|
||||
_, err := _c.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_c *PaymentAuditLogCreateBulk) ExecX(ctx context.Context) {
|
||||
if err := _c.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
|
||||
// of the `INSERT` statement. For example:
|
||||
//
|
||||
// client.PaymentAuditLog.CreateBulk(builders...).
|
||||
// OnConflict(
|
||||
// // Update the row with the new values
|
||||
// // the was proposed for insertion.
|
||||
// sql.ResolveWithNewValues(),
|
||||
// ).
|
||||
// // Override some of the fields with custom
|
||||
// // update values.
|
||||
// Update(func(u *ent.PaymentAuditLogUpsert) {
|
||||
// SetOrderID(v+v).
|
||||
// }).
|
||||
// Exec(ctx)
|
||||
func (_c *PaymentAuditLogCreateBulk) OnConflict(opts ...sql.ConflictOption) *PaymentAuditLogUpsertBulk {
|
||||
_c.conflict = opts
|
||||
return &PaymentAuditLogUpsertBulk{
|
||||
create: _c,
|
||||
}
|
||||
}
|
||||
|
||||
// OnConflictColumns calls `OnConflict` and configures the columns
|
||||
// as conflict target. Using this option is equivalent to using:
|
||||
//
|
||||
// client.PaymentAuditLog.Create().
|
||||
// OnConflict(sql.ConflictColumns(columns...)).
|
||||
// Exec(ctx)
|
||||
func (_c *PaymentAuditLogCreateBulk) OnConflictColumns(columns ...string) *PaymentAuditLogUpsertBulk {
|
||||
_c.conflict = append(_c.conflict, sql.ConflictColumns(columns...))
|
||||
return &PaymentAuditLogUpsertBulk{
|
||||
create: _c,
|
||||
}
|
||||
}
|
||||
|
||||
// PaymentAuditLogUpsertBulk is the builder for "upsert"-ing
|
||||
// a bulk of PaymentAuditLog nodes.
|
||||
type PaymentAuditLogUpsertBulk struct {
|
||||
create *PaymentAuditLogCreateBulk
|
||||
}
|
||||
|
||||
// UpdateNewValues updates the mutable fields using the new values that
|
||||
// were set on create. Using this option is equivalent to using:
|
||||
//
|
||||
// client.PaymentAuditLog.Create().
|
||||
// OnConflict(
|
||||
// sql.ResolveWithNewValues(),
|
||||
// ).
|
||||
// Exec(ctx)
|
||||
func (u *PaymentAuditLogUpsertBulk) UpdateNewValues() *PaymentAuditLogUpsertBulk {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
|
||||
for _, b := range u.create.builders {
|
||||
if _, exists := b.mutation.CreatedAt(); exists {
|
||||
s.SetIgnore(paymentauditlog.FieldCreatedAt)
|
||||
}
|
||||
}
|
||||
}))
|
||||
return u
|
||||
}
|
||||
|
||||
// Ignore sets each column to itself in case of conflict.
|
||||
// Using this option is equivalent to using:
|
||||
//
|
||||
// client.PaymentAuditLog.Create().
|
||||
// OnConflict(sql.ResolveWithIgnore()).
|
||||
// Exec(ctx)
|
||||
func (u *PaymentAuditLogUpsertBulk) Ignore() *PaymentAuditLogUpsertBulk {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
|
||||
return u
|
||||
}
|
||||
|
||||
// DoNothing configures the conflict_action to `DO NOTHING`.
|
||||
// Supported only by SQLite and PostgreSQL.
|
||||
func (u *PaymentAuditLogUpsertBulk) DoNothing() *PaymentAuditLogUpsertBulk {
|
||||
u.create.conflict = append(u.create.conflict, sql.DoNothing())
|
||||
return u
|
||||
}
|
||||
|
||||
// Update allows overriding fields `UPDATE` values. See the PaymentAuditLogCreateBulk.OnConflict
|
||||
// documentation for more info.
|
||||
func (u *PaymentAuditLogUpsertBulk) Update(set func(*PaymentAuditLogUpsert)) *PaymentAuditLogUpsertBulk {
|
||||
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
|
||||
set(&PaymentAuditLogUpsert{UpdateSet: update})
|
||||
}))
|
||||
return u
|
||||
}
|
||||
|
||||
// SetOrderID sets the "order_id" field.
|
||||
func (u *PaymentAuditLogUpsertBulk) SetOrderID(v string) *PaymentAuditLogUpsertBulk {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.SetOrderID(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateOrderID sets the "order_id" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsertBulk) UpdateOrderID() *PaymentAuditLogUpsertBulk {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.UpdateOrderID()
|
||||
})
|
||||
}
|
||||
|
||||
// SetAction sets the "action" field.
|
||||
func (u *PaymentAuditLogUpsertBulk) SetAction(v string) *PaymentAuditLogUpsertBulk {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.SetAction(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateAction sets the "action" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsertBulk) UpdateAction() *PaymentAuditLogUpsertBulk {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.UpdateAction()
|
||||
})
|
||||
}
|
||||
|
||||
// SetDetail sets the "detail" field.
|
||||
func (u *PaymentAuditLogUpsertBulk) SetDetail(v string) *PaymentAuditLogUpsertBulk {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.SetDetail(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateDetail sets the "detail" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsertBulk) UpdateDetail() *PaymentAuditLogUpsertBulk {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.UpdateDetail()
|
||||
})
|
||||
}
|
||||
|
||||
// SetOperator sets the "operator" field.
|
||||
func (u *PaymentAuditLogUpsertBulk) SetOperator(v string) *PaymentAuditLogUpsertBulk {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.SetOperator(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateOperator sets the "operator" field to the value that was provided on create.
|
||||
func (u *PaymentAuditLogUpsertBulk) UpdateOperator() *PaymentAuditLogUpsertBulk {
|
||||
return u.Update(func(s *PaymentAuditLogUpsert) {
|
||||
s.UpdateOperator()
|
||||
})
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (u *PaymentAuditLogUpsertBulk) Exec(ctx context.Context) error {
|
||||
if u.create.err != nil {
|
||||
return u.create.err
|
||||
}
|
||||
for i, b := range u.create.builders {
|
||||
if len(b.conflict) != 0 {
|
||||
return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the PaymentAuditLogCreateBulk instead", i)
|
||||
}
|
||||
}
|
||||
if len(u.create.conflict) == 0 {
|
||||
return errors.New("ent: missing options for PaymentAuditLogCreateBulk.OnConflict")
|
||||
}
|
||||
return u.create.Exec(ctx)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (u *PaymentAuditLogUpsertBulk) ExecX(ctx context.Context) {
|
||||
if err := u.create.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// PaymentAuditLogDelete is the builder for deleting a PaymentAuditLog entity.
|
||||
type PaymentAuditLogDelete struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *PaymentAuditLogMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentAuditLogDelete builder.
|
||||
func (_d *PaymentAuditLogDelete) Where(ps ...predicate.PaymentAuditLog) *PaymentAuditLogDelete {
|
||||
_d.mutation.Where(ps...)
|
||||
return _d
|
||||
}
|
||||
|
||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||
func (_d *PaymentAuditLogDelete) Exec(ctx context.Context) (int, error) {
|
||||
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_d *PaymentAuditLogDelete) ExecX(ctx context.Context) int {
|
||||
n, err := _d.Exec(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (_d *PaymentAuditLogDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
_spec := sqlgraph.NewDeleteSpec(paymentauditlog.Table, sqlgraph.NewFieldSpec(paymentauditlog.FieldID, field.TypeInt64))
|
||||
if ps := _d.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
|
||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
_d.mutation.done = true
|
||||
return affected, err
|
||||
}
|
||||
|
||||
// PaymentAuditLogDeleteOne is the builder for deleting a single PaymentAuditLog entity.
|
||||
type PaymentAuditLogDeleteOne struct {
|
||||
_d *PaymentAuditLogDelete
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentAuditLogDelete builder.
|
||||
func (_d *PaymentAuditLogDeleteOne) Where(ps ...predicate.PaymentAuditLog) *PaymentAuditLogDeleteOne {
|
||||
_d._d.mutation.Where(ps...)
|
||||
return _d
|
||||
}
|
||||
|
||||
// Exec executes the deletion query.
|
||||
func (_d *PaymentAuditLogDeleteOne) Exec(ctx context.Context) error {
|
||||
n, err := _d._d.Exec(ctx)
|
||||
switch {
|
||||
case err != nil:
|
||||
return err
|
||||
case n == 0:
|
||||
return &NotFoundError{paymentauditlog.Label}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_d *PaymentAuditLogDeleteOne) ExecX(ctx context.Context) {
|
||||
if err := _d.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// PaymentAuditLogQuery is the builder for querying PaymentAuditLog entities.
|
||||
type PaymentAuditLogQuery struct {
|
||||
config
|
||||
ctx *QueryContext
|
||||
order []paymentauditlog.OrderOption
|
||||
inters []Interceptor
|
||||
predicates []predicate.PaymentAuditLog
|
||||
modifiers []func(*sql.Selector)
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
}
|
||||
|
||||
// Where adds a new predicate for the PaymentAuditLogQuery builder.
|
||||
func (_q *PaymentAuditLogQuery) Where(ps ...predicate.PaymentAuditLog) *PaymentAuditLogQuery {
|
||||
_q.predicates = append(_q.predicates, ps...)
|
||||
return _q
|
||||
}
|
||||
|
||||
// Limit the number of records to be returned by this query.
|
||||
func (_q *PaymentAuditLogQuery) Limit(limit int) *PaymentAuditLogQuery {
|
||||
_q.ctx.Limit = &limit
|
||||
return _q
|
||||
}
|
||||
|
||||
// Offset to start from.
|
||||
func (_q *PaymentAuditLogQuery) Offset(offset int) *PaymentAuditLogQuery {
|
||||
_q.ctx.Offset = &offset
|
||||
return _q
|
||||
}
|
||||
|
||||
// Unique configures the query builder to filter duplicate records on query.
|
||||
// By default, unique is set to true, and can be disabled using this method.
|
||||
func (_q *PaymentAuditLogQuery) Unique(unique bool) *PaymentAuditLogQuery {
|
||||
_q.ctx.Unique = &unique
|
||||
return _q
|
||||
}
|
||||
|
||||
// Order specifies how the records should be ordered.
|
||||
func (_q *PaymentAuditLogQuery) Order(o ...paymentauditlog.OrderOption) *PaymentAuditLogQuery {
|
||||
_q.order = append(_q.order, o...)
|
||||
return _q
|
||||
}
|
||||
|
||||
// First returns the first PaymentAuditLog entity from the query.
|
||||
// Returns a *NotFoundError when no PaymentAuditLog was found.
|
||||
func (_q *PaymentAuditLogQuery) First(ctx context.Context) (*PaymentAuditLog, error) {
|
||||
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nil, &NotFoundError{paymentauditlog.Label}
|
||||
}
|
||||
return nodes[0], nil
|
||||
}
|
||||
|
||||
// FirstX is like First, but panics if an error occurs.
|
||||
func (_q *PaymentAuditLogQuery) FirstX(ctx context.Context) *PaymentAuditLog {
|
||||
node, err := _q.First(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// FirstID returns the first PaymentAuditLog ID from the query.
|
||||
// Returns a *NotFoundError when no PaymentAuditLog ID was found.
|
||||
func (_q *PaymentAuditLogQuery) FirstID(ctx context.Context) (id int64, err error) {
|
||||
var ids []int64
|
||||
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
err = &NotFoundError{paymentauditlog.Label}
|
||||
return
|
||||
}
|
||||
return ids[0], nil
|
||||
}
|
||||
|
||||
// FirstIDX is like FirstID, but panics if an error occurs.
|
||||
func (_q *PaymentAuditLogQuery) FirstIDX(ctx context.Context) int64 {
|
||||
id, err := _q.FirstID(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// Only returns a single PaymentAuditLog entity found by the query, ensuring it only returns one.
|
||||
// Returns a *NotSingularError when more than one PaymentAuditLog entity is found.
|
||||
// Returns a *NotFoundError when no PaymentAuditLog entities are found.
|
||||
func (_q *PaymentAuditLogQuery) Only(ctx context.Context) (*PaymentAuditLog, error) {
|
||||
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch len(nodes) {
|
||||
case 1:
|
||||
return nodes[0], nil
|
||||
case 0:
|
||||
return nil, &NotFoundError{paymentauditlog.Label}
|
||||
default:
|
||||
return nil, &NotSingularError{paymentauditlog.Label}
|
||||
}
|
||||
}
|
||||
|
||||
// OnlyX is like Only, but panics if an error occurs.
|
||||
func (_q *PaymentAuditLogQuery) OnlyX(ctx context.Context) *PaymentAuditLog {
|
||||
node, err := _q.Only(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// OnlyID is like Only, but returns the only PaymentAuditLog ID in the query.
|
||||
// Returns a *NotSingularError when more than one PaymentAuditLog ID is found.
|
||||
// Returns a *NotFoundError when no entities are found.
|
||||
func (_q *PaymentAuditLogQuery) OnlyID(ctx context.Context) (id int64, err error) {
|
||||
var ids []int64
|
||||
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
|
||||
return
|
||||
}
|
||||
switch len(ids) {
|
||||
case 1:
|
||||
id = ids[0]
|
||||
case 0:
|
||||
err = &NotFoundError{paymentauditlog.Label}
|
||||
default:
|
||||
err = &NotSingularError{paymentauditlog.Label}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OnlyIDX is like OnlyID, but panics if an error occurs.
|
||||
func (_q *PaymentAuditLogQuery) OnlyIDX(ctx context.Context) int64 {
|
||||
id, err := _q.OnlyID(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// All executes the query and returns a list of PaymentAuditLogs.
|
||||
func (_q *PaymentAuditLogQuery) All(ctx context.Context) ([]*PaymentAuditLog, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
qr := querierAll[[]*PaymentAuditLog, *PaymentAuditLogQuery]()
|
||||
return withInterceptors[[]*PaymentAuditLog](ctx, _q, qr, _q.inters)
|
||||
}
|
||||
|
||||
// AllX is like All, but panics if an error occurs.
|
||||
func (_q *PaymentAuditLogQuery) AllX(ctx context.Context) []*PaymentAuditLog {
|
||||
nodes, err := _q.All(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
// IDs executes the query and returns a list of PaymentAuditLog IDs.
|
||||
func (_q *PaymentAuditLogQuery) IDs(ctx context.Context) (ids []int64, err error) {
|
||||
if _q.ctx.Unique == nil && _q.path != nil {
|
||||
_q.Unique(true)
|
||||
}
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
|
||||
if err = _q.Select(paymentauditlog.FieldID).Scan(ctx, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// IDsX is like IDs, but panics if an error occurs.
|
||||
func (_q *PaymentAuditLogQuery) IDsX(ctx context.Context) []int64 {
|
||||
ids, err := _q.IDs(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// Count returns the count of the given query.
|
||||
func (_q *PaymentAuditLogQuery) Count(ctx context.Context) (int, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return withInterceptors[int](ctx, _q, querierCount[*PaymentAuditLogQuery](), _q.inters)
|
||||
}
|
||||
|
||||
// CountX is like Count, but panics if an error occurs.
|
||||
func (_q *PaymentAuditLogQuery) CountX(ctx context.Context) int {
|
||||
count, err := _q.Count(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Exist returns true if the query has elements in the graph.
|
||||
func (_q *PaymentAuditLogQuery) Exist(ctx context.Context) (bool, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
|
||||
switch _, err := _q.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExistX is like Exist, but panics if an error occurs.
|
||||
func (_q *PaymentAuditLogQuery) ExistX(ctx context.Context) bool {
|
||||
exist, err := _q.Exist(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return exist
|
||||
}
|
||||
|
||||
// Clone returns a duplicate of the PaymentAuditLogQuery builder, including all associated steps. It can be
|
||||
// used to prepare common query builders and use them differently after the clone is made.
|
||||
func (_q *PaymentAuditLogQuery) Clone() *PaymentAuditLogQuery {
|
||||
if _q == nil {
|
||||
return nil
|
||||
}
|
||||
return &PaymentAuditLogQuery{
|
||||
config: _q.config,
|
||||
ctx: _q.ctx.Clone(),
|
||||
order: append([]paymentauditlog.OrderOption{}, _q.order...),
|
||||
inters: append([]Interceptor{}, _q.inters...),
|
||||
predicates: append([]predicate.PaymentAuditLog{}, _q.predicates...),
|
||||
// clone intermediate query.
|
||||
sql: _q.sql.Clone(),
|
||||
path: _q.path,
|
||||
}
|
||||
}
|
||||
|
||||
// GroupBy is used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// OrderID string `json:"order_id,omitempty"`
|
||||
// Count int `json:"count,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.PaymentAuditLog.Query().
|
||||
// GroupBy(paymentauditlog.FieldOrderID).
|
||||
// Aggregate(ent.Count()).
|
||||
// Scan(ctx, &v)
|
||||
func (_q *PaymentAuditLogQuery) GroupBy(field string, fields ...string) *PaymentAuditLogGroupBy {
|
||||
_q.ctx.Fields = append([]string{field}, fields...)
|
||||
grbuild := &PaymentAuditLogGroupBy{build: _q}
|
||||
grbuild.flds = &_q.ctx.Fields
|
||||
grbuild.label = paymentauditlog.Label
|
||||
grbuild.scan = grbuild.Scan
|
||||
return grbuild
|
||||
}
|
||||
|
||||
// Select allows the selection one or more fields/columns for the given query,
|
||||
// instead of selecting all fields in the entity.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// OrderID string `json:"order_id,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.PaymentAuditLog.Query().
|
||||
// Select(paymentauditlog.FieldOrderID).
|
||||
// Scan(ctx, &v)
|
||||
func (_q *PaymentAuditLogQuery) Select(fields ...string) *PaymentAuditLogSelect {
|
||||
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
|
||||
sbuild := &PaymentAuditLogSelect{PaymentAuditLogQuery: _q}
|
||||
sbuild.label = paymentauditlog.Label
|
||||
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
|
||||
return sbuild
|
||||
}
|
||||
|
||||
// Aggregate returns a PaymentAuditLogSelect configured with the given aggregations.
|
||||
func (_q *PaymentAuditLogQuery) Aggregate(fns ...AggregateFunc) *PaymentAuditLogSelect {
|
||||
return _q.Select().Aggregate(fns...)
|
||||
}
|
||||
|
||||
func (_q *PaymentAuditLogQuery) prepareQuery(ctx context.Context) error {
|
||||
for _, inter := range _q.inters {
|
||||
if inter == nil {
|
||||
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
|
||||
}
|
||||
if trv, ok := inter.(Traverser); ok {
|
||||
if err := trv.Traverse(ctx, _q); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range _q.ctx.Fields {
|
||||
if !paymentauditlog.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
}
|
||||
if _q.path != nil {
|
||||
prev, err := _q.path(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_q.sql = prev
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_q *PaymentAuditLogQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*PaymentAuditLog, error) {
|
||||
var (
|
||||
nodes = []*PaymentAuditLog{}
|
||||
_spec = _q.querySpec()
|
||||
)
|
||||
_spec.ScanValues = func(columns []string) ([]any, error) {
|
||||
return (*PaymentAuditLog).scanValues(nil, columns)
|
||||
}
|
||||
_spec.Assign = func(columns []string, values []any) error {
|
||||
node := &PaymentAuditLog{config: _q.config}
|
||||
nodes = append(nodes, node)
|
||||
return node.assignValues(columns, values)
|
||||
}
|
||||
if len(_q.modifiers) > 0 {
|
||||
_spec.Modifiers = _q.modifiers
|
||||
}
|
||||
for i := range hooks {
|
||||
hooks[i](ctx, _spec)
|
||||
}
|
||||
if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nodes, nil
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (_q *PaymentAuditLogQuery) sqlCount(ctx context.Context) (int, error) {
|
||||
_spec := _q.querySpec()
|
||||
if len(_q.modifiers) > 0 {
|
||||
_spec.Modifiers = _q.modifiers
|
||||
}
|
||||
_spec.Node.Columns = _q.ctx.Fields
|
||||
if len(_q.ctx.Fields) > 0 {
|
||||
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
|
||||
}
|
||||
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
|
||||
}
|
||||
|
||||
func (_q *PaymentAuditLogQuery) querySpec() *sqlgraph.QuerySpec {
|
||||
_spec := sqlgraph.NewQuerySpec(paymentauditlog.Table, paymentauditlog.Columns, sqlgraph.NewFieldSpec(paymentauditlog.FieldID, field.TypeInt64))
|
||||
_spec.From = _q.sql
|
||||
if unique := _q.ctx.Unique; unique != nil {
|
||||
_spec.Unique = *unique
|
||||
} else if _q.path != nil {
|
||||
_spec.Unique = true
|
||||
}
|
||||
if fields := _q.ctx.Fields; len(fields) > 0 {
|
||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, paymentauditlog.FieldID)
|
||||
for i := range fields {
|
||||
if fields[i] != paymentauditlog.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
if ps := _q.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if limit := _q.ctx.Limit; limit != nil {
|
||||
_spec.Limit = *limit
|
||||
}
|
||||
if offset := _q.ctx.Offset; offset != nil {
|
||||
_spec.Offset = *offset
|
||||
}
|
||||
if ps := _q.order; len(ps) > 0 {
|
||||
_spec.Order = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
return _spec
|
||||
}
|
||||
|
||||
func (_q *PaymentAuditLogQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||
builder := sql.Dialect(_q.driver.Dialect())
|
||||
t1 := builder.Table(paymentauditlog.Table)
|
||||
columns := _q.ctx.Fields
|
||||
if len(columns) == 0 {
|
||||
columns = paymentauditlog.Columns
|
||||
}
|
||||
selector := builder.Select(t1.Columns(columns...)...).From(t1)
|
||||
if _q.sql != nil {
|
||||
selector = _q.sql
|
||||
selector.Select(selector.Columns(columns...)...)
|
||||
}
|
||||
if _q.ctx.Unique != nil && *_q.ctx.Unique {
|
||||
selector.Distinct()
|
||||
}
|
||||
for _, m := range _q.modifiers {
|
||||
m(selector)
|
||||
}
|
||||
for _, p := range _q.predicates {
|
||||
p(selector)
|
||||
}
|
||||
for _, p := range _q.order {
|
||||
p(selector)
|
||||
}
|
||||
if offset := _q.ctx.Offset; offset != nil {
|
||||
// limit is mandatory for offset clause. We start
|
||||
// with default value, and override it below if needed.
|
||||
selector.Offset(*offset).Limit(math.MaxInt32)
|
||||
}
|
||||
if limit := _q.ctx.Limit; limit != nil {
|
||||
selector.Limit(*limit)
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
// ForUpdate locks the selected rows against concurrent updates, and prevent them from being
|
||||
// updated, deleted or "selected ... for update" by other sessions, until the transaction is
|
||||
// either committed or rolled-back.
|
||||
func (_q *PaymentAuditLogQuery) ForUpdate(opts ...sql.LockOption) *PaymentAuditLogQuery {
|
||||
if _q.driver.Dialect() == dialect.Postgres {
|
||||
_q.Unique(false)
|
||||
}
|
||||
_q.modifiers = append(_q.modifiers, func(s *sql.Selector) {
|
||||
s.ForUpdate(opts...)
|
||||
})
|
||||
return _q
|
||||
}
|
||||
|
||||
// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock
|
||||
// on any rows that are read. Other sessions can read the rows, but cannot modify them
|
||||
// until your transaction commits.
|
||||
func (_q *PaymentAuditLogQuery) ForShare(opts ...sql.LockOption) *PaymentAuditLogQuery {
|
||||
if _q.driver.Dialect() == dialect.Postgres {
|
||||
_q.Unique(false)
|
||||
}
|
||||
_q.modifiers = append(_q.modifiers, func(s *sql.Selector) {
|
||||
s.ForShare(opts...)
|
||||
})
|
||||
return _q
|
||||
}
|
||||
|
||||
// PaymentAuditLogGroupBy is the group-by builder for PaymentAuditLog entities.
|
||||
type PaymentAuditLogGroupBy struct {
|
||||
selector
|
||||
build *PaymentAuditLogQuery
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the group-by query.
|
||||
func (_g *PaymentAuditLogGroupBy) Aggregate(fns ...AggregateFunc) *PaymentAuditLogGroupBy {
|
||||
_g.fns = append(_g.fns, fns...)
|
||||
return _g
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (_g *PaymentAuditLogGroupBy) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
|
||||
if err := _g.build.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*PaymentAuditLogQuery, *PaymentAuditLogGroupBy](ctx, _g.build, _g, _g.build.inters, v)
|
||||
}
|
||||
|
||||
func (_g *PaymentAuditLogGroupBy) sqlScan(ctx context.Context, root *PaymentAuditLogQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx).Select()
|
||||
aggregation := make([]string, 0, len(_g.fns))
|
||||
for _, fn := range _g.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
if len(selector.SelectedColumns()) == 0 {
|
||||
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
|
||||
for _, f := range *_g.flds {
|
||||
columns = append(columns, selector.C(f))
|
||||
}
|
||||
columns = append(columns, aggregation...)
|
||||
selector.Select(columns...)
|
||||
}
|
||||
selector.GroupBy(selector.Columns(*_g.flds...)...)
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
// PaymentAuditLogSelect is the builder for selecting fields of PaymentAuditLog entities.
|
||||
type PaymentAuditLogSelect struct {
|
||||
*PaymentAuditLogQuery
|
||||
selector
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the selector query.
|
||||
func (_s *PaymentAuditLogSelect) Aggregate(fns ...AggregateFunc) *PaymentAuditLogSelect {
|
||||
_s.fns = append(_s.fns, fns...)
|
||||
return _s
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (_s *PaymentAuditLogSelect) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
|
||||
if err := _s.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*PaymentAuditLogQuery, *PaymentAuditLogSelect](ctx, _s.PaymentAuditLogQuery, _s, _s.inters, v)
|
||||
}
|
||||
|
||||
func (_s *PaymentAuditLogSelect) sqlScan(ctx context.Context, root *PaymentAuditLogQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx)
|
||||
aggregation := make([]string, 0, len(_s.fns))
|
||||
for _, fn := range _s.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
switch n := len(*_s.selector.flds); {
|
||||
case n == 0 && len(aggregation) > 0:
|
||||
selector.Select(aggregation...)
|
||||
case n != 0 && len(aggregation) > 0:
|
||||
selector.AppendSelect(aggregation...)
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := _s.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// PaymentAuditLogUpdate is the builder for updating PaymentAuditLog entities.
|
||||
type PaymentAuditLogUpdate struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *PaymentAuditLogMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentAuditLogUpdate builder.
|
||||
func (_u *PaymentAuditLogUpdate) Where(ps ...predicate.PaymentAuditLog) *PaymentAuditLogUpdate {
|
||||
_u.mutation.Where(ps...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetOrderID sets the "order_id" field.
|
||||
func (_u *PaymentAuditLogUpdate) SetOrderID(v string) *PaymentAuditLogUpdate {
|
||||
_u.mutation.SetOrderID(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableOrderID sets the "order_id" field if the given value is not nil.
|
||||
func (_u *PaymentAuditLogUpdate) SetNillableOrderID(v *string) *PaymentAuditLogUpdate {
|
||||
if v != nil {
|
||||
_u.SetOrderID(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetAction sets the "action" field.
|
||||
func (_u *PaymentAuditLogUpdate) SetAction(v string) *PaymentAuditLogUpdate {
|
||||
_u.mutation.SetAction(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableAction sets the "action" field if the given value is not nil.
|
||||
func (_u *PaymentAuditLogUpdate) SetNillableAction(v *string) *PaymentAuditLogUpdate {
|
||||
if v != nil {
|
||||
_u.SetAction(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetDetail sets the "detail" field.
|
||||
func (_u *PaymentAuditLogUpdate) SetDetail(v string) *PaymentAuditLogUpdate {
|
||||
_u.mutation.SetDetail(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableDetail sets the "detail" field if the given value is not nil.
|
||||
func (_u *PaymentAuditLogUpdate) SetNillableDetail(v *string) *PaymentAuditLogUpdate {
|
||||
if v != nil {
|
||||
_u.SetDetail(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetOperator sets the "operator" field.
|
||||
func (_u *PaymentAuditLogUpdate) SetOperator(v string) *PaymentAuditLogUpdate {
|
||||
_u.mutation.SetOperator(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableOperator sets the "operator" field if the given value is not nil.
|
||||
func (_u *PaymentAuditLogUpdate) SetNillableOperator(v *string) *PaymentAuditLogUpdate {
|
||||
if v != nil {
|
||||
_u.SetOperator(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// Mutation returns the PaymentAuditLogMutation object of the builder.
|
||||
func (_u *PaymentAuditLogUpdate) Mutation() *PaymentAuditLogMutation {
|
||||
return _u.mutation
|
||||
}
|
||||
|
||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||
func (_u *PaymentAuditLogUpdate) Save(ctx context.Context) (int, error) {
|
||||
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (_u *PaymentAuditLogUpdate) SaveX(ctx context.Context) int {
|
||||
affected, err := _u.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return affected
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (_u *PaymentAuditLogUpdate) Exec(ctx context.Context) error {
|
||||
_, err := _u.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_u *PaymentAuditLogUpdate) ExecX(ctx context.Context) {
|
||||
if err := _u.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (_u *PaymentAuditLogUpdate) check() error {
|
||||
if v, ok := _u.mutation.OrderID(); ok {
|
||||
if err := paymentauditlog.OrderIDValidator(v); err != nil {
|
||||
return &ValidationError{Name: "order_id", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.order_id": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.Action(); ok {
|
||||
if err := paymentauditlog.ActionValidator(v); err != nil {
|
||||
return &ValidationError{Name: "action", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.action": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.Operator(); ok {
|
||||
if err := paymentauditlog.OperatorValidator(v); err != nil {
|
||||
return &ValidationError{Name: "operator", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.operator": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_u *PaymentAuditLogUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
if err := _u.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(paymentauditlog.Table, paymentauditlog.Columns, sqlgraph.NewFieldSpec(paymentauditlog.FieldID, field.TypeInt64))
|
||||
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, ok := _u.mutation.OrderID(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldOrderID, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Action(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldAction, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Detail(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldDetail, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Operator(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldOperator, field.TypeString, value)
|
||||
}
|
||||
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{paymentauditlog.Label}
|
||||
} else if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
_u.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
// PaymentAuditLogUpdateOne is the builder for updating a single PaymentAuditLog entity.
|
||||
type PaymentAuditLogUpdateOne struct {
|
||||
config
|
||||
fields []string
|
||||
hooks []Hook
|
||||
mutation *PaymentAuditLogMutation
|
||||
}
|
||||
|
||||
// SetOrderID sets the "order_id" field.
|
||||
func (_u *PaymentAuditLogUpdateOne) SetOrderID(v string) *PaymentAuditLogUpdateOne {
|
||||
_u.mutation.SetOrderID(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableOrderID sets the "order_id" field if the given value is not nil.
|
||||
func (_u *PaymentAuditLogUpdateOne) SetNillableOrderID(v *string) *PaymentAuditLogUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetOrderID(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetAction sets the "action" field.
|
||||
func (_u *PaymentAuditLogUpdateOne) SetAction(v string) *PaymentAuditLogUpdateOne {
|
||||
_u.mutation.SetAction(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableAction sets the "action" field if the given value is not nil.
|
||||
func (_u *PaymentAuditLogUpdateOne) SetNillableAction(v *string) *PaymentAuditLogUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetAction(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetDetail sets the "detail" field.
|
||||
func (_u *PaymentAuditLogUpdateOne) SetDetail(v string) *PaymentAuditLogUpdateOne {
|
||||
_u.mutation.SetDetail(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableDetail sets the "detail" field if the given value is not nil.
|
||||
func (_u *PaymentAuditLogUpdateOne) SetNillableDetail(v *string) *PaymentAuditLogUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetDetail(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetOperator sets the "operator" field.
|
||||
func (_u *PaymentAuditLogUpdateOne) SetOperator(v string) *PaymentAuditLogUpdateOne {
|
||||
_u.mutation.SetOperator(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableOperator sets the "operator" field if the given value is not nil.
|
||||
func (_u *PaymentAuditLogUpdateOne) SetNillableOperator(v *string) *PaymentAuditLogUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetOperator(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// Mutation returns the PaymentAuditLogMutation object of the builder.
|
||||
func (_u *PaymentAuditLogUpdateOne) Mutation() *PaymentAuditLogMutation {
|
||||
return _u.mutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentAuditLogUpdate builder.
|
||||
func (_u *PaymentAuditLogUpdateOne) Where(ps ...predicate.PaymentAuditLog) *PaymentAuditLogUpdateOne {
|
||||
_u.mutation.Where(ps...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||
// The default is selecting all fields defined in the entity schema.
|
||||
func (_u *PaymentAuditLogUpdateOne) Select(field string, fields ...string) *PaymentAuditLogUpdateOne {
|
||||
_u.fields = append([]string{field}, fields...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Save executes the query and returns the updated PaymentAuditLog entity.
|
||||
func (_u *PaymentAuditLogUpdateOne) Save(ctx context.Context) (*PaymentAuditLog, error) {
|
||||
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (_u *PaymentAuditLogUpdateOne) SaveX(ctx context.Context) *PaymentAuditLog {
|
||||
node, err := _u.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// Exec executes the query on the entity.
|
||||
func (_u *PaymentAuditLogUpdateOne) Exec(ctx context.Context) error {
|
||||
_, err := _u.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_u *PaymentAuditLogUpdateOne) ExecX(ctx context.Context) {
|
||||
if err := _u.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (_u *PaymentAuditLogUpdateOne) check() error {
|
||||
if v, ok := _u.mutation.OrderID(); ok {
|
||||
if err := paymentauditlog.OrderIDValidator(v); err != nil {
|
||||
return &ValidationError{Name: "order_id", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.order_id": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.Action(); ok {
|
||||
if err := paymentauditlog.ActionValidator(v); err != nil {
|
||||
return &ValidationError{Name: "action", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.action": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.Operator(); ok {
|
||||
if err := paymentauditlog.OperatorValidator(v); err != nil {
|
||||
return &ValidationError{Name: "operator", err: fmt.Errorf(`ent: validator failed for field "PaymentAuditLog.operator": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_u *PaymentAuditLogUpdateOne) sqlSave(ctx context.Context) (_node *PaymentAuditLog, err error) {
|
||||
if err := _u.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(paymentauditlog.Table, paymentauditlog.Columns, sqlgraph.NewFieldSpec(paymentauditlog.FieldID, field.TypeInt64))
|
||||
id, ok := _u.mutation.ID()
|
||||
if !ok {
|
||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "PaymentAuditLog.id" for update`)}
|
||||
}
|
||||
_spec.Node.ID.Value = id
|
||||
if fields := _u.fields; len(fields) > 0 {
|
||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, paymentauditlog.FieldID)
|
||||
for _, f := range fields {
|
||||
if !paymentauditlog.ValidColumn(f) {
|
||||
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
if f != paymentauditlog.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, ok := _u.mutation.OrderID(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldOrderID, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Action(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldAction, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Detail(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldDetail, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Operator(); ok {
|
||||
_spec.SetField(paymentauditlog.FieldOperator, field.TypeString, value)
|
||||
}
|
||||
_node = &PaymentAuditLog{config: _u.config}
|
||||
_spec.Assign = _node.assignValues
|
||||
_spec.ScanValues = _node.scanValues
|
||||
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{paymentauditlog.Label}
|
||||
} else if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
_u.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/user"
|
||||
)
|
||||
|
||||
// PaymentOrder is the model entity for the PaymentOrder schema.
|
||||
type PaymentOrder struct {
|
||||
config `json:"-"`
|
||||
// ID of the ent.
|
||||
ID int64 `json:"id,omitempty"`
|
||||
// UserID holds the value of the "user_id" field.
|
||||
UserID int64 `json:"user_id,omitempty"`
|
||||
// UserEmail holds the value of the "user_email" field.
|
||||
UserEmail string `json:"user_email,omitempty"`
|
||||
// UserName holds the value of the "user_name" field.
|
||||
UserName string `json:"user_name,omitempty"`
|
||||
// UserNotes holds the value of the "user_notes" field.
|
||||
UserNotes *string `json:"user_notes,omitempty"`
|
||||
// Amount holds the value of the "amount" field.
|
||||
Amount float64 `json:"amount,omitempty"`
|
||||
// PayAmount holds the value of the "pay_amount" field.
|
||||
PayAmount float64 `json:"pay_amount,omitempty"`
|
||||
// FeeRate holds the value of the "fee_rate" field.
|
||||
FeeRate float64 `json:"fee_rate,omitempty"`
|
||||
// RechargeCode holds the value of the "recharge_code" field.
|
||||
RechargeCode string `json:"recharge_code,omitempty"`
|
||||
// PaymentType holds the value of the "payment_type" field.
|
||||
PaymentType string `json:"payment_type,omitempty"`
|
||||
// PaymentTradeNo holds the value of the "payment_trade_no" field.
|
||||
PaymentTradeNo string `json:"payment_trade_no,omitempty"`
|
||||
// PayURL holds the value of the "pay_url" field.
|
||||
PayURL *string `json:"pay_url,omitempty"`
|
||||
// QrCode holds the value of the "qr_code" field.
|
||||
QrCode *string `json:"qr_code,omitempty"`
|
||||
// QrCodeImg holds the value of the "qr_code_img" field.
|
||||
QrCodeImg *string `json:"qr_code_img,omitempty"`
|
||||
// OrderType holds the value of the "order_type" field.
|
||||
OrderType string `json:"order_type,omitempty"`
|
||||
// PlanID holds the value of the "plan_id" field.
|
||||
PlanID *int64 `json:"plan_id,omitempty"`
|
||||
// SubscriptionGroupID holds the value of the "subscription_group_id" field.
|
||||
SubscriptionGroupID *int64 `json:"subscription_group_id,omitempty"`
|
||||
// SubscriptionDays holds the value of the "subscription_days" field.
|
||||
SubscriptionDays *int `json:"subscription_days,omitempty"`
|
||||
// ProviderInstanceID holds the value of the "provider_instance_id" field.
|
||||
ProviderInstanceID *string `json:"provider_instance_id,omitempty"`
|
||||
// Status holds the value of the "status" field.
|
||||
Status string `json:"status,omitempty"`
|
||||
// RefundAmount holds the value of the "refund_amount" field.
|
||||
RefundAmount float64 `json:"refund_amount,omitempty"`
|
||||
// RefundReason holds the value of the "refund_reason" field.
|
||||
RefundReason *string `json:"refund_reason,omitempty"`
|
||||
// RefundAt holds the value of the "refund_at" field.
|
||||
RefundAt *time.Time `json:"refund_at,omitempty"`
|
||||
// ForceRefund holds the value of the "force_refund" field.
|
||||
ForceRefund bool `json:"force_refund,omitempty"`
|
||||
// RefundRequestedAt holds the value of the "refund_requested_at" field.
|
||||
RefundRequestedAt *time.Time `json:"refund_requested_at,omitempty"`
|
||||
// RefundRequestReason holds the value of the "refund_request_reason" field.
|
||||
RefundRequestReason *string `json:"refund_request_reason,omitempty"`
|
||||
// RefundRequestedBy holds the value of the "refund_requested_by" field.
|
||||
RefundRequestedBy *string `json:"refund_requested_by,omitempty"`
|
||||
// ExpiresAt holds the value of the "expires_at" field.
|
||||
ExpiresAt time.Time `json:"expires_at,omitempty"`
|
||||
// PaidAt holds the value of the "paid_at" field.
|
||||
PaidAt *time.Time `json:"paid_at,omitempty"`
|
||||
// CompletedAt holds the value of the "completed_at" field.
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
// FailedAt holds the value of the "failed_at" field.
|
||||
FailedAt *time.Time `json:"failed_at,omitempty"`
|
||||
// FailedReason holds the value of the "failed_reason" field.
|
||||
FailedReason *string `json:"failed_reason,omitempty"`
|
||||
// ClientIP holds the value of the "client_ip" field.
|
||||
ClientIP string `json:"client_ip,omitempty"`
|
||||
// SrcHost holds the value of the "src_host" field.
|
||||
SrcHost string `json:"src_host,omitempty"`
|
||||
// SrcURL holds the value of the "src_url" field.
|
||||
SrcURL *string `json:"src_url,omitempty"`
|
||||
// CreatedAt holds the value of the "created_at" field.
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
// UpdatedAt holds the value of the "updated_at" field.
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the PaymentOrderQuery when eager-loading is set.
|
||||
Edges PaymentOrderEdges `json:"edges"`
|
||||
selectValues sql.SelectValues
|
||||
}
|
||||
|
||||
// PaymentOrderEdges holds the relations/edges for other nodes in the graph.
|
||||
type PaymentOrderEdges struct {
|
||||
// User holds the value of the user edge.
|
||||
User *User `json:"user,omitempty"`
|
||||
// loadedTypes holds the information for reporting if a
|
||||
// type was loaded (or requested) in eager-loading or not.
|
||||
loadedTypes [1]bool
|
||||
}
|
||||
|
||||
// UserOrErr returns the User value or an error if the edge
|
||||
// was not loaded in eager-loading, or loaded but was not found.
|
||||
func (e PaymentOrderEdges) UserOrErr() (*User, error) {
|
||||
if e.User != nil {
|
||||
return e.User, nil
|
||||
} else if e.loadedTypes[0] {
|
||||
return nil, &NotFoundError{label: user.Label}
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "user"}
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*PaymentOrder) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case paymentorder.FieldForceRefund:
|
||||
values[i] = new(sql.NullBool)
|
||||
case paymentorder.FieldAmount, paymentorder.FieldPayAmount, paymentorder.FieldFeeRate, paymentorder.FieldRefundAmount:
|
||||
values[i] = new(sql.NullFloat64)
|
||||
case paymentorder.FieldID, paymentorder.FieldUserID, paymentorder.FieldPlanID, paymentorder.FieldSubscriptionGroupID, paymentorder.FieldSubscriptionDays:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case paymentorder.FieldUserEmail, paymentorder.FieldUserName, paymentorder.FieldUserNotes, paymentorder.FieldRechargeCode, paymentorder.FieldPaymentType, paymentorder.FieldPaymentTradeNo, paymentorder.FieldPayURL, paymentorder.FieldQrCode, paymentorder.FieldQrCodeImg, paymentorder.FieldOrderType, paymentorder.FieldProviderInstanceID, paymentorder.FieldStatus, paymentorder.FieldRefundReason, paymentorder.FieldRefundRequestReason, paymentorder.FieldRefundRequestedBy, paymentorder.FieldFailedReason, paymentorder.FieldClientIP, paymentorder.FieldSrcHost, paymentorder.FieldSrcURL:
|
||||
values[i] = new(sql.NullString)
|
||||
case paymentorder.FieldRefundAt, paymentorder.FieldRefundRequestedAt, paymentorder.FieldExpiresAt, paymentorder.FieldPaidAt, paymentorder.FieldCompletedAt, paymentorder.FieldFailedAt, paymentorder.FieldCreatedAt, paymentorder.FieldUpdatedAt:
|
||||
values[i] = new(sql.NullTime)
|
||||
default:
|
||||
values[i] = new(sql.UnknownType)
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the PaymentOrder fields.
|
||||
func (_m *PaymentOrder) assignValues(columns []string, values []any) error {
|
||||
if m, n := len(values), len(columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case paymentorder.FieldID:
|
||||
value, ok := values[i].(*sql.NullInt64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field id", value)
|
||||
}
|
||||
_m.ID = int64(value.Int64)
|
||||
case paymentorder.FieldUserID:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field user_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.UserID = value.Int64
|
||||
}
|
||||
case paymentorder.FieldUserEmail:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field user_email", values[i])
|
||||
} else if value.Valid {
|
||||
_m.UserEmail = value.String
|
||||
}
|
||||
case paymentorder.FieldUserName:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field user_name", values[i])
|
||||
} else if value.Valid {
|
||||
_m.UserName = value.String
|
||||
}
|
||||
case paymentorder.FieldUserNotes:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field user_notes", values[i])
|
||||
} else if value.Valid {
|
||||
_m.UserNotes = new(string)
|
||||
*_m.UserNotes = value.String
|
||||
}
|
||||
case paymentorder.FieldAmount:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field amount", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Amount = value.Float64
|
||||
}
|
||||
case paymentorder.FieldPayAmount:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field pay_amount", values[i])
|
||||
} else if value.Valid {
|
||||
_m.PayAmount = value.Float64
|
||||
}
|
||||
case paymentorder.FieldFeeRate:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field fee_rate", values[i])
|
||||
} else if value.Valid {
|
||||
_m.FeeRate = value.Float64
|
||||
}
|
||||
case paymentorder.FieldRechargeCode:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field recharge_code", values[i])
|
||||
} else if value.Valid {
|
||||
_m.RechargeCode = value.String
|
||||
}
|
||||
case paymentorder.FieldPaymentType:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field payment_type", values[i])
|
||||
} else if value.Valid {
|
||||
_m.PaymentType = value.String
|
||||
}
|
||||
case paymentorder.FieldPaymentTradeNo:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field payment_trade_no", values[i])
|
||||
} else if value.Valid {
|
||||
_m.PaymentTradeNo = value.String
|
||||
}
|
||||
case paymentorder.FieldPayURL:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field pay_url", values[i])
|
||||
} else if value.Valid {
|
||||
_m.PayURL = new(string)
|
||||
*_m.PayURL = value.String
|
||||
}
|
||||
case paymentorder.FieldQrCode:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field qr_code", values[i])
|
||||
} else if value.Valid {
|
||||
_m.QrCode = new(string)
|
||||
*_m.QrCode = value.String
|
||||
}
|
||||
case paymentorder.FieldQrCodeImg:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field qr_code_img", values[i])
|
||||
} else if value.Valid {
|
||||
_m.QrCodeImg = new(string)
|
||||
*_m.QrCodeImg = value.String
|
||||
}
|
||||
case paymentorder.FieldOrderType:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field order_type", values[i])
|
||||
} else if value.Valid {
|
||||
_m.OrderType = value.String
|
||||
}
|
||||
case paymentorder.FieldPlanID:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field plan_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.PlanID = new(int64)
|
||||
*_m.PlanID = value.Int64
|
||||
}
|
||||
case paymentorder.FieldSubscriptionGroupID:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field subscription_group_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.SubscriptionGroupID = new(int64)
|
||||
*_m.SubscriptionGroupID = value.Int64
|
||||
}
|
||||
case paymentorder.FieldSubscriptionDays:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field subscription_days", values[i])
|
||||
} else if value.Valid {
|
||||
_m.SubscriptionDays = new(int)
|
||||
*_m.SubscriptionDays = int(value.Int64)
|
||||
}
|
||||
case paymentorder.FieldProviderInstanceID:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field provider_instance_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ProviderInstanceID = new(string)
|
||||
*_m.ProviderInstanceID = value.String
|
||||
}
|
||||
case paymentorder.FieldStatus:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field status", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Status = value.String
|
||||
}
|
||||
case paymentorder.FieldRefundAmount:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field refund_amount", values[i])
|
||||
} else if value.Valid {
|
||||
_m.RefundAmount = value.Float64
|
||||
}
|
||||
case paymentorder.FieldRefundReason:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field refund_reason", values[i])
|
||||
} else if value.Valid {
|
||||
_m.RefundReason = new(string)
|
||||
*_m.RefundReason = value.String
|
||||
}
|
||||
case paymentorder.FieldRefundAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field refund_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.RefundAt = new(time.Time)
|
||||
*_m.RefundAt = value.Time
|
||||
}
|
||||
case paymentorder.FieldForceRefund:
|
||||
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field force_refund", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ForceRefund = value.Bool
|
||||
}
|
||||
case paymentorder.FieldRefundRequestedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field refund_requested_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.RefundRequestedAt = new(time.Time)
|
||||
*_m.RefundRequestedAt = value.Time
|
||||
}
|
||||
case paymentorder.FieldRefundRequestReason:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field refund_request_reason", values[i])
|
||||
} else if value.Valid {
|
||||
_m.RefundRequestReason = new(string)
|
||||
*_m.RefundRequestReason = value.String
|
||||
}
|
||||
case paymentorder.FieldRefundRequestedBy:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field refund_requested_by", values[i])
|
||||
} else if value.Valid {
|
||||
_m.RefundRequestedBy = new(string)
|
||||
*_m.RefundRequestedBy = value.String
|
||||
}
|
||||
case paymentorder.FieldExpiresAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field expires_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ExpiresAt = value.Time
|
||||
}
|
||||
case paymentorder.FieldPaidAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field paid_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.PaidAt = new(time.Time)
|
||||
*_m.PaidAt = value.Time
|
||||
}
|
||||
case paymentorder.FieldCompletedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field completed_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.CompletedAt = new(time.Time)
|
||||
*_m.CompletedAt = value.Time
|
||||
}
|
||||
case paymentorder.FieldFailedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field failed_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.FailedAt = new(time.Time)
|
||||
*_m.FailedAt = value.Time
|
||||
}
|
||||
case paymentorder.FieldFailedReason:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field failed_reason", values[i])
|
||||
} else if value.Valid {
|
||||
_m.FailedReason = new(string)
|
||||
*_m.FailedReason = value.String
|
||||
}
|
||||
case paymentorder.FieldClientIP:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field client_ip", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ClientIP = value.String
|
||||
}
|
||||
case paymentorder.FieldSrcHost:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field src_host", values[i])
|
||||
} else if value.Valid {
|
||||
_m.SrcHost = value.String
|
||||
}
|
||||
case paymentorder.FieldSrcURL:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field src_url", values[i])
|
||||
} else if value.Valid {
|
||||
_m.SrcURL = new(string)
|
||||
*_m.SrcURL = value.String
|
||||
}
|
||||
case paymentorder.FieldCreatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.CreatedAt = value.Time
|
||||
}
|
||||
case paymentorder.FieldUpdatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.UpdatedAt = value.Time
|
||||
}
|
||||
default:
|
||||
_m.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns the ent.Value that was dynamically selected and assigned to the PaymentOrder.
|
||||
// This includes values selected through modifiers, order, etc.
|
||||
func (_m *PaymentOrder) Value(name string) (ent.Value, error) {
|
||||
return _m.selectValues.Get(name)
|
||||
}
|
||||
|
||||
// QueryUser queries the "user" edge of the PaymentOrder entity.
|
||||
func (_m *PaymentOrder) QueryUser() *UserQuery {
|
||||
return NewPaymentOrderClient(_m.config).QueryUser(_m)
|
||||
}
|
||||
|
||||
// Update returns a builder for updating this PaymentOrder.
|
||||
// Note that you need to call PaymentOrder.Unwrap() before calling this method if this PaymentOrder
|
||||
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||
func (_m *PaymentOrder) Update() *PaymentOrderUpdateOne {
|
||||
return NewPaymentOrderClient(_m.config).UpdateOne(_m)
|
||||
}
|
||||
|
||||
// Unwrap unwraps the PaymentOrder entity that was returned from a transaction after it was closed,
|
||||
// so that all future queries will be executed through the driver which created the transaction.
|
||||
func (_m *PaymentOrder) Unwrap() *PaymentOrder {
|
||||
_tx, ok := _m.config.driver.(*txDriver)
|
||||
if !ok {
|
||||
panic("ent: PaymentOrder is not a transactional entity")
|
||||
}
|
||||
_m.config.driver = _tx.drv
|
||||
return _m
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer.
|
||||
func (_m *PaymentOrder) String() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("PaymentOrder(")
|
||||
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
|
||||
builder.WriteString("user_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.UserID))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("user_email=")
|
||||
builder.WriteString(_m.UserEmail)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("user_name=")
|
||||
builder.WriteString(_m.UserName)
|
||||
builder.WriteString(", ")
|
||||
if v := _m.UserNotes; v != nil {
|
||||
builder.WriteString("user_notes=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("amount=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Amount))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("pay_amount=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.PayAmount))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("fee_rate=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.FeeRate))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("recharge_code=")
|
||||
builder.WriteString(_m.RechargeCode)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("payment_type=")
|
||||
builder.WriteString(_m.PaymentType)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("payment_trade_no=")
|
||||
builder.WriteString(_m.PaymentTradeNo)
|
||||
builder.WriteString(", ")
|
||||
if v := _m.PayURL; v != nil {
|
||||
builder.WriteString("pay_url=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.QrCode; v != nil {
|
||||
builder.WriteString("qr_code=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.QrCodeImg; v != nil {
|
||||
builder.WriteString("qr_code_img=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("order_type=")
|
||||
builder.WriteString(_m.OrderType)
|
||||
builder.WriteString(", ")
|
||||
if v := _m.PlanID; v != nil {
|
||||
builder.WriteString("plan_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.SubscriptionGroupID; v != nil {
|
||||
builder.WriteString("subscription_group_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.SubscriptionDays; v != nil {
|
||||
builder.WriteString("subscription_days=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.ProviderInstanceID; v != nil {
|
||||
builder.WriteString("provider_instance_id=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("status=")
|
||||
builder.WriteString(_m.Status)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("refund_amount=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.RefundAmount))
|
||||
builder.WriteString(", ")
|
||||
if v := _m.RefundReason; v != nil {
|
||||
builder.WriteString("refund_reason=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.RefundAt; v != nil {
|
||||
builder.WriteString("refund_at=")
|
||||
builder.WriteString(v.Format(time.ANSIC))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("force_refund=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.ForceRefund))
|
||||
builder.WriteString(", ")
|
||||
if v := _m.RefundRequestedAt; v != nil {
|
||||
builder.WriteString("refund_requested_at=")
|
||||
builder.WriteString(v.Format(time.ANSIC))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.RefundRequestReason; v != nil {
|
||||
builder.WriteString("refund_request_reason=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.RefundRequestedBy; v != nil {
|
||||
builder.WriteString("refund_requested_by=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("expires_at=")
|
||||
builder.WriteString(_m.ExpiresAt.Format(time.ANSIC))
|
||||
builder.WriteString(", ")
|
||||
if v := _m.PaidAt; v != nil {
|
||||
builder.WriteString("paid_at=")
|
||||
builder.WriteString(v.Format(time.ANSIC))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.CompletedAt; v != nil {
|
||||
builder.WriteString("completed_at=")
|
||||
builder.WriteString(v.Format(time.ANSIC))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.FailedAt; v != nil {
|
||||
builder.WriteString("failed_at=")
|
||||
builder.WriteString(v.Format(time.ANSIC))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.FailedReason; v != nil {
|
||||
builder.WriteString("failed_reason=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("client_ip=")
|
||||
builder.WriteString(_m.ClientIP)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("src_host=")
|
||||
builder.WriteString(_m.SrcHost)
|
||||
builder.WriteString(", ")
|
||||
if v := _m.SrcURL; v != nil {
|
||||
builder.WriteString("src_url=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("created_at=")
|
||||
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("updated_at=")
|
||||
builder.WriteString(_m.UpdatedAt.Format(time.ANSIC))
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// PaymentOrders is a parsable slice of PaymentOrder.
|
||||
type PaymentOrders []*PaymentOrder
|
||||
@@ -0,0 +1,394 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package paymentorder
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
)
|
||||
|
||||
const (
|
||||
// Label holds the string label denoting the paymentorder type in the database.
|
||||
Label = "payment_order"
|
||||
// FieldID holds the string denoting the id field in the database.
|
||||
FieldID = "id"
|
||||
// FieldUserID holds the string denoting the user_id field in the database.
|
||||
FieldUserID = "user_id"
|
||||
// FieldUserEmail holds the string denoting the user_email field in the database.
|
||||
FieldUserEmail = "user_email"
|
||||
// FieldUserName holds the string denoting the user_name field in the database.
|
||||
FieldUserName = "user_name"
|
||||
// FieldUserNotes holds the string denoting the user_notes field in the database.
|
||||
FieldUserNotes = "user_notes"
|
||||
// FieldAmount holds the string denoting the amount field in the database.
|
||||
FieldAmount = "amount"
|
||||
// FieldPayAmount holds the string denoting the pay_amount field in the database.
|
||||
FieldPayAmount = "pay_amount"
|
||||
// FieldFeeRate holds the string denoting the fee_rate field in the database.
|
||||
FieldFeeRate = "fee_rate"
|
||||
// FieldRechargeCode holds the string denoting the recharge_code field in the database.
|
||||
FieldRechargeCode = "recharge_code"
|
||||
// FieldPaymentType holds the string denoting the payment_type field in the database.
|
||||
FieldPaymentType = "payment_type"
|
||||
// FieldPaymentTradeNo holds the string denoting the payment_trade_no field in the database.
|
||||
FieldPaymentTradeNo = "payment_trade_no"
|
||||
// FieldPayURL holds the string denoting the pay_url field in the database.
|
||||
FieldPayURL = "pay_url"
|
||||
// FieldQrCode holds the string denoting the qr_code field in the database.
|
||||
FieldQrCode = "qr_code"
|
||||
// FieldQrCodeImg holds the string denoting the qr_code_img field in the database.
|
||||
FieldQrCodeImg = "qr_code_img"
|
||||
// FieldOrderType holds the string denoting the order_type field in the database.
|
||||
FieldOrderType = "order_type"
|
||||
// FieldPlanID holds the string denoting the plan_id field in the database.
|
||||
FieldPlanID = "plan_id"
|
||||
// FieldSubscriptionGroupID holds the string denoting the subscription_group_id field in the database.
|
||||
FieldSubscriptionGroupID = "subscription_group_id"
|
||||
// FieldSubscriptionDays holds the string denoting the subscription_days field in the database.
|
||||
FieldSubscriptionDays = "subscription_days"
|
||||
// FieldProviderInstanceID holds the string denoting the provider_instance_id field in the database.
|
||||
FieldProviderInstanceID = "provider_instance_id"
|
||||
// FieldStatus holds the string denoting the status field in the database.
|
||||
FieldStatus = "status"
|
||||
// FieldRefundAmount holds the string denoting the refund_amount field in the database.
|
||||
FieldRefundAmount = "refund_amount"
|
||||
// FieldRefundReason holds the string denoting the refund_reason field in the database.
|
||||
FieldRefundReason = "refund_reason"
|
||||
// FieldRefundAt holds the string denoting the refund_at field in the database.
|
||||
FieldRefundAt = "refund_at"
|
||||
// FieldForceRefund holds the string denoting the force_refund field in the database.
|
||||
FieldForceRefund = "force_refund"
|
||||
// FieldRefundRequestedAt holds the string denoting the refund_requested_at field in the database.
|
||||
FieldRefundRequestedAt = "refund_requested_at"
|
||||
// FieldRefundRequestReason holds the string denoting the refund_request_reason field in the database.
|
||||
FieldRefundRequestReason = "refund_request_reason"
|
||||
// FieldRefundRequestedBy holds the string denoting the refund_requested_by field in the database.
|
||||
FieldRefundRequestedBy = "refund_requested_by"
|
||||
// FieldExpiresAt holds the string denoting the expires_at field in the database.
|
||||
FieldExpiresAt = "expires_at"
|
||||
// FieldPaidAt holds the string denoting the paid_at field in the database.
|
||||
FieldPaidAt = "paid_at"
|
||||
// FieldCompletedAt holds the string denoting the completed_at field in the database.
|
||||
FieldCompletedAt = "completed_at"
|
||||
// FieldFailedAt holds the string denoting the failed_at field in the database.
|
||||
FieldFailedAt = "failed_at"
|
||||
// FieldFailedReason holds the string denoting the failed_reason field in the database.
|
||||
FieldFailedReason = "failed_reason"
|
||||
// FieldClientIP holds the string denoting the client_ip field in the database.
|
||||
FieldClientIP = "client_ip"
|
||||
// FieldSrcHost holds the string denoting the src_host field in the database.
|
||||
FieldSrcHost = "src_host"
|
||||
// FieldSrcURL holds the string denoting the src_url field in the database.
|
||||
FieldSrcURL = "src_url"
|
||||
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
||||
FieldCreatedAt = "created_at"
|
||||
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
|
||||
FieldUpdatedAt = "updated_at"
|
||||
// EdgeUser holds the string denoting the user edge name in mutations.
|
||||
EdgeUser = "user"
|
||||
// Table holds the table name of the paymentorder in the database.
|
||||
Table = "payment_orders"
|
||||
// UserTable is the table that holds the user relation/edge.
|
||||
UserTable = "payment_orders"
|
||||
// UserInverseTable is the table name for the User entity.
|
||||
// It exists in this package in order to avoid circular dependency with the "user" package.
|
||||
UserInverseTable = "users"
|
||||
// UserColumn is the table column denoting the user relation/edge.
|
||||
UserColumn = "user_id"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns for paymentorder fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldUserID,
|
||||
FieldUserEmail,
|
||||
FieldUserName,
|
||||
FieldUserNotes,
|
||||
FieldAmount,
|
||||
FieldPayAmount,
|
||||
FieldFeeRate,
|
||||
FieldRechargeCode,
|
||||
FieldPaymentType,
|
||||
FieldPaymentTradeNo,
|
||||
FieldPayURL,
|
||||
FieldQrCode,
|
||||
FieldQrCodeImg,
|
||||
FieldOrderType,
|
||||
FieldPlanID,
|
||||
FieldSubscriptionGroupID,
|
||||
FieldSubscriptionDays,
|
||||
FieldProviderInstanceID,
|
||||
FieldStatus,
|
||||
FieldRefundAmount,
|
||||
FieldRefundReason,
|
||||
FieldRefundAt,
|
||||
FieldForceRefund,
|
||||
FieldRefundRequestedAt,
|
||||
FieldRefundRequestReason,
|
||||
FieldRefundRequestedBy,
|
||||
FieldExpiresAt,
|
||||
FieldPaidAt,
|
||||
FieldCompletedAt,
|
||||
FieldFailedAt,
|
||||
FieldFailedReason,
|
||||
FieldClientIP,
|
||||
FieldSrcHost,
|
||||
FieldSrcURL,
|
||||
FieldCreatedAt,
|
||||
FieldUpdatedAt,
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
func ValidColumn(column string) bool {
|
||||
for i := range Columns {
|
||||
if column == Columns[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
// UserEmailValidator is a validator for the "user_email" field. It is called by the builders before save.
|
||||
UserEmailValidator func(string) error
|
||||
// UserNameValidator is a validator for the "user_name" field. It is called by the builders before save.
|
||||
UserNameValidator func(string) error
|
||||
// DefaultFeeRate holds the default value on creation for the "fee_rate" field.
|
||||
DefaultFeeRate float64
|
||||
// RechargeCodeValidator is a validator for the "recharge_code" field. It is called by the builders before save.
|
||||
RechargeCodeValidator func(string) error
|
||||
// PaymentTypeValidator is a validator for the "payment_type" field. It is called by the builders before save.
|
||||
PaymentTypeValidator func(string) error
|
||||
// PaymentTradeNoValidator is a validator for the "payment_trade_no" field. It is called by the builders before save.
|
||||
PaymentTradeNoValidator func(string) error
|
||||
// DefaultOrderType holds the default value on creation for the "order_type" field.
|
||||
DefaultOrderType string
|
||||
// OrderTypeValidator is a validator for the "order_type" field. It is called by the builders before save.
|
||||
OrderTypeValidator func(string) error
|
||||
// ProviderInstanceIDValidator is a validator for the "provider_instance_id" field. It is called by the builders before save.
|
||||
ProviderInstanceIDValidator func(string) error
|
||||
// DefaultStatus holds the default value on creation for the "status" field.
|
||||
DefaultStatus string
|
||||
// StatusValidator is a validator for the "status" field. It is called by the builders before save.
|
||||
StatusValidator func(string) error
|
||||
// DefaultRefundAmount holds the default value on creation for the "refund_amount" field.
|
||||
DefaultRefundAmount float64
|
||||
// DefaultForceRefund holds the default value on creation for the "force_refund" field.
|
||||
DefaultForceRefund bool
|
||||
// RefundRequestedByValidator is a validator for the "refund_requested_by" field. It is called by the builders before save.
|
||||
RefundRequestedByValidator func(string) error
|
||||
// ClientIPValidator is a validator for the "client_ip" field. It is called by the builders before save.
|
||||
ClientIPValidator func(string) error
|
||||
// SrcHostValidator is a validator for the "src_host" field. It is called by the builders before save.
|
||||
SrcHostValidator func(string) error
|
||||
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
||||
DefaultCreatedAt func() time.Time
|
||||
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
|
||||
DefaultUpdatedAt func() time.Time
|
||||
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
|
||||
UpdateDefaultUpdatedAt func() time.Time
|
||||
)
|
||||
|
||||
// OrderOption defines the ordering options for the PaymentOrder queries.
|
||||
type OrderOption func(*sql.Selector)
|
||||
|
||||
// ByID orders the results by the id field.
|
||||
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUserID orders the results by the user_id field.
|
||||
func ByUserID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUserID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUserEmail orders the results by the user_email field.
|
||||
func ByUserEmail(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUserEmail, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUserName orders the results by the user_name field.
|
||||
func ByUserName(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUserName, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUserNotes orders the results by the user_notes field.
|
||||
func ByUserNotes(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUserNotes, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByAmount orders the results by the amount field.
|
||||
func ByAmount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldAmount, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPayAmount orders the results by the pay_amount field.
|
||||
func ByPayAmount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPayAmount, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByFeeRate orders the results by the fee_rate field.
|
||||
func ByFeeRate(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldFeeRate, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRechargeCode orders the results by the recharge_code field.
|
||||
func ByRechargeCode(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRechargeCode, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPaymentType orders the results by the payment_type field.
|
||||
func ByPaymentType(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPaymentType, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPaymentTradeNo orders the results by the payment_trade_no field.
|
||||
func ByPaymentTradeNo(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPaymentTradeNo, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPayURL orders the results by the pay_url field.
|
||||
func ByPayURL(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPayURL, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByQrCode orders the results by the qr_code field.
|
||||
func ByQrCode(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldQrCode, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByQrCodeImg orders the results by the qr_code_img field.
|
||||
func ByQrCodeImg(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldQrCodeImg, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByOrderType orders the results by the order_type field.
|
||||
func ByOrderType(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldOrderType, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPlanID orders the results by the plan_id field.
|
||||
func ByPlanID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPlanID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySubscriptionGroupID orders the results by the subscription_group_id field.
|
||||
func BySubscriptionGroupID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSubscriptionGroupID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySubscriptionDays orders the results by the subscription_days field.
|
||||
func BySubscriptionDays(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSubscriptionDays, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByProviderInstanceID orders the results by the provider_instance_id field.
|
||||
func ByProviderInstanceID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldProviderInstanceID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByStatus orders the results by the status field.
|
||||
func ByStatus(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldStatus, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRefundAmount orders the results by the refund_amount field.
|
||||
func ByRefundAmount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRefundAmount, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRefundReason orders the results by the refund_reason field.
|
||||
func ByRefundReason(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRefundReason, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRefundAt orders the results by the refund_at field.
|
||||
func ByRefundAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRefundAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByForceRefund orders the results by the force_refund field.
|
||||
func ByForceRefund(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldForceRefund, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRefundRequestedAt orders the results by the refund_requested_at field.
|
||||
func ByRefundRequestedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRefundRequestedAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRefundRequestReason orders the results by the refund_request_reason field.
|
||||
func ByRefundRequestReason(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRefundRequestReason, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRefundRequestedBy orders the results by the refund_requested_by field.
|
||||
func ByRefundRequestedBy(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRefundRequestedBy, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByExpiresAt orders the results by the expires_at field.
|
||||
func ByExpiresAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldExpiresAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPaidAt orders the results by the paid_at field.
|
||||
func ByPaidAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPaidAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCompletedAt orders the results by the completed_at field.
|
||||
func ByCompletedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCompletedAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByFailedAt orders the results by the failed_at field.
|
||||
func ByFailedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldFailedAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByFailedReason orders the results by the failed_reason field.
|
||||
func ByFailedReason(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldFailedReason, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByClientIP orders the results by the client_ip field.
|
||||
func ByClientIP(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldClientIP, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySrcHost orders the results by the src_host field.
|
||||
func BySrcHost(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSrcHost, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySrcURL orders the results by the src_url field.
|
||||
func BySrcURL(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSrcURL, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCreatedAt orders the results by the created_at field.
|
||||
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUpdatedAt orders the results by the updated_at field.
|
||||
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUserField orders the results by user field.
|
||||
func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...))
|
||||
}
|
||||
}
|
||||
func newUserStep() *sqlgraph.Step {
|
||||
return sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(UserInverseTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
|
||||
)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// PaymentOrderDelete is the builder for deleting a PaymentOrder entity.
|
||||
type PaymentOrderDelete struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *PaymentOrderMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentOrderDelete builder.
|
||||
func (_d *PaymentOrderDelete) Where(ps ...predicate.PaymentOrder) *PaymentOrderDelete {
|
||||
_d.mutation.Where(ps...)
|
||||
return _d
|
||||
}
|
||||
|
||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||
func (_d *PaymentOrderDelete) Exec(ctx context.Context) (int, error) {
|
||||
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_d *PaymentOrderDelete) ExecX(ctx context.Context) int {
|
||||
n, err := _d.Exec(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (_d *PaymentOrderDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
_spec := sqlgraph.NewDeleteSpec(paymentorder.Table, sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64))
|
||||
if ps := _d.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
|
||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
_d.mutation.done = true
|
||||
return affected, err
|
||||
}
|
||||
|
||||
// PaymentOrderDeleteOne is the builder for deleting a single PaymentOrder entity.
|
||||
type PaymentOrderDeleteOne struct {
|
||||
_d *PaymentOrderDelete
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentOrderDelete builder.
|
||||
func (_d *PaymentOrderDeleteOne) Where(ps ...predicate.PaymentOrder) *PaymentOrderDeleteOne {
|
||||
_d._d.mutation.Where(ps...)
|
||||
return _d
|
||||
}
|
||||
|
||||
// Exec executes the deletion query.
|
||||
func (_d *PaymentOrderDeleteOne) Exec(ctx context.Context) error {
|
||||
n, err := _d._d.Exec(ctx)
|
||||
switch {
|
||||
case err != nil:
|
||||
return err
|
||||
case n == 0:
|
||||
return &NotFoundError{paymentorder.Label}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_d *PaymentOrderDeleteOne) ExecX(ctx context.Context) {
|
||||
if err := _d.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,643 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
"github.com/Wei-Shaw/sub2api/ent/user"
|
||||
)
|
||||
|
||||
// PaymentOrderQuery is the builder for querying PaymentOrder entities.
|
||||
type PaymentOrderQuery struct {
|
||||
config
|
||||
ctx *QueryContext
|
||||
order []paymentorder.OrderOption
|
||||
inters []Interceptor
|
||||
predicates []predicate.PaymentOrder
|
||||
withUser *UserQuery
|
||||
modifiers []func(*sql.Selector)
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
}
|
||||
|
||||
// Where adds a new predicate for the PaymentOrderQuery builder.
|
||||
func (_q *PaymentOrderQuery) Where(ps ...predicate.PaymentOrder) *PaymentOrderQuery {
|
||||
_q.predicates = append(_q.predicates, ps...)
|
||||
return _q
|
||||
}
|
||||
|
||||
// Limit the number of records to be returned by this query.
|
||||
func (_q *PaymentOrderQuery) Limit(limit int) *PaymentOrderQuery {
|
||||
_q.ctx.Limit = &limit
|
||||
return _q
|
||||
}
|
||||
|
||||
// Offset to start from.
|
||||
func (_q *PaymentOrderQuery) Offset(offset int) *PaymentOrderQuery {
|
||||
_q.ctx.Offset = &offset
|
||||
return _q
|
||||
}
|
||||
|
||||
// Unique configures the query builder to filter duplicate records on query.
|
||||
// By default, unique is set to true, and can be disabled using this method.
|
||||
func (_q *PaymentOrderQuery) Unique(unique bool) *PaymentOrderQuery {
|
||||
_q.ctx.Unique = &unique
|
||||
return _q
|
||||
}
|
||||
|
||||
// Order specifies how the records should be ordered.
|
||||
func (_q *PaymentOrderQuery) Order(o ...paymentorder.OrderOption) *PaymentOrderQuery {
|
||||
_q.order = append(_q.order, o...)
|
||||
return _q
|
||||
}
|
||||
|
||||
// QueryUser chains the current query on the "user" edge.
|
||||
func (_q *PaymentOrderQuery) QueryUser() *UserQuery {
|
||||
query := (&UserClient{config: _q.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector := _q.sqlQuery(ctx)
|
||||
if err := selector.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(paymentorder.Table, paymentorder.FieldID, selector),
|
||||
sqlgraph.To(user.Table, user.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, paymentorder.UserTable, paymentorder.UserColumn),
|
||||
)
|
||||
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
|
||||
return fromU, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// First returns the first PaymentOrder entity from the query.
|
||||
// Returns a *NotFoundError when no PaymentOrder was found.
|
||||
func (_q *PaymentOrderQuery) First(ctx context.Context) (*PaymentOrder, error) {
|
||||
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nil, &NotFoundError{paymentorder.Label}
|
||||
}
|
||||
return nodes[0], nil
|
||||
}
|
||||
|
||||
// FirstX is like First, but panics if an error occurs.
|
||||
func (_q *PaymentOrderQuery) FirstX(ctx context.Context) *PaymentOrder {
|
||||
node, err := _q.First(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// FirstID returns the first PaymentOrder ID from the query.
|
||||
// Returns a *NotFoundError when no PaymentOrder ID was found.
|
||||
func (_q *PaymentOrderQuery) FirstID(ctx context.Context) (id int64, err error) {
|
||||
var ids []int64
|
||||
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
err = &NotFoundError{paymentorder.Label}
|
||||
return
|
||||
}
|
||||
return ids[0], nil
|
||||
}
|
||||
|
||||
// FirstIDX is like FirstID, but panics if an error occurs.
|
||||
func (_q *PaymentOrderQuery) FirstIDX(ctx context.Context) int64 {
|
||||
id, err := _q.FirstID(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// Only returns a single PaymentOrder entity found by the query, ensuring it only returns one.
|
||||
// Returns a *NotSingularError when more than one PaymentOrder entity is found.
|
||||
// Returns a *NotFoundError when no PaymentOrder entities are found.
|
||||
func (_q *PaymentOrderQuery) Only(ctx context.Context) (*PaymentOrder, error) {
|
||||
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch len(nodes) {
|
||||
case 1:
|
||||
return nodes[0], nil
|
||||
case 0:
|
||||
return nil, &NotFoundError{paymentorder.Label}
|
||||
default:
|
||||
return nil, &NotSingularError{paymentorder.Label}
|
||||
}
|
||||
}
|
||||
|
||||
// OnlyX is like Only, but panics if an error occurs.
|
||||
func (_q *PaymentOrderQuery) OnlyX(ctx context.Context) *PaymentOrder {
|
||||
node, err := _q.Only(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// OnlyID is like Only, but returns the only PaymentOrder ID in the query.
|
||||
// Returns a *NotSingularError when more than one PaymentOrder ID is found.
|
||||
// Returns a *NotFoundError when no entities are found.
|
||||
func (_q *PaymentOrderQuery) OnlyID(ctx context.Context) (id int64, err error) {
|
||||
var ids []int64
|
||||
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
|
||||
return
|
||||
}
|
||||
switch len(ids) {
|
||||
case 1:
|
||||
id = ids[0]
|
||||
case 0:
|
||||
err = &NotFoundError{paymentorder.Label}
|
||||
default:
|
||||
err = &NotSingularError{paymentorder.Label}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OnlyIDX is like OnlyID, but panics if an error occurs.
|
||||
func (_q *PaymentOrderQuery) OnlyIDX(ctx context.Context) int64 {
|
||||
id, err := _q.OnlyID(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// All executes the query and returns a list of PaymentOrders.
|
||||
func (_q *PaymentOrderQuery) All(ctx context.Context) ([]*PaymentOrder, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
qr := querierAll[[]*PaymentOrder, *PaymentOrderQuery]()
|
||||
return withInterceptors[[]*PaymentOrder](ctx, _q, qr, _q.inters)
|
||||
}
|
||||
|
||||
// AllX is like All, but panics if an error occurs.
|
||||
func (_q *PaymentOrderQuery) AllX(ctx context.Context) []*PaymentOrder {
|
||||
nodes, err := _q.All(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
// IDs executes the query and returns a list of PaymentOrder IDs.
|
||||
func (_q *PaymentOrderQuery) IDs(ctx context.Context) (ids []int64, err error) {
|
||||
if _q.ctx.Unique == nil && _q.path != nil {
|
||||
_q.Unique(true)
|
||||
}
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
|
||||
if err = _q.Select(paymentorder.FieldID).Scan(ctx, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// IDsX is like IDs, but panics if an error occurs.
|
||||
func (_q *PaymentOrderQuery) IDsX(ctx context.Context) []int64 {
|
||||
ids, err := _q.IDs(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// Count returns the count of the given query.
|
||||
func (_q *PaymentOrderQuery) Count(ctx context.Context) (int, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return withInterceptors[int](ctx, _q, querierCount[*PaymentOrderQuery](), _q.inters)
|
||||
}
|
||||
|
||||
// CountX is like Count, but panics if an error occurs.
|
||||
func (_q *PaymentOrderQuery) CountX(ctx context.Context) int {
|
||||
count, err := _q.Count(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Exist returns true if the query has elements in the graph.
|
||||
func (_q *PaymentOrderQuery) Exist(ctx context.Context) (bool, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
|
||||
switch _, err := _q.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExistX is like Exist, but panics if an error occurs.
|
||||
func (_q *PaymentOrderQuery) ExistX(ctx context.Context) bool {
|
||||
exist, err := _q.Exist(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return exist
|
||||
}
|
||||
|
||||
// Clone returns a duplicate of the PaymentOrderQuery builder, including all associated steps. It can be
|
||||
// used to prepare common query builders and use them differently after the clone is made.
|
||||
func (_q *PaymentOrderQuery) Clone() *PaymentOrderQuery {
|
||||
if _q == nil {
|
||||
return nil
|
||||
}
|
||||
return &PaymentOrderQuery{
|
||||
config: _q.config,
|
||||
ctx: _q.ctx.Clone(),
|
||||
order: append([]paymentorder.OrderOption{}, _q.order...),
|
||||
inters: append([]Interceptor{}, _q.inters...),
|
||||
predicates: append([]predicate.PaymentOrder{}, _q.predicates...),
|
||||
withUser: _q.withUser.Clone(),
|
||||
// clone intermediate query.
|
||||
sql: _q.sql.Clone(),
|
||||
path: _q.path,
|
||||
}
|
||||
}
|
||||
|
||||
// WithUser tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "user" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (_q *PaymentOrderQuery) WithUser(opts ...func(*UserQuery)) *PaymentOrderQuery {
|
||||
query := (&UserClient{config: _q.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
_q.withUser = query
|
||||
return _q
|
||||
}
|
||||
|
||||
// GroupBy is used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// UserID int64 `json:"user_id,omitempty"`
|
||||
// Count int `json:"count,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.PaymentOrder.Query().
|
||||
// GroupBy(paymentorder.FieldUserID).
|
||||
// Aggregate(ent.Count()).
|
||||
// Scan(ctx, &v)
|
||||
func (_q *PaymentOrderQuery) GroupBy(field string, fields ...string) *PaymentOrderGroupBy {
|
||||
_q.ctx.Fields = append([]string{field}, fields...)
|
||||
grbuild := &PaymentOrderGroupBy{build: _q}
|
||||
grbuild.flds = &_q.ctx.Fields
|
||||
grbuild.label = paymentorder.Label
|
||||
grbuild.scan = grbuild.Scan
|
||||
return grbuild
|
||||
}
|
||||
|
||||
// Select allows the selection one or more fields/columns for the given query,
|
||||
// instead of selecting all fields in the entity.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// UserID int64 `json:"user_id,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.PaymentOrder.Query().
|
||||
// Select(paymentorder.FieldUserID).
|
||||
// Scan(ctx, &v)
|
||||
func (_q *PaymentOrderQuery) Select(fields ...string) *PaymentOrderSelect {
|
||||
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
|
||||
sbuild := &PaymentOrderSelect{PaymentOrderQuery: _q}
|
||||
sbuild.label = paymentorder.Label
|
||||
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
|
||||
return sbuild
|
||||
}
|
||||
|
||||
// Aggregate returns a PaymentOrderSelect configured with the given aggregations.
|
||||
func (_q *PaymentOrderQuery) Aggregate(fns ...AggregateFunc) *PaymentOrderSelect {
|
||||
return _q.Select().Aggregate(fns...)
|
||||
}
|
||||
|
||||
func (_q *PaymentOrderQuery) prepareQuery(ctx context.Context) error {
|
||||
for _, inter := range _q.inters {
|
||||
if inter == nil {
|
||||
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
|
||||
}
|
||||
if trv, ok := inter.(Traverser); ok {
|
||||
if err := trv.Traverse(ctx, _q); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range _q.ctx.Fields {
|
||||
if !paymentorder.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
}
|
||||
if _q.path != nil {
|
||||
prev, err := _q.path(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_q.sql = prev
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_q *PaymentOrderQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*PaymentOrder, error) {
|
||||
var (
|
||||
nodes = []*PaymentOrder{}
|
||||
_spec = _q.querySpec()
|
||||
loadedTypes = [1]bool{
|
||||
_q.withUser != nil,
|
||||
}
|
||||
)
|
||||
_spec.ScanValues = func(columns []string) ([]any, error) {
|
||||
return (*PaymentOrder).scanValues(nil, columns)
|
||||
}
|
||||
_spec.Assign = func(columns []string, values []any) error {
|
||||
node := &PaymentOrder{config: _q.config}
|
||||
nodes = append(nodes, node)
|
||||
node.Edges.loadedTypes = loadedTypes
|
||||
return node.assignValues(columns, values)
|
||||
}
|
||||
if len(_q.modifiers) > 0 {
|
||||
_spec.Modifiers = _q.modifiers
|
||||
}
|
||||
for i := range hooks {
|
||||
hooks[i](ctx, _spec)
|
||||
}
|
||||
if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nodes, nil
|
||||
}
|
||||
if query := _q.withUser; query != nil {
|
||||
if err := _q.loadUser(ctx, query, nodes, nil,
|
||||
func(n *PaymentOrder, e *User) { n.Edges.User = e }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (_q *PaymentOrderQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*PaymentOrder, init func(*PaymentOrder), assign func(*PaymentOrder, *User)) error {
|
||||
ids := make([]int64, 0, len(nodes))
|
||||
nodeids := make(map[int64][]*PaymentOrder)
|
||||
for i := range nodes {
|
||||
fk := nodes[i].UserID
|
||||
if _, ok := nodeids[fk]; !ok {
|
||||
ids = append(ids, fk)
|
||||
}
|
||||
nodeids[fk] = append(nodeids[fk], nodes[i])
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
query.Where(user.IDIn(ids...))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := nodeids[n.ID]
|
||||
if !ok {
|
||||
return fmt.Errorf(`unexpected foreign-key "user_id" returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
assign(nodes[i], n)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_q *PaymentOrderQuery) sqlCount(ctx context.Context) (int, error) {
|
||||
_spec := _q.querySpec()
|
||||
if len(_q.modifiers) > 0 {
|
||||
_spec.Modifiers = _q.modifiers
|
||||
}
|
||||
_spec.Node.Columns = _q.ctx.Fields
|
||||
if len(_q.ctx.Fields) > 0 {
|
||||
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
|
||||
}
|
||||
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
|
||||
}
|
||||
|
||||
func (_q *PaymentOrderQuery) querySpec() *sqlgraph.QuerySpec {
|
||||
_spec := sqlgraph.NewQuerySpec(paymentorder.Table, paymentorder.Columns, sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64))
|
||||
_spec.From = _q.sql
|
||||
if unique := _q.ctx.Unique; unique != nil {
|
||||
_spec.Unique = *unique
|
||||
} else if _q.path != nil {
|
||||
_spec.Unique = true
|
||||
}
|
||||
if fields := _q.ctx.Fields; len(fields) > 0 {
|
||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, paymentorder.FieldID)
|
||||
for i := range fields {
|
||||
if fields[i] != paymentorder.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
|
||||
}
|
||||
}
|
||||
if _q.withUser != nil {
|
||||
_spec.Node.AddColumnOnce(paymentorder.FieldUserID)
|
||||
}
|
||||
}
|
||||
if ps := _q.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if limit := _q.ctx.Limit; limit != nil {
|
||||
_spec.Limit = *limit
|
||||
}
|
||||
if offset := _q.ctx.Offset; offset != nil {
|
||||
_spec.Offset = *offset
|
||||
}
|
||||
if ps := _q.order; len(ps) > 0 {
|
||||
_spec.Order = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
return _spec
|
||||
}
|
||||
|
||||
func (_q *PaymentOrderQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||
builder := sql.Dialect(_q.driver.Dialect())
|
||||
t1 := builder.Table(paymentorder.Table)
|
||||
columns := _q.ctx.Fields
|
||||
if len(columns) == 0 {
|
||||
columns = paymentorder.Columns
|
||||
}
|
||||
selector := builder.Select(t1.Columns(columns...)...).From(t1)
|
||||
if _q.sql != nil {
|
||||
selector = _q.sql
|
||||
selector.Select(selector.Columns(columns...)...)
|
||||
}
|
||||
if _q.ctx.Unique != nil && *_q.ctx.Unique {
|
||||
selector.Distinct()
|
||||
}
|
||||
for _, m := range _q.modifiers {
|
||||
m(selector)
|
||||
}
|
||||
for _, p := range _q.predicates {
|
||||
p(selector)
|
||||
}
|
||||
for _, p := range _q.order {
|
||||
p(selector)
|
||||
}
|
||||
if offset := _q.ctx.Offset; offset != nil {
|
||||
// limit is mandatory for offset clause. We start
|
||||
// with default value, and override it below if needed.
|
||||
selector.Offset(*offset).Limit(math.MaxInt32)
|
||||
}
|
||||
if limit := _q.ctx.Limit; limit != nil {
|
||||
selector.Limit(*limit)
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
// ForUpdate locks the selected rows against concurrent updates, and prevent them from being
|
||||
// updated, deleted or "selected ... for update" by other sessions, until the transaction is
|
||||
// either committed or rolled-back.
|
||||
func (_q *PaymentOrderQuery) ForUpdate(opts ...sql.LockOption) *PaymentOrderQuery {
|
||||
if _q.driver.Dialect() == dialect.Postgres {
|
||||
_q.Unique(false)
|
||||
}
|
||||
_q.modifiers = append(_q.modifiers, func(s *sql.Selector) {
|
||||
s.ForUpdate(opts...)
|
||||
})
|
||||
return _q
|
||||
}
|
||||
|
||||
// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock
|
||||
// on any rows that are read. Other sessions can read the rows, but cannot modify them
|
||||
// until your transaction commits.
|
||||
func (_q *PaymentOrderQuery) ForShare(opts ...sql.LockOption) *PaymentOrderQuery {
|
||||
if _q.driver.Dialect() == dialect.Postgres {
|
||||
_q.Unique(false)
|
||||
}
|
||||
_q.modifiers = append(_q.modifiers, func(s *sql.Selector) {
|
||||
s.ForShare(opts...)
|
||||
})
|
||||
return _q
|
||||
}
|
||||
|
||||
// PaymentOrderGroupBy is the group-by builder for PaymentOrder entities.
|
||||
type PaymentOrderGroupBy struct {
|
||||
selector
|
||||
build *PaymentOrderQuery
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the group-by query.
|
||||
func (_g *PaymentOrderGroupBy) Aggregate(fns ...AggregateFunc) *PaymentOrderGroupBy {
|
||||
_g.fns = append(_g.fns, fns...)
|
||||
return _g
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (_g *PaymentOrderGroupBy) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
|
||||
if err := _g.build.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*PaymentOrderQuery, *PaymentOrderGroupBy](ctx, _g.build, _g, _g.build.inters, v)
|
||||
}
|
||||
|
||||
func (_g *PaymentOrderGroupBy) sqlScan(ctx context.Context, root *PaymentOrderQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx).Select()
|
||||
aggregation := make([]string, 0, len(_g.fns))
|
||||
for _, fn := range _g.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
if len(selector.SelectedColumns()) == 0 {
|
||||
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
|
||||
for _, f := range *_g.flds {
|
||||
columns = append(columns, selector.C(f))
|
||||
}
|
||||
columns = append(columns, aggregation...)
|
||||
selector.Select(columns...)
|
||||
}
|
||||
selector.GroupBy(selector.Columns(*_g.flds...)...)
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
// PaymentOrderSelect is the builder for selecting fields of PaymentOrder entities.
|
||||
type PaymentOrderSelect struct {
|
||||
*PaymentOrderQuery
|
||||
selector
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the selector query.
|
||||
func (_s *PaymentOrderSelect) Aggregate(fns ...AggregateFunc) *PaymentOrderSelect {
|
||||
_s.fns = append(_s.fns, fns...)
|
||||
return _s
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (_s *PaymentOrderSelect) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
|
||||
if err := _s.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*PaymentOrderQuery, *PaymentOrderSelect](ctx, _s.PaymentOrderQuery, _s, _s.inters, v)
|
||||
}
|
||||
|
||||
func (_s *PaymentOrderSelect) sqlScan(ctx context.Context, root *PaymentOrderQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx)
|
||||
aggregation := make([]string, 0, len(_s.fns))
|
||||
for _, fn := range _s.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
switch n := len(*_s.selector.flds); {
|
||||
case n == 0 && len(aggregation) > 0:
|
||||
selector.Select(aggregation...)
|
||||
case n != 0 && len(aggregation) > 0:
|
||||
selector.AppendSelect(aggregation...)
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := _s.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,207 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
)
|
||||
|
||||
// PaymentProviderInstance is the model entity for the PaymentProviderInstance schema.
|
||||
type PaymentProviderInstance struct {
|
||||
config `json:"-"`
|
||||
// ID of the ent.
|
||||
ID int64 `json:"id,omitempty"`
|
||||
// ProviderKey holds the value of the "provider_key" field.
|
||||
ProviderKey string `json:"provider_key,omitempty"`
|
||||
// Name holds the value of the "name" field.
|
||||
Name string `json:"name,omitempty"`
|
||||
// Config holds the value of the "config" field.
|
||||
Config string `json:"config,omitempty"`
|
||||
// SupportedTypes holds the value of the "supported_types" field.
|
||||
SupportedTypes string `json:"supported_types,omitempty"`
|
||||
// Enabled holds the value of the "enabled" field.
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
// SortOrder holds the value of the "sort_order" field.
|
||||
SortOrder int `json:"sort_order,omitempty"`
|
||||
// Limits holds the value of the "limits" field.
|
||||
Limits string `json:"limits,omitempty"`
|
||||
// RefundEnabled holds the value of the "refund_enabled" field.
|
||||
RefundEnabled bool `json:"refund_enabled,omitempty"`
|
||||
// CreatedAt holds the value of the "created_at" field.
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
// UpdatedAt holds the value of the "updated_at" field.
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
selectValues sql.SelectValues
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*PaymentProviderInstance) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case paymentproviderinstance.FieldEnabled, paymentproviderinstance.FieldRefundEnabled:
|
||||
values[i] = new(sql.NullBool)
|
||||
case paymentproviderinstance.FieldID, paymentproviderinstance.FieldSortOrder:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case paymentproviderinstance.FieldProviderKey, paymentproviderinstance.FieldName, paymentproviderinstance.FieldConfig, paymentproviderinstance.FieldSupportedTypes, paymentproviderinstance.FieldLimits:
|
||||
values[i] = new(sql.NullString)
|
||||
case paymentproviderinstance.FieldCreatedAt, paymentproviderinstance.FieldUpdatedAt:
|
||||
values[i] = new(sql.NullTime)
|
||||
default:
|
||||
values[i] = new(sql.UnknownType)
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the PaymentProviderInstance fields.
|
||||
func (_m *PaymentProviderInstance) assignValues(columns []string, values []any) error {
|
||||
if m, n := len(values), len(columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case paymentproviderinstance.FieldID:
|
||||
value, ok := values[i].(*sql.NullInt64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field id", value)
|
||||
}
|
||||
_m.ID = int64(value.Int64)
|
||||
case paymentproviderinstance.FieldProviderKey:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field provider_key", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ProviderKey = value.String
|
||||
}
|
||||
case paymentproviderinstance.FieldName:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field name", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Name = value.String
|
||||
}
|
||||
case paymentproviderinstance.FieldConfig:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field config", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Config = value.String
|
||||
}
|
||||
case paymentproviderinstance.FieldSupportedTypes:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field supported_types", values[i])
|
||||
} else if value.Valid {
|
||||
_m.SupportedTypes = value.String
|
||||
}
|
||||
case paymentproviderinstance.FieldEnabled:
|
||||
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field enabled", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Enabled = value.Bool
|
||||
}
|
||||
case paymentproviderinstance.FieldSortOrder:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field sort_order", values[i])
|
||||
} else if value.Valid {
|
||||
_m.SortOrder = int(value.Int64)
|
||||
}
|
||||
case paymentproviderinstance.FieldLimits:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field limits", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Limits = value.String
|
||||
}
|
||||
case paymentproviderinstance.FieldRefundEnabled:
|
||||
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field refund_enabled", values[i])
|
||||
} else if value.Valid {
|
||||
_m.RefundEnabled = value.Bool
|
||||
}
|
||||
case paymentproviderinstance.FieldCreatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.CreatedAt = value.Time
|
||||
}
|
||||
case paymentproviderinstance.FieldUpdatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.UpdatedAt = value.Time
|
||||
}
|
||||
default:
|
||||
_m.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns the ent.Value that was dynamically selected and assigned to the PaymentProviderInstance.
|
||||
// This includes values selected through modifiers, order, etc.
|
||||
func (_m *PaymentProviderInstance) Value(name string) (ent.Value, error) {
|
||||
return _m.selectValues.Get(name)
|
||||
}
|
||||
|
||||
// Update returns a builder for updating this PaymentProviderInstance.
|
||||
// Note that you need to call PaymentProviderInstance.Unwrap() before calling this method if this PaymentProviderInstance
|
||||
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||
func (_m *PaymentProviderInstance) Update() *PaymentProviderInstanceUpdateOne {
|
||||
return NewPaymentProviderInstanceClient(_m.config).UpdateOne(_m)
|
||||
}
|
||||
|
||||
// Unwrap unwraps the PaymentProviderInstance entity that was returned from a transaction after it was closed,
|
||||
// so that all future queries will be executed through the driver which created the transaction.
|
||||
func (_m *PaymentProviderInstance) Unwrap() *PaymentProviderInstance {
|
||||
_tx, ok := _m.config.driver.(*txDriver)
|
||||
if !ok {
|
||||
panic("ent: PaymentProviderInstance is not a transactional entity")
|
||||
}
|
||||
_m.config.driver = _tx.drv
|
||||
return _m
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer.
|
||||
func (_m *PaymentProviderInstance) String() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("PaymentProviderInstance(")
|
||||
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
|
||||
builder.WriteString("provider_key=")
|
||||
builder.WriteString(_m.ProviderKey)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("name=")
|
||||
builder.WriteString(_m.Name)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("config=")
|
||||
builder.WriteString(_m.Config)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("supported_types=")
|
||||
builder.WriteString(_m.SupportedTypes)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("enabled=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Enabled))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("sort_order=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.SortOrder))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("limits=")
|
||||
builder.WriteString(_m.Limits)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("refund_enabled=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.RefundEnabled))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("created_at=")
|
||||
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("updated_at=")
|
||||
builder.WriteString(_m.UpdatedAt.Format(time.ANSIC))
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// PaymentProviderInstances is a parsable slice of PaymentProviderInstance.
|
||||
type PaymentProviderInstances []*PaymentProviderInstance
|
||||
@@ -0,0 +1,148 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package paymentproviderinstance
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
)
|
||||
|
||||
const (
|
||||
// Label holds the string label denoting the paymentproviderinstance type in the database.
|
||||
Label = "payment_provider_instance"
|
||||
// FieldID holds the string denoting the id field in the database.
|
||||
FieldID = "id"
|
||||
// FieldProviderKey holds the string denoting the provider_key field in the database.
|
||||
FieldProviderKey = "provider_key"
|
||||
// FieldName holds the string denoting the name field in the database.
|
||||
FieldName = "name"
|
||||
// FieldConfig holds the string denoting the config field in the database.
|
||||
FieldConfig = "config"
|
||||
// FieldSupportedTypes holds the string denoting the supported_types field in the database.
|
||||
FieldSupportedTypes = "supported_types"
|
||||
// FieldEnabled holds the string denoting the enabled field in the database.
|
||||
FieldEnabled = "enabled"
|
||||
// FieldSortOrder holds the string denoting the sort_order field in the database.
|
||||
FieldSortOrder = "sort_order"
|
||||
// FieldLimits holds the string denoting the limits field in the database.
|
||||
FieldLimits = "limits"
|
||||
// FieldRefundEnabled holds the string denoting the refund_enabled field in the database.
|
||||
FieldRefundEnabled = "refund_enabled"
|
||||
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
||||
FieldCreatedAt = "created_at"
|
||||
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
|
||||
FieldUpdatedAt = "updated_at"
|
||||
// Table holds the table name of the paymentproviderinstance in the database.
|
||||
Table = "payment_provider_instances"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns for paymentproviderinstance fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldProviderKey,
|
||||
FieldName,
|
||||
FieldConfig,
|
||||
FieldSupportedTypes,
|
||||
FieldEnabled,
|
||||
FieldSortOrder,
|
||||
FieldLimits,
|
||||
FieldRefundEnabled,
|
||||
FieldCreatedAt,
|
||||
FieldUpdatedAt,
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
func ValidColumn(column string) bool {
|
||||
for i := range Columns {
|
||||
if column == Columns[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
// ProviderKeyValidator is a validator for the "provider_key" field. It is called by the builders before save.
|
||||
ProviderKeyValidator func(string) error
|
||||
// DefaultName holds the default value on creation for the "name" field.
|
||||
DefaultName string
|
||||
// NameValidator is a validator for the "name" field. It is called by the builders before save.
|
||||
NameValidator func(string) error
|
||||
// DefaultSupportedTypes holds the default value on creation for the "supported_types" field.
|
||||
DefaultSupportedTypes string
|
||||
// SupportedTypesValidator is a validator for the "supported_types" field. It is called by the builders before save.
|
||||
SupportedTypesValidator func(string) error
|
||||
// DefaultEnabled holds the default value on creation for the "enabled" field.
|
||||
DefaultEnabled bool
|
||||
// DefaultSortOrder holds the default value on creation for the "sort_order" field.
|
||||
DefaultSortOrder int
|
||||
// DefaultLimits holds the default value on creation for the "limits" field.
|
||||
DefaultLimits string
|
||||
// DefaultRefundEnabled holds the default value on creation for the "refund_enabled" field.
|
||||
DefaultRefundEnabled bool
|
||||
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
||||
DefaultCreatedAt func() time.Time
|
||||
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
|
||||
DefaultUpdatedAt func() time.Time
|
||||
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
|
||||
UpdateDefaultUpdatedAt func() time.Time
|
||||
)
|
||||
|
||||
// OrderOption defines the ordering options for the PaymentProviderInstance queries.
|
||||
type OrderOption func(*sql.Selector)
|
||||
|
||||
// ByID orders the results by the id field.
|
||||
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByProviderKey orders the results by the provider_key field.
|
||||
func ByProviderKey(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldProviderKey, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByName orders the results by the name field.
|
||||
func ByName(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldName, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByConfig orders the results by the config field.
|
||||
func ByConfig(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldConfig, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySupportedTypes orders the results by the supported_types field.
|
||||
func BySupportedTypes(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSupportedTypes, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByEnabled orders the results by the enabled field.
|
||||
func ByEnabled(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldEnabled, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySortOrder orders the results by the sort_order field.
|
||||
func BySortOrder(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSortOrder, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByLimits orders the results by the limits field.
|
||||
func ByLimits(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldLimits, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRefundEnabled orders the results by the refund_enabled field.
|
||||
func ByRefundEnabled(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRefundEnabled, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCreatedAt orders the results by the created_at field.
|
||||
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUpdatedAt orders the results by the updated_at field.
|
||||
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
|
||||
}
|
||||
@@ -0,0 +1,585 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package paymentproviderinstance
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// ID filters vertices based on their ID field.
|
||||
func ID(id int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDEQ applies the EQ predicate on the ID field.
|
||||
func IDEQ(id int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDNEQ applies the NEQ predicate on the ID field.
|
||||
func IDNEQ(id int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDIn applies the In predicate on the ID field.
|
||||
func IDIn(ids ...int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDNotIn applies the NotIn predicate on the ID field.
|
||||
func IDNotIn(ids ...int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDGT applies the GT predicate on the ID field.
|
||||
func IDGT(id int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDGTE applies the GTE predicate on the ID field.
|
||||
func IDGTE(id int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLT applies the LT predicate on the ID field.
|
||||
func IDLT(id int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLTE applies the LTE predicate on the ID field.
|
||||
func IDLTE(id int64) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldID, id))
|
||||
}
|
||||
|
||||
// ProviderKey applies equality check predicate on the "provider_key" field. It's identical to ProviderKeyEQ.
|
||||
func ProviderKey(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
|
||||
func Name(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldName, v))
|
||||
}
|
||||
|
||||
// Config applies equality check predicate on the "config" field. It's identical to ConfigEQ.
|
||||
func Config(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldConfig, v))
|
||||
}
|
||||
|
||||
// SupportedTypes applies equality check predicate on the "supported_types" field. It's identical to SupportedTypesEQ.
|
||||
func SupportedTypes(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// Enabled applies equality check predicate on the "enabled" field. It's identical to EnabledEQ.
|
||||
func Enabled(v bool) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldEnabled, v))
|
||||
}
|
||||
|
||||
// SortOrder applies equality check predicate on the "sort_order" field. It's identical to SortOrderEQ.
|
||||
func SortOrder(v int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// Limits applies equality check predicate on the "limits" field. It's identical to LimitsEQ.
|
||||
func Limits(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldLimits, v))
|
||||
}
|
||||
|
||||
// RefundEnabled applies equality check predicate on the "refund_enabled" field. It's identical to RefundEnabledEQ.
|
||||
func RefundEnabled(v bool) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldRefundEnabled, v))
|
||||
}
|
||||
|
||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||
func CreatedAt(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
||||
func UpdatedAt(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// ProviderKeyEQ applies the EQ predicate on the "provider_key" field.
|
||||
func ProviderKeyEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyNEQ applies the NEQ predicate on the "provider_key" field.
|
||||
func ProviderKeyNEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyIn applies the In predicate on the "provider_key" field.
|
||||
func ProviderKeyIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldProviderKey, vs...))
|
||||
}
|
||||
|
||||
// ProviderKeyNotIn applies the NotIn predicate on the "provider_key" field.
|
||||
func ProviderKeyNotIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldProviderKey, vs...))
|
||||
}
|
||||
|
||||
// ProviderKeyGT applies the GT predicate on the "provider_key" field.
|
||||
func ProviderKeyGT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyGTE applies the GTE predicate on the "provider_key" field.
|
||||
func ProviderKeyGTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyLT applies the LT predicate on the "provider_key" field.
|
||||
func ProviderKeyLT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyLTE applies the LTE predicate on the "provider_key" field.
|
||||
func ProviderKeyLTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyContains applies the Contains predicate on the "provider_key" field.
|
||||
func ProviderKeyContains(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContains(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyHasPrefix applies the HasPrefix predicate on the "provider_key" field.
|
||||
func ProviderKeyHasPrefix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasPrefix(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyHasSuffix applies the HasSuffix predicate on the "provider_key" field.
|
||||
func ProviderKeyHasSuffix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasSuffix(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyEqualFold applies the EqualFold predicate on the "provider_key" field.
|
||||
func ProviderKeyEqualFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEqualFold(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// ProviderKeyContainsFold applies the ContainsFold predicate on the "provider_key" field.
|
||||
func ProviderKeyContainsFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContainsFold(FieldProviderKey, v))
|
||||
}
|
||||
|
||||
// NameEQ applies the EQ predicate on the "name" field.
|
||||
func NameEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldName, v))
|
||||
}
|
||||
|
||||
// NameNEQ applies the NEQ predicate on the "name" field.
|
||||
func NameNEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldName, v))
|
||||
}
|
||||
|
||||
// NameIn applies the In predicate on the "name" field.
|
||||
func NameIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldName, vs...))
|
||||
}
|
||||
|
||||
// NameNotIn applies the NotIn predicate on the "name" field.
|
||||
func NameNotIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldName, vs...))
|
||||
}
|
||||
|
||||
// NameGT applies the GT predicate on the "name" field.
|
||||
func NameGT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldName, v))
|
||||
}
|
||||
|
||||
// NameGTE applies the GTE predicate on the "name" field.
|
||||
func NameGTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldName, v))
|
||||
}
|
||||
|
||||
// NameLT applies the LT predicate on the "name" field.
|
||||
func NameLT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldName, v))
|
||||
}
|
||||
|
||||
// NameLTE applies the LTE predicate on the "name" field.
|
||||
func NameLTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldName, v))
|
||||
}
|
||||
|
||||
// NameContains applies the Contains predicate on the "name" field.
|
||||
func NameContains(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContains(FieldName, v))
|
||||
}
|
||||
|
||||
// NameHasPrefix applies the HasPrefix predicate on the "name" field.
|
||||
func NameHasPrefix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasPrefix(FieldName, v))
|
||||
}
|
||||
|
||||
// NameHasSuffix applies the HasSuffix predicate on the "name" field.
|
||||
func NameHasSuffix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasSuffix(FieldName, v))
|
||||
}
|
||||
|
||||
// NameEqualFold applies the EqualFold predicate on the "name" field.
|
||||
func NameEqualFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEqualFold(FieldName, v))
|
||||
}
|
||||
|
||||
// NameContainsFold applies the ContainsFold predicate on the "name" field.
|
||||
func NameContainsFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContainsFold(FieldName, v))
|
||||
}
|
||||
|
||||
// ConfigEQ applies the EQ predicate on the "config" field.
|
||||
func ConfigEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigNEQ applies the NEQ predicate on the "config" field.
|
||||
func ConfigNEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigIn applies the In predicate on the "config" field.
|
||||
func ConfigIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldConfig, vs...))
|
||||
}
|
||||
|
||||
// ConfigNotIn applies the NotIn predicate on the "config" field.
|
||||
func ConfigNotIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldConfig, vs...))
|
||||
}
|
||||
|
||||
// ConfigGT applies the GT predicate on the "config" field.
|
||||
func ConfigGT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigGTE applies the GTE predicate on the "config" field.
|
||||
func ConfigGTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigLT applies the LT predicate on the "config" field.
|
||||
func ConfigLT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigLTE applies the LTE predicate on the "config" field.
|
||||
func ConfigLTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigContains applies the Contains predicate on the "config" field.
|
||||
func ConfigContains(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContains(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigHasPrefix applies the HasPrefix predicate on the "config" field.
|
||||
func ConfigHasPrefix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasPrefix(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigHasSuffix applies the HasSuffix predicate on the "config" field.
|
||||
func ConfigHasSuffix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasSuffix(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigEqualFold applies the EqualFold predicate on the "config" field.
|
||||
func ConfigEqualFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEqualFold(FieldConfig, v))
|
||||
}
|
||||
|
||||
// ConfigContainsFold applies the ContainsFold predicate on the "config" field.
|
||||
func ConfigContainsFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContainsFold(FieldConfig, v))
|
||||
}
|
||||
|
||||
// SupportedTypesEQ applies the EQ predicate on the "supported_types" field.
|
||||
func SupportedTypesEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesNEQ applies the NEQ predicate on the "supported_types" field.
|
||||
func SupportedTypesNEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesIn applies the In predicate on the "supported_types" field.
|
||||
func SupportedTypesIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldSupportedTypes, vs...))
|
||||
}
|
||||
|
||||
// SupportedTypesNotIn applies the NotIn predicate on the "supported_types" field.
|
||||
func SupportedTypesNotIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldSupportedTypes, vs...))
|
||||
}
|
||||
|
||||
// SupportedTypesGT applies the GT predicate on the "supported_types" field.
|
||||
func SupportedTypesGT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesGTE applies the GTE predicate on the "supported_types" field.
|
||||
func SupportedTypesGTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesLT applies the LT predicate on the "supported_types" field.
|
||||
func SupportedTypesLT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesLTE applies the LTE predicate on the "supported_types" field.
|
||||
func SupportedTypesLTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesContains applies the Contains predicate on the "supported_types" field.
|
||||
func SupportedTypesContains(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContains(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesHasPrefix applies the HasPrefix predicate on the "supported_types" field.
|
||||
func SupportedTypesHasPrefix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasPrefix(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesHasSuffix applies the HasSuffix predicate on the "supported_types" field.
|
||||
func SupportedTypesHasSuffix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasSuffix(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesEqualFold applies the EqualFold predicate on the "supported_types" field.
|
||||
func SupportedTypesEqualFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEqualFold(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// SupportedTypesContainsFold applies the ContainsFold predicate on the "supported_types" field.
|
||||
func SupportedTypesContainsFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContainsFold(FieldSupportedTypes, v))
|
||||
}
|
||||
|
||||
// EnabledEQ applies the EQ predicate on the "enabled" field.
|
||||
func EnabledEQ(v bool) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldEnabled, v))
|
||||
}
|
||||
|
||||
// EnabledNEQ applies the NEQ predicate on the "enabled" field.
|
||||
func EnabledNEQ(v bool) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldEnabled, v))
|
||||
}
|
||||
|
||||
// SortOrderEQ applies the EQ predicate on the "sort_order" field.
|
||||
func SortOrderEQ(v int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderNEQ applies the NEQ predicate on the "sort_order" field.
|
||||
func SortOrderNEQ(v int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderIn applies the In predicate on the "sort_order" field.
|
||||
func SortOrderIn(vs ...int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldSortOrder, vs...))
|
||||
}
|
||||
|
||||
// SortOrderNotIn applies the NotIn predicate on the "sort_order" field.
|
||||
func SortOrderNotIn(vs ...int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldSortOrder, vs...))
|
||||
}
|
||||
|
||||
// SortOrderGT applies the GT predicate on the "sort_order" field.
|
||||
func SortOrderGT(v int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderGTE applies the GTE predicate on the "sort_order" field.
|
||||
func SortOrderGTE(v int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderLT applies the LT predicate on the "sort_order" field.
|
||||
func SortOrderLT(v int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderLTE applies the LTE predicate on the "sort_order" field.
|
||||
func SortOrderLTE(v int) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// LimitsEQ applies the EQ predicate on the "limits" field.
|
||||
func LimitsEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsNEQ applies the NEQ predicate on the "limits" field.
|
||||
func LimitsNEQ(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsIn applies the In predicate on the "limits" field.
|
||||
func LimitsIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldLimits, vs...))
|
||||
}
|
||||
|
||||
// LimitsNotIn applies the NotIn predicate on the "limits" field.
|
||||
func LimitsNotIn(vs ...string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldLimits, vs...))
|
||||
}
|
||||
|
||||
// LimitsGT applies the GT predicate on the "limits" field.
|
||||
func LimitsGT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsGTE applies the GTE predicate on the "limits" field.
|
||||
func LimitsGTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsLT applies the LT predicate on the "limits" field.
|
||||
func LimitsLT(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsLTE applies the LTE predicate on the "limits" field.
|
||||
func LimitsLTE(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsContains applies the Contains predicate on the "limits" field.
|
||||
func LimitsContains(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContains(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsHasPrefix applies the HasPrefix predicate on the "limits" field.
|
||||
func LimitsHasPrefix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasPrefix(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsHasSuffix applies the HasSuffix predicate on the "limits" field.
|
||||
func LimitsHasSuffix(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldHasSuffix(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsEqualFold applies the EqualFold predicate on the "limits" field.
|
||||
func LimitsEqualFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEqualFold(FieldLimits, v))
|
||||
}
|
||||
|
||||
// LimitsContainsFold applies the ContainsFold predicate on the "limits" field.
|
||||
func LimitsContainsFold(v string) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldContainsFold(FieldLimits, v))
|
||||
}
|
||||
|
||||
// RefundEnabledEQ applies the EQ predicate on the "refund_enabled" field.
|
||||
func RefundEnabledEQ(v bool) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldRefundEnabled, v))
|
||||
}
|
||||
|
||||
// RefundEnabledNEQ applies the NEQ predicate on the "refund_enabled" field.
|
||||
func RefundEnabledNEQ(v bool) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldRefundEnabled, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||
func CreatedAtNEQ(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||
func CreatedAtIn(vs ...time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||
func CreatedAtNotIn(vs ...time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||
func CreatedAtGT(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||
func CreatedAtGTE(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||
func CreatedAtLT(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||
func CreatedAtLTE(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
||||
func UpdatedAtEQ(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
||||
func UpdatedAtNEQ(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
||||
func UpdatedAtIn(vs ...time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
||||
func UpdatedAtNotIn(vs ...time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
||||
func UpdatedAtGT(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
||||
func UpdatedAtGTE(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldGTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
||||
func UpdatedAtLT(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
||||
func UpdatedAtLTE(v time.Time) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.FieldLTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// And groups predicates with the AND operator between them.
|
||||
func And(predicates ...predicate.PaymentProviderInstance) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.AndPredicates(predicates...))
|
||||
}
|
||||
|
||||
// Or groups predicates with the OR operator between them.
|
||||
func Or(predicates ...predicate.PaymentProviderInstance) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.OrPredicates(predicates...))
|
||||
}
|
||||
|
||||
// Not applies the not operator on the given predicate.
|
||||
func Not(p predicate.PaymentProviderInstance) predicate.PaymentProviderInstance {
|
||||
return predicate.PaymentProviderInstance(sql.NotPredicates(p))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// PaymentProviderInstanceDelete is the builder for deleting a PaymentProviderInstance entity.
|
||||
type PaymentProviderInstanceDelete struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *PaymentProviderInstanceMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentProviderInstanceDelete builder.
|
||||
func (_d *PaymentProviderInstanceDelete) Where(ps ...predicate.PaymentProviderInstance) *PaymentProviderInstanceDelete {
|
||||
_d.mutation.Where(ps...)
|
||||
return _d
|
||||
}
|
||||
|
||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||
func (_d *PaymentProviderInstanceDelete) Exec(ctx context.Context) (int, error) {
|
||||
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_d *PaymentProviderInstanceDelete) ExecX(ctx context.Context) int {
|
||||
n, err := _d.Exec(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (_d *PaymentProviderInstanceDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
_spec := sqlgraph.NewDeleteSpec(paymentproviderinstance.Table, sqlgraph.NewFieldSpec(paymentproviderinstance.FieldID, field.TypeInt64))
|
||||
if ps := _d.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
|
||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
_d.mutation.done = true
|
||||
return affected, err
|
||||
}
|
||||
|
||||
// PaymentProviderInstanceDeleteOne is the builder for deleting a single PaymentProviderInstance entity.
|
||||
type PaymentProviderInstanceDeleteOne struct {
|
||||
_d *PaymentProviderInstanceDelete
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentProviderInstanceDelete builder.
|
||||
func (_d *PaymentProviderInstanceDeleteOne) Where(ps ...predicate.PaymentProviderInstance) *PaymentProviderInstanceDeleteOne {
|
||||
_d._d.mutation.Where(ps...)
|
||||
return _d
|
||||
}
|
||||
|
||||
// Exec executes the deletion query.
|
||||
func (_d *PaymentProviderInstanceDeleteOne) Exec(ctx context.Context) error {
|
||||
n, err := _d._d.Exec(ctx)
|
||||
switch {
|
||||
case err != nil:
|
||||
return err
|
||||
case n == 0:
|
||||
return &NotFoundError{paymentproviderinstance.Label}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_d *PaymentProviderInstanceDeleteOne) ExecX(ctx context.Context) {
|
||||
if err := _d.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// PaymentProviderInstanceQuery is the builder for querying PaymentProviderInstance entities.
|
||||
type PaymentProviderInstanceQuery struct {
|
||||
config
|
||||
ctx *QueryContext
|
||||
order []paymentproviderinstance.OrderOption
|
||||
inters []Interceptor
|
||||
predicates []predicate.PaymentProviderInstance
|
||||
modifiers []func(*sql.Selector)
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
}
|
||||
|
||||
// Where adds a new predicate for the PaymentProviderInstanceQuery builder.
|
||||
func (_q *PaymentProviderInstanceQuery) Where(ps ...predicate.PaymentProviderInstance) *PaymentProviderInstanceQuery {
|
||||
_q.predicates = append(_q.predicates, ps...)
|
||||
return _q
|
||||
}
|
||||
|
||||
// Limit the number of records to be returned by this query.
|
||||
func (_q *PaymentProviderInstanceQuery) Limit(limit int) *PaymentProviderInstanceQuery {
|
||||
_q.ctx.Limit = &limit
|
||||
return _q
|
||||
}
|
||||
|
||||
// Offset to start from.
|
||||
func (_q *PaymentProviderInstanceQuery) Offset(offset int) *PaymentProviderInstanceQuery {
|
||||
_q.ctx.Offset = &offset
|
||||
return _q
|
||||
}
|
||||
|
||||
// Unique configures the query builder to filter duplicate records on query.
|
||||
// By default, unique is set to true, and can be disabled using this method.
|
||||
func (_q *PaymentProviderInstanceQuery) Unique(unique bool) *PaymentProviderInstanceQuery {
|
||||
_q.ctx.Unique = &unique
|
||||
return _q
|
||||
}
|
||||
|
||||
// Order specifies how the records should be ordered.
|
||||
func (_q *PaymentProviderInstanceQuery) Order(o ...paymentproviderinstance.OrderOption) *PaymentProviderInstanceQuery {
|
||||
_q.order = append(_q.order, o...)
|
||||
return _q
|
||||
}
|
||||
|
||||
// First returns the first PaymentProviderInstance entity from the query.
|
||||
// Returns a *NotFoundError when no PaymentProviderInstance was found.
|
||||
func (_q *PaymentProviderInstanceQuery) First(ctx context.Context) (*PaymentProviderInstance, error) {
|
||||
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nil, &NotFoundError{paymentproviderinstance.Label}
|
||||
}
|
||||
return nodes[0], nil
|
||||
}
|
||||
|
||||
// FirstX is like First, but panics if an error occurs.
|
||||
func (_q *PaymentProviderInstanceQuery) FirstX(ctx context.Context) *PaymentProviderInstance {
|
||||
node, err := _q.First(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// FirstID returns the first PaymentProviderInstance ID from the query.
|
||||
// Returns a *NotFoundError when no PaymentProviderInstance ID was found.
|
||||
func (_q *PaymentProviderInstanceQuery) FirstID(ctx context.Context) (id int64, err error) {
|
||||
var ids []int64
|
||||
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
err = &NotFoundError{paymentproviderinstance.Label}
|
||||
return
|
||||
}
|
||||
return ids[0], nil
|
||||
}
|
||||
|
||||
// FirstIDX is like FirstID, but panics if an error occurs.
|
||||
func (_q *PaymentProviderInstanceQuery) FirstIDX(ctx context.Context) int64 {
|
||||
id, err := _q.FirstID(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// Only returns a single PaymentProviderInstance entity found by the query, ensuring it only returns one.
|
||||
// Returns a *NotSingularError when more than one PaymentProviderInstance entity is found.
|
||||
// Returns a *NotFoundError when no PaymentProviderInstance entities are found.
|
||||
func (_q *PaymentProviderInstanceQuery) Only(ctx context.Context) (*PaymentProviderInstance, error) {
|
||||
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch len(nodes) {
|
||||
case 1:
|
||||
return nodes[0], nil
|
||||
case 0:
|
||||
return nil, &NotFoundError{paymentproviderinstance.Label}
|
||||
default:
|
||||
return nil, &NotSingularError{paymentproviderinstance.Label}
|
||||
}
|
||||
}
|
||||
|
||||
// OnlyX is like Only, but panics if an error occurs.
|
||||
func (_q *PaymentProviderInstanceQuery) OnlyX(ctx context.Context) *PaymentProviderInstance {
|
||||
node, err := _q.Only(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// OnlyID is like Only, but returns the only PaymentProviderInstance ID in the query.
|
||||
// Returns a *NotSingularError when more than one PaymentProviderInstance ID is found.
|
||||
// Returns a *NotFoundError when no entities are found.
|
||||
func (_q *PaymentProviderInstanceQuery) OnlyID(ctx context.Context) (id int64, err error) {
|
||||
var ids []int64
|
||||
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
|
||||
return
|
||||
}
|
||||
switch len(ids) {
|
||||
case 1:
|
||||
id = ids[0]
|
||||
case 0:
|
||||
err = &NotFoundError{paymentproviderinstance.Label}
|
||||
default:
|
||||
err = &NotSingularError{paymentproviderinstance.Label}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OnlyIDX is like OnlyID, but panics if an error occurs.
|
||||
func (_q *PaymentProviderInstanceQuery) OnlyIDX(ctx context.Context) int64 {
|
||||
id, err := _q.OnlyID(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// All executes the query and returns a list of PaymentProviderInstances.
|
||||
func (_q *PaymentProviderInstanceQuery) All(ctx context.Context) ([]*PaymentProviderInstance, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
qr := querierAll[[]*PaymentProviderInstance, *PaymentProviderInstanceQuery]()
|
||||
return withInterceptors[[]*PaymentProviderInstance](ctx, _q, qr, _q.inters)
|
||||
}
|
||||
|
||||
// AllX is like All, but panics if an error occurs.
|
||||
func (_q *PaymentProviderInstanceQuery) AllX(ctx context.Context) []*PaymentProviderInstance {
|
||||
nodes, err := _q.All(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
// IDs executes the query and returns a list of PaymentProviderInstance IDs.
|
||||
func (_q *PaymentProviderInstanceQuery) IDs(ctx context.Context) (ids []int64, err error) {
|
||||
if _q.ctx.Unique == nil && _q.path != nil {
|
||||
_q.Unique(true)
|
||||
}
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
|
||||
if err = _q.Select(paymentproviderinstance.FieldID).Scan(ctx, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// IDsX is like IDs, but panics if an error occurs.
|
||||
func (_q *PaymentProviderInstanceQuery) IDsX(ctx context.Context) []int64 {
|
||||
ids, err := _q.IDs(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// Count returns the count of the given query.
|
||||
func (_q *PaymentProviderInstanceQuery) Count(ctx context.Context) (int, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return withInterceptors[int](ctx, _q, querierCount[*PaymentProviderInstanceQuery](), _q.inters)
|
||||
}
|
||||
|
||||
// CountX is like Count, but panics if an error occurs.
|
||||
func (_q *PaymentProviderInstanceQuery) CountX(ctx context.Context) int {
|
||||
count, err := _q.Count(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Exist returns true if the query has elements in the graph.
|
||||
func (_q *PaymentProviderInstanceQuery) Exist(ctx context.Context) (bool, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
|
||||
switch _, err := _q.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExistX is like Exist, but panics if an error occurs.
|
||||
func (_q *PaymentProviderInstanceQuery) ExistX(ctx context.Context) bool {
|
||||
exist, err := _q.Exist(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return exist
|
||||
}
|
||||
|
||||
// Clone returns a duplicate of the PaymentProviderInstanceQuery builder, including all associated steps. It can be
|
||||
// used to prepare common query builders and use them differently after the clone is made.
|
||||
func (_q *PaymentProviderInstanceQuery) Clone() *PaymentProviderInstanceQuery {
|
||||
if _q == nil {
|
||||
return nil
|
||||
}
|
||||
return &PaymentProviderInstanceQuery{
|
||||
config: _q.config,
|
||||
ctx: _q.ctx.Clone(),
|
||||
order: append([]paymentproviderinstance.OrderOption{}, _q.order...),
|
||||
inters: append([]Interceptor{}, _q.inters...),
|
||||
predicates: append([]predicate.PaymentProviderInstance{}, _q.predicates...),
|
||||
// clone intermediate query.
|
||||
sql: _q.sql.Clone(),
|
||||
path: _q.path,
|
||||
}
|
||||
}
|
||||
|
||||
// GroupBy is used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// ProviderKey string `json:"provider_key,omitempty"`
|
||||
// Count int `json:"count,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.PaymentProviderInstance.Query().
|
||||
// GroupBy(paymentproviderinstance.FieldProviderKey).
|
||||
// Aggregate(ent.Count()).
|
||||
// Scan(ctx, &v)
|
||||
func (_q *PaymentProviderInstanceQuery) GroupBy(field string, fields ...string) *PaymentProviderInstanceGroupBy {
|
||||
_q.ctx.Fields = append([]string{field}, fields...)
|
||||
grbuild := &PaymentProviderInstanceGroupBy{build: _q}
|
||||
grbuild.flds = &_q.ctx.Fields
|
||||
grbuild.label = paymentproviderinstance.Label
|
||||
grbuild.scan = grbuild.Scan
|
||||
return grbuild
|
||||
}
|
||||
|
||||
// Select allows the selection one or more fields/columns for the given query,
|
||||
// instead of selecting all fields in the entity.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// ProviderKey string `json:"provider_key,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.PaymentProviderInstance.Query().
|
||||
// Select(paymentproviderinstance.FieldProviderKey).
|
||||
// Scan(ctx, &v)
|
||||
func (_q *PaymentProviderInstanceQuery) Select(fields ...string) *PaymentProviderInstanceSelect {
|
||||
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
|
||||
sbuild := &PaymentProviderInstanceSelect{PaymentProviderInstanceQuery: _q}
|
||||
sbuild.label = paymentproviderinstance.Label
|
||||
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
|
||||
return sbuild
|
||||
}
|
||||
|
||||
// Aggregate returns a PaymentProviderInstanceSelect configured with the given aggregations.
|
||||
func (_q *PaymentProviderInstanceQuery) Aggregate(fns ...AggregateFunc) *PaymentProviderInstanceSelect {
|
||||
return _q.Select().Aggregate(fns...)
|
||||
}
|
||||
|
||||
func (_q *PaymentProviderInstanceQuery) prepareQuery(ctx context.Context) error {
|
||||
for _, inter := range _q.inters {
|
||||
if inter == nil {
|
||||
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
|
||||
}
|
||||
if trv, ok := inter.(Traverser); ok {
|
||||
if err := trv.Traverse(ctx, _q); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range _q.ctx.Fields {
|
||||
if !paymentproviderinstance.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
}
|
||||
if _q.path != nil {
|
||||
prev, err := _q.path(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_q.sql = prev
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_q *PaymentProviderInstanceQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*PaymentProviderInstance, error) {
|
||||
var (
|
||||
nodes = []*PaymentProviderInstance{}
|
||||
_spec = _q.querySpec()
|
||||
)
|
||||
_spec.ScanValues = func(columns []string) ([]any, error) {
|
||||
return (*PaymentProviderInstance).scanValues(nil, columns)
|
||||
}
|
||||
_spec.Assign = func(columns []string, values []any) error {
|
||||
node := &PaymentProviderInstance{config: _q.config}
|
||||
nodes = append(nodes, node)
|
||||
return node.assignValues(columns, values)
|
||||
}
|
||||
if len(_q.modifiers) > 0 {
|
||||
_spec.Modifiers = _q.modifiers
|
||||
}
|
||||
for i := range hooks {
|
||||
hooks[i](ctx, _spec)
|
||||
}
|
||||
if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nodes, nil
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (_q *PaymentProviderInstanceQuery) sqlCount(ctx context.Context) (int, error) {
|
||||
_spec := _q.querySpec()
|
||||
if len(_q.modifiers) > 0 {
|
||||
_spec.Modifiers = _q.modifiers
|
||||
}
|
||||
_spec.Node.Columns = _q.ctx.Fields
|
||||
if len(_q.ctx.Fields) > 0 {
|
||||
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
|
||||
}
|
||||
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
|
||||
}
|
||||
|
||||
func (_q *PaymentProviderInstanceQuery) querySpec() *sqlgraph.QuerySpec {
|
||||
_spec := sqlgraph.NewQuerySpec(paymentproviderinstance.Table, paymentproviderinstance.Columns, sqlgraph.NewFieldSpec(paymentproviderinstance.FieldID, field.TypeInt64))
|
||||
_spec.From = _q.sql
|
||||
if unique := _q.ctx.Unique; unique != nil {
|
||||
_spec.Unique = *unique
|
||||
} else if _q.path != nil {
|
||||
_spec.Unique = true
|
||||
}
|
||||
if fields := _q.ctx.Fields; len(fields) > 0 {
|
||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, paymentproviderinstance.FieldID)
|
||||
for i := range fields {
|
||||
if fields[i] != paymentproviderinstance.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
if ps := _q.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if limit := _q.ctx.Limit; limit != nil {
|
||||
_spec.Limit = *limit
|
||||
}
|
||||
if offset := _q.ctx.Offset; offset != nil {
|
||||
_spec.Offset = *offset
|
||||
}
|
||||
if ps := _q.order; len(ps) > 0 {
|
||||
_spec.Order = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
return _spec
|
||||
}
|
||||
|
||||
func (_q *PaymentProviderInstanceQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||
builder := sql.Dialect(_q.driver.Dialect())
|
||||
t1 := builder.Table(paymentproviderinstance.Table)
|
||||
columns := _q.ctx.Fields
|
||||
if len(columns) == 0 {
|
||||
columns = paymentproviderinstance.Columns
|
||||
}
|
||||
selector := builder.Select(t1.Columns(columns...)...).From(t1)
|
||||
if _q.sql != nil {
|
||||
selector = _q.sql
|
||||
selector.Select(selector.Columns(columns...)...)
|
||||
}
|
||||
if _q.ctx.Unique != nil && *_q.ctx.Unique {
|
||||
selector.Distinct()
|
||||
}
|
||||
for _, m := range _q.modifiers {
|
||||
m(selector)
|
||||
}
|
||||
for _, p := range _q.predicates {
|
||||
p(selector)
|
||||
}
|
||||
for _, p := range _q.order {
|
||||
p(selector)
|
||||
}
|
||||
if offset := _q.ctx.Offset; offset != nil {
|
||||
// limit is mandatory for offset clause. We start
|
||||
// with default value, and override it below if needed.
|
||||
selector.Offset(*offset).Limit(math.MaxInt32)
|
||||
}
|
||||
if limit := _q.ctx.Limit; limit != nil {
|
||||
selector.Limit(*limit)
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
// ForUpdate locks the selected rows against concurrent updates, and prevent them from being
|
||||
// updated, deleted or "selected ... for update" by other sessions, until the transaction is
|
||||
// either committed or rolled-back.
|
||||
func (_q *PaymentProviderInstanceQuery) ForUpdate(opts ...sql.LockOption) *PaymentProviderInstanceQuery {
|
||||
if _q.driver.Dialect() == dialect.Postgres {
|
||||
_q.Unique(false)
|
||||
}
|
||||
_q.modifiers = append(_q.modifiers, func(s *sql.Selector) {
|
||||
s.ForUpdate(opts...)
|
||||
})
|
||||
return _q
|
||||
}
|
||||
|
||||
// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock
|
||||
// on any rows that are read. Other sessions can read the rows, but cannot modify them
|
||||
// until your transaction commits.
|
||||
func (_q *PaymentProviderInstanceQuery) ForShare(opts ...sql.LockOption) *PaymentProviderInstanceQuery {
|
||||
if _q.driver.Dialect() == dialect.Postgres {
|
||||
_q.Unique(false)
|
||||
}
|
||||
_q.modifiers = append(_q.modifiers, func(s *sql.Selector) {
|
||||
s.ForShare(opts...)
|
||||
})
|
||||
return _q
|
||||
}
|
||||
|
||||
// PaymentProviderInstanceGroupBy is the group-by builder for PaymentProviderInstance entities.
|
||||
type PaymentProviderInstanceGroupBy struct {
|
||||
selector
|
||||
build *PaymentProviderInstanceQuery
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the group-by query.
|
||||
func (_g *PaymentProviderInstanceGroupBy) Aggregate(fns ...AggregateFunc) *PaymentProviderInstanceGroupBy {
|
||||
_g.fns = append(_g.fns, fns...)
|
||||
return _g
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (_g *PaymentProviderInstanceGroupBy) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
|
||||
if err := _g.build.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*PaymentProviderInstanceQuery, *PaymentProviderInstanceGroupBy](ctx, _g.build, _g, _g.build.inters, v)
|
||||
}
|
||||
|
||||
func (_g *PaymentProviderInstanceGroupBy) sqlScan(ctx context.Context, root *PaymentProviderInstanceQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx).Select()
|
||||
aggregation := make([]string, 0, len(_g.fns))
|
||||
for _, fn := range _g.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
if len(selector.SelectedColumns()) == 0 {
|
||||
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
|
||||
for _, f := range *_g.flds {
|
||||
columns = append(columns, selector.C(f))
|
||||
}
|
||||
columns = append(columns, aggregation...)
|
||||
selector.Select(columns...)
|
||||
}
|
||||
selector.GroupBy(selector.Columns(*_g.flds...)...)
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
// PaymentProviderInstanceSelect is the builder for selecting fields of PaymentProviderInstance entities.
|
||||
type PaymentProviderInstanceSelect struct {
|
||||
*PaymentProviderInstanceQuery
|
||||
selector
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the selector query.
|
||||
func (_s *PaymentProviderInstanceSelect) Aggregate(fns ...AggregateFunc) *PaymentProviderInstanceSelect {
|
||||
_s.fns = append(_s.fns, fns...)
|
||||
return _s
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (_s *PaymentProviderInstanceSelect) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
|
||||
if err := _s.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*PaymentProviderInstanceQuery, *PaymentProviderInstanceSelect](ctx, _s.PaymentProviderInstanceQuery, _s, _s.inters, v)
|
||||
}
|
||||
|
||||
func (_s *PaymentProviderInstanceSelect) sqlScan(ctx context.Context, root *PaymentProviderInstanceQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx)
|
||||
aggregation := make([]string, 0, len(_s.fns))
|
||||
for _, fn := range _s.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
switch n := len(*_s.selector.flds); {
|
||||
case n == 0 && len(aggregation) > 0:
|
||||
selector.Select(aggregation...)
|
||||
case n != 0 && len(aggregation) > 0:
|
||||
selector.AppendSelect(aggregation...)
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := _s.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// PaymentProviderInstanceUpdate is the builder for updating PaymentProviderInstance entities.
|
||||
type PaymentProviderInstanceUpdate struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *PaymentProviderInstanceMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentProviderInstanceUpdate builder.
|
||||
func (_u *PaymentProviderInstanceUpdate) Where(ps ...predicate.PaymentProviderInstance) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.Where(ps...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetProviderKey sets the "provider_key" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetProviderKey(v string) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.SetProviderKey(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableProviderKey sets the "provider_key" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetNillableProviderKey(v *string) *PaymentProviderInstanceUpdate {
|
||||
if v != nil {
|
||||
_u.SetProviderKey(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetName sets the "name" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetName(v string) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.SetName(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableName sets the "name" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetNillableName(v *string) *PaymentProviderInstanceUpdate {
|
||||
if v != nil {
|
||||
_u.SetName(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetConfig sets the "config" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetConfig(v string) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.SetConfig(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableConfig sets the "config" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetNillableConfig(v *string) *PaymentProviderInstanceUpdate {
|
||||
if v != nil {
|
||||
_u.SetConfig(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetSupportedTypes sets the "supported_types" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetSupportedTypes(v string) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.SetSupportedTypes(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableSupportedTypes sets the "supported_types" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetNillableSupportedTypes(v *string) *PaymentProviderInstanceUpdate {
|
||||
if v != nil {
|
||||
_u.SetSupportedTypes(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetEnabled sets the "enabled" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetEnabled(v bool) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.SetEnabled(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableEnabled sets the "enabled" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetNillableEnabled(v *bool) *PaymentProviderInstanceUpdate {
|
||||
if v != nil {
|
||||
_u.SetEnabled(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetSortOrder sets the "sort_order" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetSortOrder(v int) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.ResetSortOrder()
|
||||
_u.mutation.SetSortOrder(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableSortOrder sets the "sort_order" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetNillableSortOrder(v *int) *PaymentProviderInstanceUpdate {
|
||||
if v != nil {
|
||||
_u.SetSortOrder(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddSortOrder adds value to the "sort_order" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) AddSortOrder(v int) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.AddSortOrder(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetLimits sets the "limits" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetLimits(v string) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.SetLimits(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableLimits sets the "limits" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetNillableLimits(v *string) *PaymentProviderInstanceUpdate {
|
||||
if v != nil {
|
||||
_u.SetLimits(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetRefundEnabled sets the "refund_enabled" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetRefundEnabled(v bool) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.SetRefundEnabled(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableRefundEnabled sets the "refund_enabled" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetNillableRefundEnabled(v *bool) *PaymentProviderInstanceUpdate {
|
||||
if v != nil {
|
||||
_u.SetRefundEnabled(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetUpdatedAt sets the "updated_at" field.
|
||||
func (_u *PaymentProviderInstanceUpdate) SetUpdatedAt(v time.Time) *PaymentProviderInstanceUpdate {
|
||||
_u.mutation.SetUpdatedAt(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Mutation returns the PaymentProviderInstanceMutation object of the builder.
|
||||
func (_u *PaymentProviderInstanceUpdate) Mutation() *PaymentProviderInstanceMutation {
|
||||
return _u.mutation
|
||||
}
|
||||
|
||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||
func (_u *PaymentProviderInstanceUpdate) Save(ctx context.Context) (int, error) {
|
||||
_u.defaults()
|
||||
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (_u *PaymentProviderInstanceUpdate) SaveX(ctx context.Context) int {
|
||||
affected, err := _u.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return affected
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (_u *PaymentProviderInstanceUpdate) Exec(ctx context.Context) error {
|
||||
_, err := _u.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_u *PaymentProviderInstanceUpdate) ExecX(ctx context.Context) {
|
||||
if err := _u.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// defaults sets the default values of the builder before save.
|
||||
func (_u *PaymentProviderInstanceUpdate) defaults() {
|
||||
if _, ok := _u.mutation.UpdatedAt(); !ok {
|
||||
v := paymentproviderinstance.UpdateDefaultUpdatedAt()
|
||||
_u.mutation.SetUpdatedAt(v)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (_u *PaymentProviderInstanceUpdate) check() error {
|
||||
if v, ok := _u.mutation.ProviderKey(); ok {
|
||||
if err := paymentproviderinstance.ProviderKeyValidator(v); err != nil {
|
||||
return &ValidationError{Name: "provider_key", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.provider_key": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.Name(); ok {
|
||||
if err := paymentproviderinstance.NameValidator(v); err != nil {
|
||||
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.name": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.SupportedTypes(); ok {
|
||||
if err := paymentproviderinstance.SupportedTypesValidator(v); err != nil {
|
||||
return &ValidationError{Name: "supported_types", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.supported_types": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_u *PaymentProviderInstanceUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
if err := _u.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(paymentproviderinstance.Table, paymentproviderinstance.Columns, sqlgraph.NewFieldSpec(paymentproviderinstance.FieldID, field.TypeInt64))
|
||||
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, ok := _u.mutation.ProviderKey(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldProviderKey, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Name(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldName, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Config(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldConfig, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.SupportedTypes(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldSupportedTypes, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Enabled(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldEnabled, field.TypeBool, value)
|
||||
}
|
||||
if value, ok := _u.mutation.SortOrder(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldSortOrder, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedSortOrder(); ok {
|
||||
_spec.AddField(paymentproviderinstance.FieldSortOrder, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Limits(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldLimits, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.RefundEnabled(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldRefundEnabled, field.TypeBool, value)
|
||||
}
|
||||
if value, ok := _u.mutation.UpdatedAt(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{paymentproviderinstance.Label}
|
||||
} else if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
_u.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
// PaymentProviderInstanceUpdateOne is the builder for updating a single PaymentProviderInstance entity.
|
||||
type PaymentProviderInstanceUpdateOne struct {
|
||||
config
|
||||
fields []string
|
||||
hooks []Hook
|
||||
mutation *PaymentProviderInstanceMutation
|
||||
}
|
||||
|
||||
// SetProviderKey sets the "provider_key" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetProviderKey(v string) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.SetProviderKey(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableProviderKey sets the "provider_key" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetNillableProviderKey(v *string) *PaymentProviderInstanceUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetProviderKey(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetName sets the "name" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetName(v string) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.SetName(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableName sets the "name" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetNillableName(v *string) *PaymentProviderInstanceUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetName(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetConfig sets the "config" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetConfig(v string) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.SetConfig(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableConfig sets the "config" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetNillableConfig(v *string) *PaymentProviderInstanceUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetConfig(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetSupportedTypes sets the "supported_types" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetSupportedTypes(v string) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.SetSupportedTypes(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableSupportedTypes sets the "supported_types" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetNillableSupportedTypes(v *string) *PaymentProviderInstanceUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetSupportedTypes(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetEnabled sets the "enabled" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetEnabled(v bool) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.SetEnabled(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableEnabled sets the "enabled" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetNillableEnabled(v *bool) *PaymentProviderInstanceUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetEnabled(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetSortOrder sets the "sort_order" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetSortOrder(v int) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.ResetSortOrder()
|
||||
_u.mutation.SetSortOrder(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableSortOrder sets the "sort_order" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetNillableSortOrder(v *int) *PaymentProviderInstanceUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetSortOrder(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddSortOrder adds value to the "sort_order" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) AddSortOrder(v int) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.AddSortOrder(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetLimits sets the "limits" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetLimits(v string) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.SetLimits(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableLimits sets the "limits" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetNillableLimits(v *string) *PaymentProviderInstanceUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetLimits(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetRefundEnabled sets the "refund_enabled" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetRefundEnabled(v bool) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.SetRefundEnabled(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableRefundEnabled sets the "refund_enabled" field if the given value is not nil.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetNillableRefundEnabled(v *bool) *PaymentProviderInstanceUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetRefundEnabled(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetUpdatedAt sets the "updated_at" field.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SetUpdatedAt(v time.Time) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.SetUpdatedAt(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Mutation returns the PaymentProviderInstanceMutation object of the builder.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) Mutation() *PaymentProviderInstanceMutation {
|
||||
return _u.mutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the PaymentProviderInstanceUpdate builder.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) Where(ps ...predicate.PaymentProviderInstance) *PaymentProviderInstanceUpdateOne {
|
||||
_u.mutation.Where(ps...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||
// The default is selecting all fields defined in the entity schema.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) Select(field string, fields ...string) *PaymentProviderInstanceUpdateOne {
|
||||
_u.fields = append([]string{field}, fields...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Save executes the query and returns the updated PaymentProviderInstance entity.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) Save(ctx context.Context) (*PaymentProviderInstance, error) {
|
||||
_u.defaults()
|
||||
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) SaveX(ctx context.Context) *PaymentProviderInstance {
|
||||
node, err := _u.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// Exec executes the query on the entity.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) Exec(ctx context.Context) error {
|
||||
_, err := _u.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) ExecX(ctx context.Context) {
|
||||
if err := _u.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// defaults sets the default values of the builder before save.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) defaults() {
|
||||
if _, ok := _u.mutation.UpdatedAt(); !ok {
|
||||
v := paymentproviderinstance.UpdateDefaultUpdatedAt()
|
||||
_u.mutation.SetUpdatedAt(v)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (_u *PaymentProviderInstanceUpdateOne) check() error {
|
||||
if v, ok := _u.mutation.ProviderKey(); ok {
|
||||
if err := paymentproviderinstance.ProviderKeyValidator(v); err != nil {
|
||||
return &ValidationError{Name: "provider_key", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.provider_key": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.Name(); ok {
|
||||
if err := paymentproviderinstance.NameValidator(v); err != nil {
|
||||
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.name": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.SupportedTypes(); ok {
|
||||
if err := paymentproviderinstance.SupportedTypesValidator(v); err != nil {
|
||||
return &ValidationError{Name: "supported_types", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.supported_types": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_u *PaymentProviderInstanceUpdateOne) sqlSave(ctx context.Context) (_node *PaymentProviderInstance, err error) {
|
||||
if err := _u.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(paymentproviderinstance.Table, paymentproviderinstance.Columns, sqlgraph.NewFieldSpec(paymentproviderinstance.FieldID, field.TypeInt64))
|
||||
id, ok := _u.mutation.ID()
|
||||
if !ok {
|
||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "PaymentProviderInstance.id" for update`)}
|
||||
}
|
||||
_spec.Node.ID.Value = id
|
||||
if fields := _u.fields; len(fields) > 0 {
|
||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, paymentproviderinstance.FieldID)
|
||||
for _, f := range fields {
|
||||
if !paymentproviderinstance.ValidColumn(f) {
|
||||
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
if f != paymentproviderinstance.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, ok := _u.mutation.ProviderKey(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldProviderKey, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Name(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldName, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Config(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldConfig, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.SupportedTypes(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldSupportedTypes, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Enabled(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldEnabled, field.TypeBool, value)
|
||||
}
|
||||
if value, ok := _u.mutation.SortOrder(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldSortOrder, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedSortOrder(); ok {
|
||||
_spec.AddField(paymentproviderinstance.FieldSortOrder, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Limits(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldLimits, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.RefundEnabled(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldRefundEnabled, field.TypeBool, value)
|
||||
}
|
||||
if value, ok := _u.mutation.UpdatedAt(); ok {
|
||||
_spec.SetField(paymentproviderinstance.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
_node = &PaymentProviderInstance{config: _u.config}
|
||||
_spec.Assign = _node.assignValues
|
||||
_spec.ScanValues = _node.scanValues
|
||||
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{paymentproviderinstance.Label}
|
||||
} else if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
_u.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
@@ -30,6 +30,16 @@ type Group func(*sql.Selector)
|
||||
// IdempotencyRecord is the predicate function for idempotencyrecord builders.
|
||||
type IdempotencyRecord func(*sql.Selector)
|
||||
|
||||
// PaymentAuditLog is the predicate function for paymentauditlog builders.
|
||||
type PaymentAuditLog func(*sql.Selector)
|
||||
|
||||
|
||||
// PaymentOrder is the predicate function for paymentorder builders.
|
||||
type PaymentOrder func(*sql.Selector)
|
||||
|
||||
// PaymentProviderInstance is the predicate function for paymentproviderinstance builders.
|
||||
type PaymentProviderInstance func(*sql.Selector)
|
||||
|
||||
// PromoCode is the predicate function for promocode builders.
|
||||
type PromoCode func(*sql.Selector)
|
||||
|
||||
@@ -48,6 +58,9 @@ type SecuritySecret func(*sql.Selector)
|
||||
// Setting is the predicate function for setting builders.
|
||||
type Setting func(*sql.Selector)
|
||||
|
||||
// SubscriptionPlan is the predicate function for subscriptionplan builders.
|
||||
type SubscriptionPlan func(*sql.Selector)
|
||||
|
||||
// TLSFingerprintProfile is the predicate function for tlsfingerprintprofile builders.
|
||||
type TLSFingerprintProfile func(*sql.Selector)
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
|
||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||
"github.com/Wei-Shaw/sub2api/ent/idempotencyrecord"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentauditlog"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocode"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
|
||||
"github.com/Wei-Shaw/sub2api/ent/proxy"
|
||||
@@ -20,6 +23,7 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/schema"
|
||||
"github.com/Wei-Shaw/sub2api/ent/securitysecret"
|
||||
"github.com/Wei-Shaw/sub2api/ent/setting"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
"github.com/Wei-Shaw/sub2api/ent/tlsfingerprintprofile"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagecleanuptask"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagelog"
|
||||
@@ -503,6 +507,160 @@ func init() {
|
||||
idempotencyrecordDescErrorReason := idempotencyrecordFields[6].Descriptor()
|
||||
// idempotencyrecord.ErrorReasonValidator is a validator for the "error_reason" field. It is called by the builders before save.
|
||||
idempotencyrecord.ErrorReasonValidator = idempotencyrecordDescErrorReason.Validators[0].(func(string) error)
|
||||
paymentauditlogFields := schema.PaymentAuditLog{}.Fields()
|
||||
_ = paymentauditlogFields
|
||||
// paymentauditlogDescOrderID is the schema descriptor for order_id field.
|
||||
paymentauditlogDescOrderID := paymentauditlogFields[0].Descriptor()
|
||||
// paymentauditlog.OrderIDValidator is a validator for the "order_id" field. It is called by the builders before save.
|
||||
paymentauditlog.OrderIDValidator = paymentauditlogDescOrderID.Validators[0].(func(string) error)
|
||||
// paymentauditlogDescAction is the schema descriptor for action field.
|
||||
paymentauditlogDescAction := paymentauditlogFields[1].Descriptor()
|
||||
// paymentauditlog.ActionValidator is a validator for the "action" field. It is called by the builders before save.
|
||||
paymentauditlog.ActionValidator = paymentauditlogDescAction.Validators[0].(func(string) error)
|
||||
// paymentauditlogDescDetail is the schema descriptor for detail field.
|
||||
paymentauditlogDescDetail := paymentauditlogFields[2].Descriptor()
|
||||
// paymentauditlog.DefaultDetail holds the default value on creation for the detail field.
|
||||
paymentauditlog.DefaultDetail = paymentauditlogDescDetail.Default.(string)
|
||||
// paymentauditlogDescOperator is the schema descriptor for operator field.
|
||||
paymentauditlogDescOperator := paymentauditlogFields[3].Descriptor()
|
||||
// paymentauditlog.DefaultOperator holds the default value on creation for the operator field.
|
||||
paymentauditlog.DefaultOperator = paymentauditlogDescOperator.Default.(string)
|
||||
// paymentauditlog.OperatorValidator is a validator for the "operator" field. It is called by the builders before save.
|
||||
paymentauditlog.OperatorValidator = paymentauditlogDescOperator.Validators[0].(func(string) error)
|
||||
// paymentauditlogDescCreatedAt is the schema descriptor for created_at field.
|
||||
paymentauditlogDescCreatedAt := paymentauditlogFields[4].Descriptor()
|
||||
// paymentauditlog.DefaultCreatedAt holds the default value on creation for the created_at field.
|
||||
paymentauditlog.DefaultCreatedAt = paymentauditlogDescCreatedAt.Default.(func() time.Time)
|
||||
paymentorderFields := schema.PaymentOrder{}.Fields()
|
||||
_ = paymentorderFields
|
||||
// paymentorderDescUserEmail is the schema descriptor for user_email field.
|
||||
paymentorderDescUserEmail := paymentorderFields[1].Descriptor()
|
||||
// paymentorder.UserEmailValidator is a validator for the "user_email" field. It is called by the builders before save.
|
||||
paymentorder.UserEmailValidator = paymentorderDescUserEmail.Validators[0].(func(string) error)
|
||||
// paymentorderDescUserName is the schema descriptor for user_name field.
|
||||
paymentorderDescUserName := paymentorderFields[2].Descriptor()
|
||||
// paymentorder.UserNameValidator is a validator for the "user_name" field. It is called by the builders before save.
|
||||
paymentorder.UserNameValidator = paymentorderDescUserName.Validators[0].(func(string) error)
|
||||
// paymentorderDescFeeRate is the schema descriptor for fee_rate field.
|
||||
paymentorderDescFeeRate := paymentorderFields[6].Descriptor()
|
||||
// paymentorder.DefaultFeeRate holds the default value on creation for the fee_rate field.
|
||||
paymentorder.DefaultFeeRate = paymentorderDescFeeRate.Default.(float64)
|
||||
// paymentorderDescRechargeCode is the schema descriptor for recharge_code field.
|
||||
paymentorderDescRechargeCode := paymentorderFields[7].Descriptor()
|
||||
// paymentorder.RechargeCodeValidator is a validator for the "recharge_code" field. It is called by the builders before save.
|
||||
paymentorder.RechargeCodeValidator = paymentorderDescRechargeCode.Validators[0].(func(string) error)
|
||||
// paymentorderDescPaymentType is the schema descriptor for payment_type field.
|
||||
paymentorderDescPaymentType := paymentorderFields[8].Descriptor()
|
||||
// paymentorder.PaymentTypeValidator is a validator for the "payment_type" field. It is called by the builders before save.
|
||||
paymentorder.PaymentTypeValidator = paymentorderDescPaymentType.Validators[0].(func(string) error)
|
||||
// paymentorderDescPaymentTradeNo is the schema descriptor for payment_trade_no field.
|
||||
paymentorderDescPaymentTradeNo := paymentorderFields[9].Descriptor()
|
||||
// paymentorder.PaymentTradeNoValidator is a validator for the "payment_trade_no" field. It is called by the builders before save.
|
||||
paymentorder.PaymentTradeNoValidator = paymentorderDescPaymentTradeNo.Validators[0].(func(string) error)
|
||||
// paymentorderDescOrderType is the schema descriptor for order_type field.
|
||||
paymentorderDescOrderType := paymentorderFields[13].Descriptor()
|
||||
// paymentorder.DefaultOrderType holds the default value on creation for the order_type field.
|
||||
paymentorder.DefaultOrderType = paymentorderDescOrderType.Default.(string)
|
||||
// paymentorder.OrderTypeValidator is a validator for the "order_type" field. It is called by the builders before save.
|
||||
paymentorder.OrderTypeValidator = paymentorderDescOrderType.Validators[0].(func(string) error)
|
||||
// paymentorderDescProviderInstanceID is the schema descriptor for provider_instance_id field.
|
||||
paymentorderDescProviderInstanceID := paymentorderFields[17].Descriptor()
|
||||
// paymentorder.ProviderInstanceIDValidator is a validator for the "provider_instance_id" field. It is called by the builders before save.
|
||||
paymentorder.ProviderInstanceIDValidator = paymentorderDescProviderInstanceID.Validators[0].(func(string) error)
|
||||
// paymentorderDescStatus is the schema descriptor for status field.
|
||||
paymentorderDescStatus := paymentorderFields[18].Descriptor()
|
||||
// paymentorder.DefaultStatus holds the default value on creation for the status field.
|
||||
paymentorder.DefaultStatus = paymentorderDescStatus.Default.(string)
|
||||
// paymentorder.StatusValidator is a validator for the "status" field. It is called by the builders before save.
|
||||
paymentorder.StatusValidator = paymentorderDescStatus.Validators[0].(func(string) error)
|
||||
// paymentorderDescRefundAmount is the schema descriptor for refund_amount field.
|
||||
paymentorderDescRefundAmount := paymentorderFields[19].Descriptor()
|
||||
// paymentorder.DefaultRefundAmount holds the default value on creation for the refund_amount field.
|
||||
paymentorder.DefaultRefundAmount = paymentorderDescRefundAmount.Default.(float64)
|
||||
// paymentorderDescForceRefund is the schema descriptor for force_refund field.
|
||||
paymentorderDescForceRefund := paymentorderFields[22].Descriptor()
|
||||
// paymentorder.DefaultForceRefund holds the default value on creation for the force_refund field.
|
||||
paymentorder.DefaultForceRefund = paymentorderDescForceRefund.Default.(bool)
|
||||
// paymentorderDescRefundRequestedBy is the schema descriptor for refund_requested_by field.
|
||||
paymentorderDescRefundRequestedBy := paymentorderFields[25].Descriptor()
|
||||
// paymentorder.RefundRequestedByValidator is a validator for the "refund_requested_by" field. It is called by the builders before save.
|
||||
paymentorder.RefundRequestedByValidator = paymentorderDescRefundRequestedBy.Validators[0].(func(string) error)
|
||||
// paymentorderDescClientIP is the schema descriptor for client_ip field.
|
||||
paymentorderDescClientIP := paymentorderFields[31].Descriptor()
|
||||
// paymentorder.ClientIPValidator is a validator for the "client_ip" field. It is called by the builders before save.
|
||||
paymentorder.ClientIPValidator = paymentorderDescClientIP.Validators[0].(func(string) error)
|
||||
// paymentorderDescSrcHost is the schema descriptor for src_host field.
|
||||
paymentorderDescSrcHost := paymentorderFields[32].Descriptor()
|
||||
// paymentorder.SrcHostValidator is a validator for the "src_host" field. It is called by the builders before save.
|
||||
paymentorder.SrcHostValidator = paymentorderDescSrcHost.Validators[0].(func(string) error)
|
||||
// paymentorderDescCreatedAt is the schema descriptor for created_at field.
|
||||
paymentorderDescCreatedAt := paymentorderFields[34].Descriptor()
|
||||
// paymentorder.DefaultCreatedAt holds the default value on creation for the created_at field.
|
||||
paymentorder.DefaultCreatedAt = paymentorderDescCreatedAt.Default.(func() time.Time)
|
||||
// paymentorderDescUpdatedAt is the schema descriptor for updated_at field.
|
||||
paymentorderDescUpdatedAt := paymentorderFields[35].Descriptor()
|
||||
// paymentorder.DefaultUpdatedAt holds the default value on creation for the updated_at field.
|
||||
paymentorder.DefaultUpdatedAt = paymentorderDescUpdatedAt.Default.(func() time.Time)
|
||||
// paymentorder.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
|
||||
paymentorder.UpdateDefaultUpdatedAt = paymentorderDescUpdatedAt.UpdateDefault.(func() time.Time)
|
||||
paymentproviderinstanceFields := schema.PaymentProviderInstance{}.Fields()
|
||||
_ = paymentproviderinstanceFields
|
||||
// paymentproviderinstanceDescProviderKey is the schema descriptor for provider_key field.
|
||||
paymentproviderinstanceDescProviderKey := paymentproviderinstanceFields[0].Descriptor()
|
||||
// paymentproviderinstance.ProviderKeyValidator is a validator for the "provider_key" field. It is called by the builders before save.
|
||||
paymentproviderinstance.ProviderKeyValidator = func() func(string) error {
|
||||
validators := paymentproviderinstanceDescProviderKey.Validators
|
||||
fns := [...]func(string) error{
|
||||
validators[0].(func(string) error),
|
||||
validators[1].(func(string) error),
|
||||
}
|
||||
return func(provider_key string) error {
|
||||
for _, fn := range fns {
|
||||
if err := fn(provider_key); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
// paymentproviderinstanceDescName is the schema descriptor for name field.
|
||||
paymentproviderinstanceDescName := paymentproviderinstanceFields[1].Descriptor()
|
||||
// paymentproviderinstance.DefaultName holds the default value on creation for the name field.
|
||||
paymentproviderinstance.DefaultName = paymentproviderinstanceDescName.Default.(string)
|
||||
// paymentproviderinstance.NameValidator is a validator for the "name" field. It is called by the builders before save.
|
||||
paymentproviderinstance.NameValidator = paymentproviderinstanceDescName.Validators[0].(func(string) error)
|
||||
// paymentproviderinstanceDescSupportedTypes is the schema descriptor for supported_types field.
|
||||
paymentproviderinstanceDescSupportedTypes := paymentproviderinstanceFields[3].Descriptor()
|
||||
// paymentproviderinstance.DefaultSupportedTypes holds the default value on creation for the supported_types field.
|
||||
paymentproviderinstance.DefaultSupportedTypes = paymentproviderinstanceDescSupportedTypes.Default.(string)
|
||||
// paymentproviderinstance.SupportedTypesValidator is a validator for the "supported_types" field. It is called by the builders before save.
|
||||
paymentproviderinstance.SupportedTypesValidator = paymentproviderinstanceDescSupportedTypes.Validators[0].(func(string) error)
|
||||
// paymentproviderinstanceDescEnabled is the schema descriptor for enabled field.
|
||||
paymentproviderinstanceDescEnabled := paymentproviderinstanceFields[4].Descriptor()
|
||||
// paymentproviderinstance.DefaultEnabled holds the default value on creation for the enabled field.
|
||||
paymentproviderinstance.DefaultEnabled = paymentproviderinstanceDescEnabled.Default.(bool)
|
||||
// paymentproviderinstanceDescSortOrder is the schema descriptor for sort_order field.
|
||||
paymentproviderinstanceDescSortOrder := paymentproviderinstanceFields[5].Descriptor()
|
||||
// paymentproviderinstance.DefaultSortOrder holds the default value on creation for the sort_order field.
|
||||
paymentproviderinstance.DefaultSortOrder = paymentproviderinstanceDescSortOrder.Default.(int)
|
||||
// paymentproviderinstanceDescLimits is the schema descriptor for limits field.
|
||||
paymentproviderinstanceDescLimits := paymentproviderinstanceFields[6].Descriptor()
|
||||
// paymentproviderinstance.DefaultLimits holds the default value on creation for the limits field.
|
||||
paymentproviderinstance.DefaultLimits = paymentproviderinstanceDescLimits.Default.(string)
|
||||
// paymentproviderinstanceDescRefundEnabled is the schema descriptor for refund_enabled field.
|
||||
paymentproviderinstanceDescRefundEnabled := paymentproviderinstanceFields[7].Descriptor()
|
||||
// paymentproviderinstance.DefaultRefundEnabled holds the default value on creation for the refund_enabled field.
|
||||
paymentproviderinstance.DefaultRefundEnabled = paymentproviderinstanceDescRefundEnabled.Default.(bool)
|
||||
// paymentproviderinstanceDescCreatedAt is the schema descriptor for created_at field.
|
||||
paymentproviderinstanceDescCreatedAt := paymentproviderinstanceFields[8].Descriptor()
|
||||
// paymentproviderinstance.DefaultCreatedAt holds the default value on creation for the created_at field.
|
||||
paymentproviderinstance.DefaultCreatedAt = paymentproviderinstanceDescCreatedAt.Default.(func() time.Time)
|
||||
// paymentproviderinstanceDescUpdatedAt is the schema descriptor for updated_at field.
|
||||
paymentproviderinstanceDescUpdatedAt := paymentproviderinstanceFields[9].Descriptor()
|
||||
// paymentproviderinstance.DefaultUpdatedAt holds the default value on creation for the updated_at field.
|
||||
paymentproviderinstance.DefaultUpdatedAt = paymentproviderinstanceDescUpdatedAt.Default.(func() time.Time)
|
||||
// paymentproviderinstance.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
|
||||
paymentproviderinstance.UpdateDefaultUpdatedAt = paymentproviderinstanceDescUpdatedAt.UpdateDefault.(func() time.Time)
|
||||
promocodeFields := schema.PromoCode{}.Fields()
|
||||
_ = promocodeFields
|
||||
// promocodeDescCode is the schema descriptor for code field.
|
||||
@@ -751,6 +909,68 @@ func init() {
|
||||
setting.DefaultUpdatedAt = settingDescUpdatedAt.Default.(func() time.Time)
|
||||
// setting.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
|
||||
setting.UpdateDefaultUpdatedAt = settingDescUpdatedAt.UpdateDefault.(func() time.Time)
|
||||
subscriptionplanFields := schema.SubscriptionPlan{}.Fields()
|
||||
_ = subscriptionplanFields
|
||||
// subscriptionplanDescName is the schema descriptor for name field.
|
||||
subscriptionplanDescName := subscriptionplanFields[1].Descriptor()
|
||||
// subscriptionplan.NameValidator is a validator for the "name" field. It is called by the builders before save.
|
||||
subscriptionplan.NameValidator = func() func(string) error {
|
||||
validators := subscriptionplanDescName.Validators
|
||||
fns := [...]func(string) error{
|
||||
validators[0].(func(string) error),
|
||||
validators[1].(func(string) error),
|
||||
}
|
||||
return func(name string) error {
|
||||
for _, fn := range fns {
|
||||
if err := fn(name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}()
|
||||
// subscriptionplanDescDescription is the schema descriptor for description field.
|
||||
subscriptionplanDescDescription := subscriptionplanFields[2].Descriptor()
|
||||
// subscriptionplan.DefaultDescription holds the default value on creation for the description field.
|
||||
subscriptionplan.DefaultDescription = subscriptionplanDescDescription.Default.(string)
|
||||
// subscriptionplanDescValidityDays is the schema descriptor for validity_days field.
|
||||
subscriptionplanDescValidityDays := subscriptionplanFields[5].Descriptor()
|
||||
// subscriptionplan.DefaultValidityDays holds the default value on creation for the validity_days field.
|
||||
subscriptionplan.DefaultValidityDays = subscriptionplanDescValidityDays.Default.(int)
|
||||
// subscriptionplanDescValidityUnit is the schema descriptor for validity_unit field.
|
||||
subscriptionplanDescValidityUnit := subscriptionplanFields[6].Descriptor()
|
||||
// subscriptionplan.DefaultValidityUnit holds the default value on creation for the validity_unit field.
|
||||
subscriptionplan.DefaultValidityUnit = subscriptionplanDescValidityUnit.Default.(string)
|
||||
// subscriptionplan.ValidityUnitValidator is a validator for the "validity_unit" field. It is called by the builders before save.
|
||||
subscriptionplan.ValidityUnitValidator = subscriptionplanDescValidityUnit.Validators[0].(func(string) error)
|
||||
// subscriptionplanDescFeatures is the schema descriptor for features field.
|
||||
subscriptionplanDescFeatures := subscriptionplanFields[7].Descriptor()
|
||||
// subscriptionplan.DefaultFeatures holds the default value on creation for the features field.
|
||||
subscriptionplan.DefaultFeatures = subscriptionplanDescFeatures.Default.(string)
|
||||
// subscriptionplanDescProductName is the schema descriptor for product_name field.
|
||||
subscriptionplanDescProductName := subscriptionplanFields[8].Descriptor()
|
||||
// subscriptionplan.DefaultProductName holds the default value on creation for the product_name field.
|
||||
subscriptionplan.DefaultProductName = subscriptionplanDescProductName.Default.(string)
|
||||
// subscriptionplan.ProductNameValidator is a validator for the "product_name" field. It is called by the builders before save.
|
||||
subscriptionplan.ProductNameValidator = subscriptionplanDescProductName.Validators[0].(func(string) error)
|
||||
// subscriptionplanDescForSale is the schema descriptor for for_sale field.
|
||||
subscriptionplanDescForSale := subscriptionplanFields[9].Descriptor()
|
||||
// subscriptionplan.DefaultForSale holds the default value on creation for the for_sale field.
|
||||
subscriptionplan.DefaultForSale = subscriptionplanDescForSale.Default.(bool)
|
||||
// subscriptionplanDescSortOrder is the schema descriptor for sort_order field.
|
||||
subscriptionplanDescSortOrder := subscriptionplanFields[10].Descriptor()
|
||||
// subscriptionplan.DefaultSortOrder holds the default value on creation for the sort_order field.
|
||||
subscriptionplan.DefaultSortOrder = subscriptionplanDescSortOrder.Default.(int)
|
||||
// subscriptionplanDescCreatedAt is the schema descriptor for created_at field.
|
||||
subscriptionplanDescCreatedAt := subscriptionplanFields[11].Descriptor()
|
||||
// subscriptionplan.DefaultCreatedAt holds the default value on creation for the created_at field.
|
||||
subscriptionplan.DefaultCreatedAt = subscriptionplanDescCreatedAt.Default.(func() time.Time)
|
||||
// subscriptionplanDescUpdatedAt is the schema descriptor for updated_at field.
|
||||
subscriptionplanDescUpdatedAt := subscriptionplanFields[12].Descriptor()
|
||||
// subscriptionplan.DefaultUpdatedAt holds the default value on creation for the updated_at field.
|
||||
subscriptionplan.DefaultUpdatedAt = subscriptionplanDescUpdatedAt.Default.(func() time.Time)
|
||||
// subscriptionplan.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
|
||||
subscriptionplan.UpdateDefaultUpdatedAt = subscriptionplanDescUpdatedAt.UpdateDefault.(func() time.Time)
|
||||
tlsfingerprintprofileMixin := schema.TLSFingerprintProfile{}.Mixin()
|
||||
tlsfingerprintprofileMixinFields0 := tlsfingerprintprofileMixin[0].Fields()
|
||||
_ = tlsfingerprintprofileMixinFields0
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
"entgo.io/ent/dialect/entsql"
|
||||
"entgo.io/ent/schema"
|
||||
"entgo.io/ent/schema/field"
|
||||
"entgo.io/ent/schema/index"
|
||||
)
|
||||
|
||||
// PaymentAuditLog holds the schema definition for the PaymentAuditLog entity.
|
||||
//
|
||||
// 删除策略:硬删除
|
||||
// PaymentAuditLog 使用硬删除而非软删除,原因如下:
|
||||
// - 审计日志本身即为不可变记录,通常只追加不修改
|
||||
// - 如需清理历史日志,直接按时间范围批量删除即可
|
||||
// - 保持表结构简洁,提升插入和查询性能
|
||||
type PaymentAuditLog struct {
|
||||
ent.Schema
|
||||
}
|
||||
|
||||
func (PaymentAuditLog) Annotations() []schema.Annotation {
|
||||
return []schema.Annotation{
|
||||
entsql.Annotation{Table: "payment_audit_logs"},
|
||||
}
|
||||
}
|
||||
|
||||
func (PaymentAuditLog) Fields() []ent.Field {
|
||||
return []ent.Field{
|
||||
field.String("order_id").
|
||||
MaxLen(64),
|
||||
field.String("action").
|
||||
MaxLen(50),
|
||||
field.String("detail").
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}).
|
||||
Default(""),
|
||||
field.String("operator").
|
||||
MaxLen(100).
|
||||
Default("system"),
|
||||
field.Time("created_at").
|
||||
Immutable().
|
||||
Default(time.Now).
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
}
|
||||
}
|
||||
|
||||
func (PaymentAuditLog) Indexes() []ent.Index {
|
||||
return []ent.Index{
|
||||
index.Fields("order_id"),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
"entgo.io/ent/dialect/entsql"
|
||||
"entgo.io/ent/schema"
|
||||
"entgo.io/ent/schema/edge"
|
||||
"entgo.io/ent/schema/field"
|
||||
"entgo.io/ent/schema/index"
|
||||
)
|
||||
|
||||
// PaymentOrder holds the schema definition for the PaymentOrder entity.
|
||||
//
|
||||
// 删除策略:硬删除
|
||||
// PaymentOrder 使用硬删除而非软删除,原因如下:
|
||||
// - 订单通过 status 字段追踪完整生命周期,无需依赖软删除
|
||||
// - 订单审计通过 PaymentAuditLog 表记录,删除前可归档
|
||||
// - 减少查询复杂度,避免软删除过滤开销
|
||||
type PaymentOrder struct {
|
||||
ent.Schema
|
||||
}
|
||||
|
||||
func (PaymentOrder) Annotations() []schema.Annotation {
|
||||
return []schema.Annotation{
|
||||
entsql.Annotation{Table: "payment_orders"},
|
||||
}
|
||||
}
|
||||
|
||||
func (PaymentOrder) Fields() []ent.Field {
|
||||
return []ent.Field{
|
||||
// 用户信息(冗余存储,避免关联查询)
|
||||
field.Int64("user_id"),
|
||||
field.String("user_email").
|
||||
MaxLen(255),
|
||||
field.String("user_name").
|
||||
MaxLen(100),
|
||||
field.String("user_notes").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
|
||||
// 金额信息
|
||||
field.Float("amount").
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,2)"}),
|
||||
field.Float("pay_amount").
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,2)"}),
|
||||
field.Float("fee_rate").
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(10,4)"}).
|
||||
Default(0),
|
||||
field.String("recharge_code").
|
||||
MaxLen(64),
|
||||
|
||||
// 支付信息
|
||||
field.String("payment_type").
|
||||
MaxLen(30),
|
||||
field.String("payment_trade_no").
|
||||
MaxLen(128),
|
||||
field.String("pay_url").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
field.String("qr_code").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
field.String("qr_code_img").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
|
||||
// 订单类型 & 订阅关联
|
||||
field.String("order_type").
|
||||
MaxLen(20).
|
||||
Default("balance"),
|
||||
field.Int64("plan_id").
|
||||
Optional().
|
||||
Nillable(),
|
||||
field.Int64("subscription_group_id").
|
||||
Optional().
|
||||
Nillable(),
|
||||
field.Int("subscription_days").
|
||||
Optional().
|
||||
Nillable(),
|
||||
field.String("provider_instance_id").
|
||||
Optional().
|
||||
Nillable().
|
||||
MaxLen(64),
|
||||
|
||||
// 状态
|
||||
field.String("status").
|
||||
MaxLen(30).
|
||||
Default("PENDING"),
|
||||
|
||||
// 退款信息
|
||||
field.Float("refund_amount").
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,2)"}).
|
||||
Default(0),
|
||||
field.String("refund_reason").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
field.Time("refund_at").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.Bool("force_refund").
|
||||
Default(false),
|
||||
field.Time("refund_requested_at").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.String("refund_request_reason").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
field.String("refund_requested_by").
|
||||
Optional().
|
||||
Nillable().
|
||||
MaxLen(20),
|
||||
|
||||
// 时间节点
|
||||
field.Time("expires_at").
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.Time("paid_at").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.Time("completed_at").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.Time("failed_at").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.String("failed_reason").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
|
||||
// 来源信息
|
||||
field.String("client_ip").
|
||||
MaxLen(50),
|
||||
field.String("src_host").
|
||||
MaxLen(255),
|
||||
field.String("src_url").
|
||||
Optional().
|
||||
Nillable().
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
|
||||
// 时间戳
|
||||
field.Time("created_at").
|
||||
Immutable().
|
||||
Default(time.Now).
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.Time("updated_at").
|
||||
Default(time.Now).
|
||||
UpdateDefault(time.Now).
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
}
|
||||
}
|
||||
|
||||
func (PaymentOrder) Edges() []ent.Edge {
|
||||
return []ent.Edge{
|
||||
edge.From("user", User.Type).
|
||||
Ref("payment_orders").
|
||||
Field("user_id").
|
||||
Unique().
|
||||
Required(),
|
||||
}
|
||||
}
|
||||
|
||||
func (PaymentOrder) Indexes() []ent.Index {
|
||||
return []ent.Index{
|
||||
index.Fields("user_id"),
|
||||
index.Fields("status"),
|
||||
index.Fields("expires_at"),
|
||||
index.Fields("created_at"),
|
||||
index.Fields("paid_at"),
|
||||
index.Fields("payment_type", "paid_at"),
|
||||
index.Fields("order_type"),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
"entgo.io/ent/dialect/entsql"
|
||||
"entgo.io/ent/schema"
|
||||
"entgo.io/ent/schema/field"
|
||||
"entgo.io/ent/schema/index"
|
||||
)
|
||||
|
||||
// PaymentProviderInstance holds the schema definition for the PaymentProviderInstance entity.
|
||||
//
|
||||
// 删除策略:硬删除
|
||||
// PaymentProviderInstance 使用硬删除而非软删除,原因如下:
|
||||
// - 服务商实例为管理员配置的支付通道,删除即表示废弃
|
||||
// - 通过 enabled 字段控制是否启用,删除仅用于彻底移除
|
||||
// - config 字段存储加密后的密钥信息,删除时应彻底清除
|
||||
type PaymentProviderInstance struct {
|
||||
ent.Schema
|
||||
}
|
||||
|
||||
func (PaymentProviderInstance) Annotations() []schema.Annotation {
|
||||
return []schema.Annotation{
|
||||
entsql.Annotation{Table: "payment_provider_instances"},
|
||||
}
|
||||
}
|
||||
|
||||
func (PaymentProviderInstance) Fields() []ent.Field {
|
||||
return []ent.Field{
|
||||
field.String("provider_key").
|
||||
MaxLen(30).
|
||||
NotEmpty(),
|
||||
field.String("name").
|
||||
MaxLen(100).
|
||||
Default(""),
|
||||
field.String("config").
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}),
|
||||
field.String("supported_types").
|
||||
MaxLen(200).
|
||||
Default(""),
|
||||
field.Bool("enabled").
|
||||
Default(true),
|
||||
field.Int("sort_order").
|
||||
Default(0),
|
||||
field.String("limits").
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}).
|
||||
Default(""),
|
||||
field.Bool("refund_enabled").
|
||||
Default(false),
|
||||
field.Time("created_at").
|
||||
Immutable().
|
||||
Default(time.Now).
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.Time("updated_at").
|
||||
Default(time.Now).
|
||||
UpdateDefault(time.Now).
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
}
|
||||
}
|
||||
|
||||
func (PaymentProviderInstance) Indexes() []ent.Index {
|
||||
return []ent.Index{
|
||||
index.Fields("provider_key"),
|
||||
index.Fields("enabled"),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
"entgo.io/ent/dialect/entsql"
|
||||
"entgo.io/ent/schema"
|
||||
"entgo.io/ent/schema/field"
|
||||
"entgo.io/ent/schema/index"
|
||||
)
|
||||
|
||||
// SubscriptionPlan holds the schema definition for the SubscriptionPlan entity.
|
||||
//
|
||||
// 删除策略:硬删除
|
||||
// SubscriptionPlan 使用硬删除而非软删除,原因如下:
|
||||
// - 套餐为管理员维护的商品配置,删除即表示下架移除
|
||||
// - 通过 for_sale 字段控制是否在售,删除仅用于彻底移除
|
||||
// - 已购买的订阅记录保存在 UserSubscription 中,不受套餐删除影响
|
||||
type SubscriptionPlan struct {
|
||||
ent.Schema
|
||||
}
|
||||
|
||||
func (SubscriptionPlan) Annotations() []schema.Annotation {
|
||||
return []schema.Annotation{
|
||||
entsql.Annotation{Table: "subscription_plans"},
|
||||
}
|
||||
}
|
||||
|
||||
func (SubscriptionPlan) Fields() []ent.Field {
|
||||
return []ent.Field{
|
||||
field.Int64("group_id"),
|
||||
field.String("name").
|
||||
MaxLen(100).
|
||||
NotEmpty(),
|
||||
field.String("description").
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}).
|
||||
Default(""),
|
||||
field.Float("price").
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,2)"}),
|
||||
field.Float("original_price").
|
||||
SchemaType(map[string]string{dialect.Postgres: "decimal(20,2)"}).
|
||||
Optional().
|
||||
Nillable(),
|
||||
field.Int("validity_days").
|
||||
Default(30),
|
||||
field.String("validity_unit").
|
||||
MaxLen(10).
|
||||
Default("day"),
|
||||
field.String("features").
|
||||
SchemaType(map[string]string{dialect.Postgres: "text"}).
|
||||
Default(""),
|
||||
field.String("product_name").
|
||||
MaxLen(100).
|
||||
Default(""),
|
||||
field.Bool("for_sale").
|
||||
Default(true),
|
||||
field.Int("sort_order").
|
||||
Default(0),
|
||||
field.Time("created_at").
|
||||
Immutable().
|
||||
Default(time.Now).
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
field.Time("updated_at").
|
||||
Default(time.Now).
|
||||
UpdateDefault(time.Now).
|
||||
SchemaType(map[string]string{dialect.Postgres: "timestamptz"}),
|
||||
}
|
||||
}
|
||||
|
||||
func (SubscriptionPlan) Indexes() []ent.Index {
|
||||
return []ent.Index{
|
||||
index.Fields("group_id"),
|
||||
index.Fields("for_sale"),
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,7 @@ func (User) Edges() []ent.Edge {
|
||||
edge.To("usage_logs", UsageLog.Type),
|
||||
edge.To("attribute_values", UserAttributeValue.Type),
|
||||
edge.To("promo_code_usages", PromoCodeUsage.Type),
|
||||
edge.To("payment_orders", PaymentOrder.Type),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
)
|
||||
|
||||
// SubscriptionPlan is the model entity for the SubscriptionPlan schema.
|
||||
type SubscriptionPlan struct {
|
||||
config `json:"-"`
|
||||
// ID of the ent.
|
||||
ID int64 `json:"id,omitempty"`
|
||||
// GroupID holds the value of the "group_id" field.
|
||||
GroupID int64 `json:"group_id,omitempty"`
|
||||
// Name holds the value of the "name" field.
|
||||
Name string `json:"name,omitempty"`
|
||||
// Description holds the value of the "description" field.
|
||||
Description string `json:"description,omitempty"`
|
||||
// Price holds the value of the "price" field.
|
||||
Price float64 `json:"price,omitempty"`
|
||||
// OriginalPrice holds the value of the "original_price" field.
|
||||
OriginalPrice *float64 `json:"original_price,omitempty"`
|
||||
// ValidityDays holds the value of the "validity_days" field.
|
||||
ValidityDays int `json:"validity_days,omitempty"`
|
||||
// ValidityUnit holds the value of the "validity_unit" field.
|
||||
ValidityUnit string `json:"validity_unit,omitempty"`
|
||||
// Features holds the value of the "features" field.
|
||||
Features string `json:"features,omitempty"`
|
||||
// ProductName holds the value of the "product_name" field.
|
||||
ProductName string `json:"product_name,omitempty"`
|
||||
// ForSale holds the value of the "for_sale" field.
|
||||
ForSale bool `json:"for_sale,omitempty"`
|
||||
// SortOrder holds the value of the "sort_order" field.
|
||||
SortOrder int `json:"sort_order,omitempty"`
|
||||
// CreatedAt holds the value of the "created_at" field.
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
// UpdatedAt holds the value of the "updated_at" field.
|
||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||
selectValues sql.SelectValues
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*SubscriptionPlan) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case subscriptionplan.FieldForSale:
|
||||
values[i] = new(sql.NullBool)
|
||||
case subscriptionplan.FieldPrice, subscriptionplan.FieldOriginalPrice:
|
||||
values[i] = new(sql.NullFloat64)
|
||||
case subscriptionplan.FieldID, subscriptionplan.FieldGroupID, subscriptionplan.FieldValidityDays, subscriptionplan.FieldSortOrder:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case subscriptionplan.FieldName, subscriptionplan.FieldDescription, subscriptionplan.FieldValidityUnit, subscriptionplan.FieldFeatures, subscriptionplan.FieldProductName:
|
||||
values[i] = new(sql.NullString)
|
||||
case subscriptionplan.FieldCreatedAt, subscriptionplan.FieldUpdatedAt:
|
||||
values[i] = new(sql.NullTime)
|
||||
default:
|
||||
values[i] = new(sql.UnknownType)
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the SubscriptionPlan fields.
|
||||
func (_m *SubscriptionPlan) assignValues(columns []string, values []any) error {
|
||||
if m, n := len(values), len(columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case subscriptionplan.FieldID:
|
||||
value, ok := values[i].(*sql.NullInt64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field id", value)
|
||||
}
|
||||
_m.ID = int64(value.Int64)
|
||||
case subscriptionplan.FieldGroupID:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field group_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.GroupID = value.Int64
|
||||
}
|
||||
case subscriptionplan.FieldName:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field name", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Name = value.String
|
||||
}
|
||||
case subscriptionplan.FieldDescription:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field description", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Description = value.String
|
||||
}
|
||||
case subscriptionplan.FieldPrice:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field price", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Price = value.Float64
|
||||
}
|
||||
case subscriptionplan.FieldOriginalPrice:
|
||||
if value, ok := values[i].(*sql.NullFloat64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field original_price", values[i])
|
||||
} else if value.Valid {
|
||||
_m.OriginalPrice = new(float64)
|
||||
*_m.OriginalPrice = value.Float64
|
||||
}
|
||||
case subscriptionplan.FieldValidityDays:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field validity_days", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ValidityDays = int(value.Int64)
|
||||
}
|
||||
case subscriptionplan.FieldValidityUnit:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field validity_unit", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ValidityUnit = value.String
|
||||
}
|
||||
case subscriptionplan.FieldFeatures:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field features", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Features = value.String
|
||||
}
|
||||
case subscriptionplan.FieldProductName:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field product_name", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ProductName = value.String
|
||||
}
|
||||
case subscriptionplan.FieldForSale:
|
||||
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field for_sale", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ForSale = value.Bool
|
||||
}
|
||||
case subscriptionplan.FieldSortOrder:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field sort_order", values[i])
|
||||
} else if value.Valid {
|
||||
_m.SortOrder = int(value.Int64)
|
||||
}
|
||||
case subscriptionplan.FieldCreatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.CreatedAt = value.Time
|
||||
}
|
||||
case subscriptionplan.FieldUpdatedAt:
|
||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
|
||||
} else if value.Valid {
|
||||
_m.UpdatedAt = value.Time
|
||||
}
|
||||
default:
|
||||
_m.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns the ent.Value that was dynamically selected and assigned to the SubscriptionPlan.
|
||||
// This includes values selected through modifiers, order, etc.
|
||||
func (_m *SubscriptionPlan) Value(name string) (ent.Value, error) {
|
||||
return _m.selectValues.Get(name)
|
||||
}
|
||||
|
||||
// Update returns a builder for updating this SubscriptionPlan.
|
||||
// Note that you need to call SubscriptionPlan.Unwrap() before calling this method if this SubscriptionPlan
|
||||
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||
func (_m *SubscriptionPlan) Update() *SubscriptionPlanUpdateOne {
|
||||
return NewSubscriptionPlanClient(_m.config).UpdateOne(_m)
|
||||
}
|
||||
|
||||
// Unwrap unwraps the SubscriptionPlan entity that was returned from a transaction after it was closed,
|
||||
// so that all future queries will be executed through the driver which created the transaction.
|
||||
func (_m *SubscriptionPlan) Unwrap() *SubscriptionPlan {
|
||||
_tx, ok := _m.config.driver.(*txDriver)
|
||||
if !ok {
|
||||
panic("ent: SubscriptionPlan is not a transactional entity")
|
||||
}
|
||||
_m.config.driver = _tx.drv
|
||||
return _m
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer.
|
||||
func (_m *SubscriptionPlan) String() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("SubscriptionPlan(")
|
||||
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
|
||||
builder.WriteString("group_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.GroupID))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("name=")
|
||||
builder.WriteString(_m.Name)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("description=")
|
||||
builder.WriteString(_m.Description)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("price=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Price))
|
||||
builder.WriteString(", ")
|
||||
if v := _m.OriginalPrice; v != nil {
|
||||
builder.WriteString("original_price=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("validity_days=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.ValidityDays))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("validity_unit=")
|
||||
builder.WriteString(_m.ValidityUnit)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("features=")
|
||||
builder.WriteString(_m.Features)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("product_name=")
|
||||
builder.WriteString(_m.ProductName)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("for_sale=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.ForSale))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("sort_order=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.SortOrder))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("created_at=")
|
||||
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("updated_at=")
|
||||
builder.WriteString(_m.UpdatedAt.Format(time.ANSIC))
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// SubscriptionPlans is a parsable slice of SubscriptionPlan.
|
||||
type SubscriptionPlans []*SubscriptionPlan
|
||||
@@ -0,0 +1,174 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package subscriptionplan
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
)
|
||||
|
||||
const (
|
||||
// Label holds the string label denoting the subscriptionplan type in the database.
|
||||
Label = "subscription_plan"
|
||||
// FieldID holds the string denoting the id field in the database.
|
||||
FieldID = "id"
|
||||
// FieldGroupID holds the string denoting the group_id field in the database.
|
||||
FieldGroupID = "group_id"
|
||||
// FieldName holds the string denoting the name field in the database.
|
||||
FieldName = "name"
|
||||
// FieldDescription holds the string denoting the description field in the database.
|
||||
FieldDescription = "description"
|
||||
// FieldPrice holds the string denoting the price field in the database.
|
||||
FieldPrice = "price"
|
||||
// FieldOriginalPrice holds the string denoting the original_price field in the database.
|
||||
FieldOriginalPrice = "original_price"
|
||||
// FieldValidityDays holds the string denoting the validity_days field in the database.
|
||||
FieldValidityDays = "validity_days"
|
||||
// FieldValidityUnit holds the string denoting the validity_unit field in the database.
|
||||
FieldValidityUnit = "validity_unit"
|
||||
// FieldFeatures holds the string denoting the features field in the database.
|
||||
FieldFeatures = "features"
|
||||
// FieldProductName holds the string denoting the product_name field in the database.
|
||||
FieldProductName = "product_name"
|
||||
// FieldForSale holds the string denoting the for_sale field in the database.
|
||||
FieldForSale = "for_sale"
|
||||
// FieldSortOrder holds the string denoting the sort_order field in the database.
|
||||
FieldSortOrder = "sort_order"
|
||||
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
||||
FieldCreatedAt = "created_at"
|
||||
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
|
||||
FieldUpdatedAt = "updated_at"
|
||||
// Table holds the table name of the subscriptionplan in the database.
|
||||
Table = "subscription_plans"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns for subscriptionplan fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldGroupID,
|
||||
FieldName,
|
||||
FieldDescription,
|
||||
FieldPrice,
|
||||
FieldOriginalPrice,
|
||||
FieldValidityDays,
|
||||
FieldValidityUnit,
|
||||
FieldFeatures,
|
||||
FieldProductName,
|
||||
FieldForSale,
|
||||
FieldSortOrder,
|
||||
FieldCreatedAt,
|
||||
FieldUpdatedAt,
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
func ValidColumn(column string) bool {
|
||||
for i := range Columns {
|
||||
if column == Columns[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
// NameValidator is a validator for the "name" field. It is called by the builders before save.
|
||||
NameValidator func(string) error
|
||||
// DefaultDescription holds the default value on creation for the "description" field.
|
||||
DefaultDescription string
|
||||
// DefaultValidityDays holds the default value on creation for the "validity_days" field.
|
||||
DefaultValidityDays int
|
||||
// DefaultValidityUnit holds the default value on creation for the "validity_unit" field.
|
||||
DefaultValidityUnit string
|
||||
// ValidityUnitValidator is a validator for the "validity_unit" field. It is called by the builders before save.
|
||||
ValidityUnitValidator func(string) error
|
||||
// DefaultFeatures holds the default value on creation for the "features" field.
|
||||
DefaultFeatures string
|
||||
// DefaultProductName holds the default value on creation for the "product_name" field.
|
||||
DefaultProductName string
|
||||
// ProductNameValidator is a validator for the "product_name" field. It is called by the builders before save.
|
||||
ProductNameValidator func(string) error
|
||||
// DefaultForSale holds the default value on creation for the "for_sale" field.
|
||||
DefaultForSale bool
|
||||
// DefaultSortOrder holds the default value on creation for the "sort_order" field.
|
||||
DefaultSortOrder int
|
||||
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
||||
DefaultCreatedAt func() time.Time
|
||||
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
|
||||
DefaultUpdatedAt func() time.Time
|
||||
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
|
||||
UpdateDefaultUpdatedAt func() time.Time
|
||||
)
|
||||
|
||||
// OrderOption defines the ordering options for the SubscriptionPlan queries.
|
||||
type OrderOption func(*sql.Selector)
|
||||
|
||||
// ByID orders the results by the id field.
|
||||
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByGroupID orders the results by the group_id field.
|
||||
func ByGroupID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldGroupID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByName orders the results by the name field.
|
||||
func ByName(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldName, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByDescription orders the results by the description field.
|
||||
func ByDescription(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldDescription, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPrice orders the results by the price field.
|
||||
func ByPrice(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPrice, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByOriginalPrice orders the results by the original_price field.
|
||||
func ByOriginalPrice(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldOriginalPrice, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByValidityDays orders the results by the validity_days field.
|
||||
func ByValidityDays(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldValidityDays, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByValidityUnit orders the results by the validity_unit field.
|
||||
func ByValidityUnit(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldValidityUnit, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByFeatures orders the results by the features field.
|
||||
func ByFeatures(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldFeatures, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByProductName orders the results by the product_name field.
|
||||
func ByProductName(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldProductName, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByForSale orders the results by the for_sale field.
|
||||
func ByForSale(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldForSale, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySortOrder orders the results by the sort_order field.
|
||||
func BySortOrder(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSortOrder, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCreatedAt orders the results by the created_at field.
|
||||
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUpdatedAt orders the results by the updated_at field.
|
||||
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
|
||||
}
|
||||
@@ -0,0 +1,760 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package subscriptionplan
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
)
|
||||
|
||||
// ID filters vertices based on their ID field.
|
||||
func ID(id int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDEQ applies the EQ predicate on the ID field.
|
||||
func IDEQ(id int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDNEQ applies the NEQ predicate on the ID field.
|
||||
func IDNEQ(id int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDIn applies the In predicate on the ID field.
|
||||
func IDIn(ids ...int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDNotIn applies the NotIn predicate on the ID field.
|
||||
func IDNotIn(ids ...int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDGT applies the GT predicate on the ID field.
|
||||
func IDGT(id int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDGTE applies the GTE predicate on the ID field.
|
||||
func IDGTE(id int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLT applies the LT predicate on the ID field.
|
||||
func IDLT(id int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLTE applies the LTE predicate on the ID field.
|
||||
func IDLTE(id int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldID, id))
|
||||
}
|
||||
|
||||
// GroupID applies equality check predicate on the "group_id" field. It's identical to GroupIDEQ.
|
||||
func GroupID(v int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldGroupID, v))
|
||||
}
|
||||
|
||||
// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
|
||||
func Name(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldName, v))
|
||||
}
|
||||
|
||||
// Description applies equality check predicate on the "description" field. It's identical to DescriptionEQ.
|
||||
func Description(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldDescription, v))
|
||||
}
|
||||
|
||||
// Price applies equality check predicate on the "price" field. It's identical to PriceEQ.
|
||||
func Price(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldPrice, v))
|
||||
}
|
||||
|
||||
// OriginalPrice applies equality check predicate on the "original_price" field. It's identical to OriginalPriceEQ.
|
||||
func OriginalPrice(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldOriginalPrice, v))
|
||||
}
|
||||
|
||||
// ValidityDays applies equality check predicate on the "validity_days" field. It's identical to ValidityDaysEQ.
|
||||
func ValidityDays(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldValidityDays, v))
|
||||
}
|
||||
|
||||
// ValidityUnit applies equality check predicate on the "validity_unit" field. It's identical to ValidityUnitEQ.
|
||||
func ValidityUnit(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// Features applies equality check predicate on the "features" field. It's identical to FeaturesEQ.
|
||||
func Features(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// ProductName applies equality check predicate on the "product_name" field. It's identical to ProductNameEQ.
|
||||
func ProductName(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ForSale applies equality check predicate on the "for_sale" field. It's identical to ForSaleEQ.
|
||||
func ForSale(v bool) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldForSale, v))
|
||||
}
|
||||
|
||||
// SortOrder applies equality check predicate on the "sort_order" field. It's identical to SortOrderEQ.
|
||||
func SortOrder(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||
func CreatedAt(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
||||
func UpdatedAt(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// GroupIDEQ applies the EQ predicate on the "group_id" field.
|
||||
func GroupIDEQ(v int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldGroupID, v))
|
||||
}
|
||||
|
||||
// GroupIDNEQ applies the NEQ predicate on the "group_id" field.
|
||||
func GroupIDNEQ(v int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldGroupID, v))
|
||||
}
|
||||
|
||||
// GroupIDIn applies the In predicate on the "group_id" field.
|
||||
func GroupIDIn(vs ...int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldGroupID, vs...))
|
||||
}
|
||||
|
||||
// GroupIDNotIn applies the NotIn predicate on the "group_id" field.
|
||||
func GroupIDNotIn(vs ...int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldGroupID, vs...))
|
||||
}
|
||||
|
||||
// GroupIDGT applies the GT predicate on the "group_id" field.
|
||||
func GroupIDGT(v int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldGroupID, v))
|
||||
}
|
||||
|
||||
// GroupIDGTE applies the GTE predicate on the "group_id" field.
|
||||
func GroupIDGTE(v int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldGroupID, v))
|
||||
}
|
||||
|
||||
// GroupIDLT applies the LT predicate on the "group_id" field.
|
||||
func GroupIDLT(v int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldGroupID, v))
|
||||
}
|
||||
|
||||
// GroupIDLTE applies the LTE predicate on the "group_id" field.
|
||||
func GroupIDLTE(v int64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldGroupID, v))
|
||||
}
|
||||
|
||||
// NameEQ applies the EQ predicate on the "name" field.
|
||||
func NameEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldName, v))
|
||||
}
|
||||
|
||||
// NameNEQ applies the NEQ predicate on the "name" field.
|
||||
func NameNEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldName, v))
|
||||
}
|
||||
|
||||
// NameIn applies the In predicate on the "name" field.
|
||||
func NameIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldName, vs...))
|
||||
}
|
||||
|
||||
// NameNotIn applies the NotIn predicate on the "name" field.
|
||||
func NameNotIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldName, vs...))
|
||||
}
|
||||
|
||||
// NameGT applies the GT predicate on the "name" field.
|
||||
func NameGT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldName, v))
|
||||
}
|
||||
|
||||
// NameGTE applies the GTE predicate on the "name" field.
|
||||
func NameGTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldName, v))
|
||||
}
|
||||
|
||||
// NameLT applies the LT predicate on the "name" field.
|
||||
func NameLT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldName, v))
|
||||
}
|
||||
|
||||
// NameLTE applies the LTE predicate on the "name" field.
|
||||
func NameLTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldName, v))
|
||||
}
|
||||
|
||||
// NameContains applies the Contains predicate on the "name" field.
|
||||
func NameContains(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContains(FieldName, v))
|
||||
}
|
||||
|
||||
// NameHasPrefix applies the HasPrefix predicate on the "name" field.
|
||||
func NameHasPrefix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasPrefix(FieldName, v))
|
||||
}
|
||||
|
||||
// NameHasSuffix applies the HasSuffix predicate on the "name" field.
|
||||
func NameHasSuffix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasSuffix(FieldName, v))
|
||||
}
|
||||
|
||||
// NameEqualFold applies the EqualFold predicate on the "name" field.
|
||||
func NameEqualFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEqualFold(FieldName, v))
|
||||
}
|
||||
|
||||
// NameContainsFold applies the ContainsFold predicate on the "name" field.
|
||||
func NameContainsFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContainsFold(FieldName, v))
|
||||
}
|
||||
|
||||
// DescriptionEQ applies the EQ predicate on the "description" field.
|
||||
func DescriptionEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionNEQ applies the NEQ predicate on the "description" field.
|
||||
func DescriptionNEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionIn applies the In predicate on the "description" field.
|
||||
func DescriptionIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldDescription, vs...))
|
||||
}
|
||||
|
||||
// DescriptionNotIn applies the NotIn predicate on the "description" field.
|
||||
func DescriptionNotIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldDescription, vs...))
|
||||
}
|
||||
|
||||
// DescriptionGT applies the GT predicate on the "description" field.
|
||||
func DescriptionGT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionGTE applies the GTE predicate on the "description" field.
|
||||
func DescriptionGTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionLT applies the LT predicate on the "description" field.
|
||||
func DescriptionLT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionLTE applies the LTE predicate on the "description" field.
|
||||
func DescriptionLTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionContains applies the Contains predicate on the "description" field.
|
||||
func DescriptionContains(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContains(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionHasPrefix applies the HasPrefix predicate on the "description" field.
|
||||
func DescriptionHasPrefix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasPrefix(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionHasSuffix applies the HasSuffix predicate on the "description" field.
|
||||
func DescriptionHasSuffix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasSuffix(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionEqualFold applies the EqualFold predicate on the "description" field.
|
||||
func DescriptionEqualFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEqualFold(FieldDescription, v))
|
||||
}
|
||||
|
||||
// DescriptionContainsFold applies the ContainsFold predicate on the "description" field.
|
||||
func DescriptionContainsFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContainsFold(FieldDescription, v))
|
||||
}
|
||||
|
||||
// PriceEQ applies the EQ predicate on the "price" field.
|
||||
func PriceEQ(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldPrice, v))
|
||||
}
|
||||
|
||||
// PriceNEQ applies the NEQ predicate on the "price" field.
|
||||
func PriceNEQ(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldPrice, v))
|
||||
}
|
||||
|
||||
// PriceIn applies the In predicate on the "price" field.
|
||||
func PriceIn(vs ...float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldPrice, vs...))
|
||||
}
|
||||
|
||||
// PriceNotIn applies the NotIn predicate on the "price" field.
|
||||
func PriceNotIn(vs ...float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldPrice, vs...))
|
||||
}
|
||||
|
||||
// PriceGT applies the GT predicate on the "price" field.
|
||||
func PriceGT(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldPrice, v))
|
||||
}
|
||||
|
||||
// PriceGTE applies the GTE predicate on the "price" field.
|
||||
func PriceGTE(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldPrice, v))
|
||||
}
|
||||
|
||||
// PriceLT applies the LT predicate on the "price" field.
|
||||
func PriceLT(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldPrice, v))
|
||||
}
|
||||
|
||||
// PriceLTE applies the LTE predicate on the "price" field.
|
||||
func PriceLTE(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldPrice, v))
|
||||
}
|
||||
|
||||
// OriginalPriceEQ applies the EQ predicate on the "original_price" field.
|
||||
func OriginalPriceEQ(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldOriginalPrice, v))
|
||||
}
|
||||
|
||||
// OriginalPriceNEQ applies the NEQ predicate on the "original_price" field.
|
||||
func OriginalPriceNEQ(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldOriginalPrice, v))
|
||||
}
|
||||
|
||||
// OriginalPriceIn applies the In predicate on the "original_price" field.
|
||||
func OriginalPriceIn(vs ...float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldOriginalPrice, vs...))
|
||||
}
|
||||
|
||||
// OriginalPriceNotIn applies the NotIn predicate on the "original_price" field.
|
||||
func OriginalPriceNotIn(vs ...float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldOriginalPrice, vs...))
|
||||
}
|
||||
|
||||
// OriginalPriceGT applies the GT predicate on the "original_price" field.
|
||||
func OriginalPriceGT(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldOriginalPrice, v))
|
||||
}
|
||||
|
||||
// OriginalPriceGTE applies the GTE predicate on the "original_price" field.
|
||||
func OriginalPriceGTE(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldOriginalPrice, v))
|
||||
}
|
||||
|
||||
// OriginalPriceLT applies the LT predicate on the "original_price" field.
|
||||
func OriginalPriceLT(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldOriginalPrice, v))
|
||||
}
|
||||
|
||||
// OriginalPriceLTE applies the LTE predicate on the "original_price" field.
|
||||
func OriginalPriceLTE(v float64) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldOriginalPrice, v))
|
||||
}
|
||||
|
||||
// OriginalPriceIsNil applies the IsNil predicate on the "original_price" field.
|
||||
func OriginalPriceIsNil() predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIsNull(FieldOriginalPrice))
|
||||
}
|
||||
|
||||
// OriginalPriceNotNil applies the NotNil predicate on the "original_price" field.
|
||||
func OriginalPriceNotNil() predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotNull(FieldOriginalPrice))
|
||||
}
|
||||
|
||||
// ValidityDaysEQ applies the EQ predicate on the "validity_days" field.
|
||||
func ValidityDaysEQ(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldValidityDays, v))
|
||||
}
|
||||
|
||||
// ValidityDaysNEQ applies the NEQ predicate on the "validity_days" field.
|
||||
func ValidityDaysNEQ(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldValidityDays, v))
|
||||
}
|
||||
|
||||
// ValidityDaysIn applies the In predicate on the "validity_days" field.
|
||||
func ValidityDaysIn(vs ...int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldValidityDays, vs...))
|
||||
}
|
||||
|
||||
// ValidityDaysNotIn applies the NotIn predicate on the "validity_days" field.
|
||||
func ValidityDaysNotIn(vs ...int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldValidityDays, vs...))
|
||||
}
|
||||
|
||||
// ValidityDaysGT applies the GT predicate on the "validity_days" field.
|
||||
func ValidityDaysGT(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldValidityDays, v))
|
||||
}
|
||||
|
||||
// ValidityDaysGTE applies the GTE predicate on the "validity_days" field.
|
||||
func ValidityDaysGTE(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldValidityDays, v))
|
||||
}
|
||||
|
||||
// ValidityDaysLT applies the LT predicate on the "validity_days" field.
|
||||
func ValidityDaysLT(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldValidityDays, v))
|
||||
}
|
||||
|
||||
// ValidityDaysLTE applies the LTE predicate on the "validity_days" field.
|
||||
func ValidityDaysLTE(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldValidityDays, v))
|
||||
}
|
||||
|
||||
// ValidityUnitEQ applies the EQ predicate on the "validity_unit" field.
|
||||
func ValidityUnitEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitNEQ applies the NEQ predicate on the "validity_unit" field.
|
||||
func ValidityUnitNEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitIn applies the In predicate on the "validity_unit" field.
|
||||
func ValidityUnitIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldValidityUnit, vs...))
|
||||
}
|
||||
|
||||
// ValidityUnitNotIn applies the NotIn predicate on the "validity_unit" field.
|
||||
func ValidityUnitNotIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldValidityUnit, vs...))
|
||||
}
|
||||
|
||||
// ValidityUnitGT applies the GT predicate on the "validity_unit" field.
|
||||
func ValidityUnitGT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitGTE applies the GTE predicate on the "validity_unit" field.
|
||||
func ValidityUnitGTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitLT applies the LT predicate on the "validity_unit" field.
|
||||
func ValidityUnitLT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitLTE applies the LTE predicate on the "validity_unit" field.
|
||||
func ValidityUnitLTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitContains applies the Contains predicate on the "validity_unit" field.
|
||||
func ValidityUnitContains(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContains(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitHasPrefix applies the HasPrefix predicate on the "validity_unit" field.
|
||||
func ValidityUnitHasPrefix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasPrefix(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitHasSuffix applies the HasSuffix predicate on the "validity_unit" field.
|
||||
func ValidityUnitHasSuffix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasSuffix(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitEqualFold applies the EqualFold predicate on the "validity_unit" field.
|
||||
func ValidityUnitEqualFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEqualFold(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// ValidityUnitContainsFold applies the ContainsFold predicate on the "validity_unit" field.
|
||||
func ValidityUnitContainsFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContainsFold(FieldValidityUnit, v))
|
||||
}
|
||||
|
||||
// FeaturesEQ applies the EQ predicate on the "features" field.
|
||||
func FeaturesEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesNEQ applies the NEQ predicate on the "features" field.
|
||||
func FeaturesNEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesIn applies the In predicate on the "features" field.
|
||||
func FeaturesIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldFeatures, vs...))
|
||||
}
|
||||
|
||||
// FeaturesNotIn applies the NotIn predicate on the "features" field.
|
||||
func FeaturesNotIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldFeatures, vs...))
|
||||
}
|
||||
|
||||
// FeaturesGT applies the GT predicate on the "features" field.
|
||||
func FeaturesGT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesGTE applies the GTE predicate on the "features" field.
|
||||
func FeaturesGTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesLT applies the LT predicate on the "features" field.
|
||||
func FeaturesLT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesLTE applies the LTE predicate on the "features" field.
|
||||
func FeaturesLTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesContains applies the Contains predicate on the "features" field.
|
||||
func FeaturesContains(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContains(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesHasPrefix applies the HasPrefix predicate on the "features" field.
|
||||
func FeaturesHasPrefix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasPrefix(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesHasSuffix applies the HasSuffix predicate on the "features" field.
|
||||
func FeaturesHasSuffix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasSuffix(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesEqualFold applies the EqualFold predicate on the "features" field.
|
||||
func FeaturesEqualFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEqualFold(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// FeaturesContainsFold applies the ContainsFold predicate on the "features" field.
|
||||
func FeaturesContainsFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContainsFold(FieldFeatures, v))
|
||||
}
|
||||
|
||||
// ProductNameEQ applies the EQ predicate on the "product_name" field.
|
||||
func ProductNameEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameNEQ applies the NEQ predicate on the "product_name" field.
|
||||
func ProductNameNEQ(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameIn applies the In predicate on the "product_name" field.
|
||||
func ProductNameIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldProductName, vs...))
|
||||
}
|
||||
|
||||
// ProductNameNotIn applies the NotIn predicate on the "product_name" field.
|
||||
func ProductNameNotIn(vs ...string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldProductName, vs...))
|
||||
}
|
||||
|
||||
// ProductNameGT applies the GT predicate on the "product_name" field.
|
||||
func ProductNameGT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameGTE applies the GTE predicate on the "product_name" field.
|
||||
func ProductNameGTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameLT applies the LT predicate on the "product_name" field.
|
||||
func ProductNameLT(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameLTE applies the LTE predicate on the "product_name" field.
|
||||
func ProductNameLTE(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameContains applies the Contains predicate on the "product_name" field.
|
||||
func ProductNameContains(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContains(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameHasPrefix applies the HasPrefix predicate on the "product_name" field.
|
||||
func ProductNameHasPrefix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasPrefix(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameHasSuffix applies the HasSuffix predicate on the "product_name" field.
|
||||
func ProductNameHasSuffix(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldHasSuffix(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameEqualFold applies the EqualFold predicate on the "product_name" field.
|
||||
func ProductNameEqualFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEqualFold(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ProductNameContainsFold applies the ContainsFold predicate on the "product_name" field.
|
||||
func ProductNameContainsFold(v string) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldContainsFold(FieldProductName, v))
|
||||
}
|
||||
|
||||
// ForSaleEQ applies the EQ predicate on the "for_sale" field.
|
||||
func ForSaleEQ(v bool) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldForSale, v))
|
||||
}
|
||||
|
||||
// ForSaleNEQ applies the NEQ predicate on the "for_sale" field.
|
||||
func ForSaleNEQ(v bool) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldForSale, v))
|
||||
}
|
||||
|
||||
// SortOrderEQ applies the EQ predicate on the "sort_order" field.
|
||||
func SortOrderEQ(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderNEQ applies the NEQ predicate on the "sort_order" field.
|
||||
func SortOrderNEQ(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderIn applies the In predicate on the "sort_order" field.
|
||||
func SortOrderIn(vs ...int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldSortOrder, vs...))
|
||||
}
|
||||
|
||||
// SortOrderNotIn applies the NotIn predicate on the "sort_order" field.
|
||||
func SortOrderNotIn(vs ...int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldSortOrder, vs...))
|
||||
}
|
||||
|
||||
// SortOrderGT applies the GT predicate on the "sort_order" field.
|
||||
func SortOrderGT(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderGTE applies the GTE predicate on the "sort_order" field.
|
||||
func SortOrderGTE(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderLT applies the LT predicate on the "sort_order" field.
|
||||
func SortOrderLT(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// SortOrderLTE applies the LTE predicate on the "sort_order" field.
|
||||
func SortOrderLTE(v int) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldSortOrder, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||
func CreatedAtNEQ(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||
func CreatedAtIn(vs ...time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||
func CreatedAtNotIn(vs ...time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||
}
|
||||
|
||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||
func CreatedAtGT(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||
func CreatedAtGTE(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||
func CreatedAtLT(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||
func CreatedAtLTE(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldCreatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
||||
func UpdatedAtEQ(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
||||
func UpdatedAtNEQ(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNEQ(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
||||
func UpdatedAtIn(vs ...time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
||||
func UpdatedAtNotIn(vs ...time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldNotIn(FieldUpdatedAt, vs...))
|
||||
}
|
||||
|
||||
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
||||
func UpdatedAtGT(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
||||
func UpdatedAtGTE(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldGTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
||||
func UpdatedAtLT(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLT(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
||||
func UpdatedAtLTE(v time.Time) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.FieldLTE(FieldUpdatedAt, v))
|
||||
}
|
||||
|
||||
// And groups predicates with the AND operator between them.
|
||||
func And(predicates ...predicate.SubscriptionPlan) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.AndPredicates(predicates...))
|
||||
}
|
||||
|
||||
// Or groups predicates with the OR operator between them.
|
||||
func Or(predicates ...predicate.SubscriptionPlan) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.OrPredicates(predicates...))
|
||||
}
|
||||
|
||||
// Not applies the not operator on the given predicate.
|
||||
func Not(p predicate.SubscriptionPlan) predicate.SubscriptionPlan {
|
||||
return predicate.SubscriptionPlan(sql.NotPredicates(p))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
)
|
||||
|
||||
// SubscriptionPlanDelete is the builder for deleting a SubscriptionPlan entity.
|
||||
type SubscriptionPlanDelete struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *SubscriptionPlanMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the SubscriptionPlanDelete builder.
|
||||
func (_d *SubscriptionPlanDelete) Where(ps ...predicate.SubscriptionPlan) *SubscriptionPlanDelete {
|
||||
_d.mutation.Where(ps...)
|
||||
return _d
|
||||
}
|
||||
|
||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||
func (_d *SubscriptionPlanDelete) Exec(ctx context.Context) (int, error) {
|
||||
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_d *SubscriptionPlanDelete) ExecX(ctx context.Context) int {
|
||||
n, err := _d.Exec(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (_d *SubscriptionPlanDelete) sqlExec(ctx context.Context) (int, error) {
|
||||
_spec := sqlgraph.NewDeleteSpec(subscriptionplan.Table, sqlgraph.NewFieldSpec(subscriptionplan.FieldID, field.TypeInt64))
|
||||
if ps := _d.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
|
||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
_d.mutation.done = true
|
||||
return affected, err
|
||||
}
|
||||
|
||||
// SubscriptionPlanDeleteOne is the builder for deleting a single SubscriptionPlan entity.
|
||||
type SubscriptionPlanDeleteOne struct {
|
||||
_d *SubscriptionPlanDelete
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the SubscriptionPlanDelete builder.
|
||||
func (_d *SubscriptionPlanDeleteOne) Where(ps ...predicate.SubscriptionPlan) *SubscriptionPlanDeleteOne {
|
||||
_d._d.mutation.Where(ps...)
|
||||
return _d
|
||||
}
|
||||
|
||||
// Exec executes the deletion query.
|
||||
func (_d *SubscriptionPlanDeleteOne) Exec(ctx context.Context) error {
|
||||
n, err := _d._d.Exec(ctx)
|
||||
switch {
|
||||
case err != nil:
|
||||
return err
|
||||
case n == 0:
|
||||
return &NotFoundError{subscriptionplan.Label}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_d *SubscriptionPlanDeleteOne) ExecX(ctx context.Context) {
|
||||
if err := _d.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
)
|
||||
|
||||
// SubscriptionPlanQuery is the builder for querying SubscriptionPlan entities.
|
||||
type SubscriptionPlanQuery struct {
|
||||
config
|
||||
ctx *QueryContext
|
||||
order []subscriptionplan.OrderOption
|
||||
inters []Interceptor
|
||||
predicates []predicate.SubscriptionPlan
|
||||
modifiers []func(*sql.Selector)
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
}
|
||||
|
||||
// Where adds a new predicate for the SubscriptionPlanQuery builder.
|
||||
func (_q *SubscriptionPlanQuery) Where(ps ...predicate.SubscriptionPlan) *SubscriptionPlanQuery {
|
||||
_q.predicates = append(_q.predicates, ps...)
|
||||
return _q
|
||||
}
|
||||
|
||||
// Limit the number of records to be returned by this query.
|
||||
func (_q *SubscriptionPlanQuery) Limit(limit int) *SubscriptionPlanQuery {
|
||||
_q.ctx.Limit = &limit
|
||||
return _q
|
||||
}
|
||||
|
||||
// Offset to start from.
|
||||
func (_q *SubscriptionPlanQuery) Offset(offset int) *SubscriptionPlanQuery {
|
||||
_q.ctx.Offset = &offset
|
||||
return _q
|
||||
}
|
||||
|
||||
// Unique configures the query builder to filter duplicate records on query.
|
||||
// By default, unique is set to true, and can be disabled using this method.
|
||||
func (_q *SubscriptionPlanQuery) Unique(unique bool) *SubscriptionPlanQuery {
|
||||
_q.ctx.Unique = &unique
|
||||
return _q
|
||||
}
|
||||
|
||||
// Order specifies how the records should be ordered.
|
||||
func (_q *SubscriptionPlanQuery) Order(o ...subscriptionplan.OrderOption) *SubscriptionPlanQuery {
|
||||
_q.order = append(_q.order, o...)
|
||||
return _q
|
||||
}
|
||||
|
||||
// First returns the first SubscriptionPlan entity from the query.
|
||||
// Returns a *NotFoundError when no SubscriptionPlan was found.
|
||||
func (_q *SubscriptionPlanQuery) First(ctx context.Context) (*SubscriptionPlan, error) {
|
||||
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nil, &NotFoundError{subscriptionplan.Label}
|
||||
}
|
||||
return nodes[0], nil
|
||||
}
|
||||
|
||||
// FirstX is like First, but panics if an error occurs.
|
||||
func (_q *SubscriptionPlanQuery) FirstX(ctx context.Context) *SubscriptionPlan {
|
||||
node, err := _q.First(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// FirstID returns the first SubscriptionPlan ID from the query.
|
||||
// Returns a *NotFoundError when no SubscriptionPlan ID was found.
|
||||
func (_q *SubscriptionPlanQuery) FirstID(ctx context.Context) (id int64, err error) {
|
||||
var ids []int64
|
||||
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
err = &NotFoundError{subscriptionplan.Label}
|
||||
return
|
||||
}
|
||||
return ids[0], nil
|
||||
}
|
||||
|
||||
// FirstIDX is like FirstID, but panics if an error occurs.
|
||||
func (_q *SubscriptionPlanQuery) FirstIDX(ctx context.Context) int64 {
|
||||
id, err := _q.FirstID(ctx)
|
||||
if err != nil && !IsNotFound(err) {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// Only returns a single SubscriptionPlan entity found by the query, ensuring it only returns one.
|
||||
// Returns a *NotSingularError when more than one SubscriptionPlan entity is found.
|
||||
// Returns a *NotFoundError when no SubscriptionPlan entities are found.
|
||||
func (_q *SubscriptionPlanQuery) Only(ctx context.Context) (*SubscriptionPlan, error) {
|
||||
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch len(nodes) {
|
||||
case 1:
|
||||
return nodes[0], nil
|
||||
case 0:
|
||||
return nil, &NotFoundError{subscriptionplan.Label}
|
||||
default:
|
||||
return nil, &NotSingularError{subscriptionplan.Label}
|
||||
}
|
||||
}
|
||||
|
||||
// OnlyX is like Only, but panics if an error occurs.
|
||||
func (_q *SubscriptionPlanQuery) OnlyX(ctx context.Context) *SubscriptionPlan {
|
||||
node, err := _q.Only(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// OnlyID is like Only, but returns the only SubscriptionPlan ID in the query.
|
||||
// Returns a *NotSingularError when more than one SubscriptionPlan ID is found.
|
||||
// Returns a *NotFoundError when no entities are found.
|
||||
func (_q *SubscriptionPlanQuery) OnlyID(ctx context.Context) (id int64, err error) {
|
||||
var ids []int64
|
||||
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
|
||||
return
|
||||
}
|
||||
switch len(ids) {
|
||||
case 1:
|
||||
id = ids[0]
|
||||
case 0:
|
||||
err = &NotFoundError{subscriptionplan.Label}
|
||||
default:
|
||||
err = &NotSingularError{subscriptionplan.Label}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OnlyIDX is like OnlyID, but panics if an error occurs.
|
||||
func (_q *SubscriptionPlanQuery) OnlyIDX(ctx context.Context) int64 {
|
||||
id, err := _q.OnlyID(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// All executes the query and returns a list of SubscriptionPlans.
|
||||
func (_q *SubscriptionPlanQuery) All(ctx context.Context) ([]*SubscriptionPlan, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
qr := querierAll[[]*SubscriptionPlan, *SubscriptionPlanQuery]()
|
||||
return withInterceptors[[]*SubscriptionPlan](ctx, _q, qr, _q.inters)
|
||||
}
|
||||
|
||||
// AllX is like All, but panics if an error occurs.
|
||||
func (_q *SubscriptionPlanQuery) AllX(ctx context.Context) []*SubscriptionPlan {
|
||||
nodes, err := _q.All(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
// IDs executes the query and returns a list of SubscriptionPlan IDs.
|
||||
func (_q *SubscriptionPlanQuery) IDs(ctx context.Context) (ids []int64, err error) {
|
||||
if _q.ctx.Unique == nil && _q.path != nil {
|
||||
_q.Unique(true)
|
||||
}
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
|
||||
if err = _q.Select(subscriptionplan.FieldID).Scan(ctx, &ids); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// IDsX is like IDs, but panics if an error occurs.
|
||||
func (_q *SubscriptionPlanQuery) IDsX(ctx context.Context) []int64 {
|
||||
ids, err := _q.IDs(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
// Count returns the count of the given query.
|
||||
func (_q *SubscriptionPlanQuery) Count(ctx context.Context) (int, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return withInterceptors[int](ctx, _q, querierCount[*SubscriptionPlanQuery](), _q.inters)
|
||||
}
|
||||
|
||||
// CountX is like Count, but panics if an error occurs.
|
||||
func (_q *SubscriptionPlanQuery) CountX(ctx context.Context) int {
|
||||
count, err := _q.Count(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Exist returns true if the query has elements in the graph.
|
||||
func (_q *SubscriptionPlanQuery) Exist(ctx context.Context) (bool, error) {
|
||||
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
|
||||
switch _, err := _q.FirstID(ctx); {
|
||||
case IsNotFound(err):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ExistX is like Exist, but panics if an error occurs.
|
||||
func (_q *SubscriptionPlanQuery) ExistX(ctx context.Context) bool {
|
||||
exist, err := _q.Exist(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return exist
|
||||
}
|
||||
|
||||
// Clone returns a duplicate of the SubscriptionPlanQuery builder, including all associated steps. It can be
|
||||
// used to prepare common query builders and use them differently after the clone is made.
|
||||
func (_q *SubscriptionPlanQuery) Clone() *SubscriptionPlanQuery {
|
||||
if _q == nil {
|
||||
return nil
|
||||
}
|
||||
return &SubscriptionPlanQuery{
|
||||
config: _q.config,
|
||||
ctx: _q.ctx.Clone(),
|
||||
order: append([]subscriptionplan.OrderOption{}, _q.order...),
|
||||
inters: append([]Interceptor{}, _q.inters...),
|
||||
predicates: append([]predicate.SubscriptionPlan{}, _q.predicates...),
|
||||
// clone intermediate query.
|
||||
sql: _q.sql.Clone(),
|
||||
path: _q.path,
|
||||
}
|
||||
}
|
||||
|
||||
// GroupBy is used to group vertices by one or more fields/columns.
|
||||
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// GroupID int64 `json:"group_id,omitempty"`
|
||||
// Count int `json:"count,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.SubscriptionPlan.Query().
|
||||
// GroupBy(subscriptionplan.FieldGroupID).
|
||||
// Aggregate(ent.Count()).
|
||||
// Scan(ctx, &v)
|
||||
func (_q *SubscriptionPlanQuery) GroupBy(field string, fields ...string) *SubscriptionPlanGroupBy {
|
||||
_q.ctx.Fields = append([]string{field}, fields...)
|
||||
grbuild := &SubscriptionPlanGroupBy{build: _q}
|
||||
grbuild.flds = &_q.ctx.Fields
|
||||
grbuild.label = subscriptionplan.Label
|
||||
grbuild.scan = grbuild.Scan
|
||||
return grbuild
|
||||
}
|
||||
|
||||
// Select allows the selection one or more fields/columns for the given query,
|
||||
// instead of selecting all fields in the entity.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var v []struct {
|
||||
// GroupID int64 `json:"group_id,omitempty"`
|
||||
// }
|
||||
//
|
||||
// client.SubscriptionPlan.Query().
|
||||
// Select(subscriptionplan.FieldGroupID).
|
||||
// Scan(ctx, &v)
|
||||
func (_q *SubscriptionPlanQuery) Select(fields ...string) *SubscriptionPlanSelect {
|
||||
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
|
||||
sbuild := &SubscriptionPlanSelect{SubscriptionPlanQuery: _q}
|
||||
sbuild.label = subscriptionplan.Label
|
||||
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
|
||||
return sbuild
|
||||
}
|
||||
|
||||
// Aggregate returns a SubscriptionPlanSelect configured with the given aggregations.
|
||||
func (_q *SubscriptionPlanQuery) Aggregate(fns ...AggregateFunc) *SubscriptionPlanSelect {
|
||||
return _q.Select().Aggregate(fns...)
|
||||
}
|
||||
|
||||
func (_q *SubscriptionPlanQuery) prepareQuery(ctx context.Context) error {
|
||||
for _, inter := range _q.inters {
|
||||
if inter == nil {
|
||||
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
|
||||
}
|
||||
if trv, ok := inter.(Traverser); ok {
|
||||
if err := trv.Traverse(ctx, _q); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, f := range _q.ctx.Fields {
|
||||
if !subscriptionplan.ValidColumn(f) {
|
||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
}
|
||||
if _q.path != nil {
|
||||
prev, err := _q.path(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_q.sql = prev
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_q *SubscriptionPlanQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*SubscriptionPlan, error) {
|
||||
var (
|
||||
nodes = []*SubscriptionPlan{}
|
||||
_spec = _q.querySpec()
|
||||
)
|
||||
_spec.ScanValues = func(columns []string) ([]any, error) {
|
||||
return (*SubscriptionPlan).scanValues(nil, columns)
|
||||
}
|
||||
_spec.Assign = func(columns []string, values []any) error {
|
||||
node := &SubscriptionPlan{config: _q.config}
|
||||
nodes = append(nodes, node)
|
||||
return node.assignValues(columns, values)
|
||||
}
|
||||
if len(_q.modifiers) > 0 {
|
||||
_spec.Modifiers = _q.modifiers
|
||||
}
|
||||
for i := range hooks {
|
||||
hooks[i](ctx, _spec)
|
||||
}
|
||||
if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(nodes) == 0 {
|
||||
return nodes, nil
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (_q *SubscriptionPlanQuery) sqlCount(ctx context.Context) (int, error) {
|
||||
_spec := _q.querySpec()
|
||||
if len(_q.modifiers) > 0 {
|
||||
_spec.Modifiers = _q.modifiers
|
||||
}
|
||||
_spec.Node.Columns = _q.ctx.Fields
|
||||
if len(_q.ctx.Fields) > 0 {
|
||||
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
|
||||
}
|
||||
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
|
||||
}
|
||||
|
||||
func (_q *SubscriptionPlanQuery) querySpec() *sqlgraph.QuerySpec {
|
||||
_spec := sqlgraph.NewQuerySpec(subscriptionplan.Table, subscriptionplan.Columns, sqlgraph.NewFieldSpec(subscriptionplan.FieldID, field.TypeInt64))
|
||||
_spec.From = _q.sql
|
||||
if unique := _q.ctx.Unique; unique != nil {
|
||||
_spec.Unique = *unique
|
||||
} else if _q.path != nil {
|
||||
_spec.Unique = true
|
||||
}
|
||||
if fields := _q.ctx.Fields; len(fields) > 0 {
|
||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, subscriptionplan.FieldID)
|
||||
for i := range fields {
|
||||
if fields[i] != subscriptionplan.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
if ps := _q.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if limit := _q.ctx.Limit; limit != nil {
|
||||
_spec.Limit = *limit
|
||||
}
|
||||
if offset := _q.ctx.Offset; offset != nil {
|
||||
_spec.Offset = *offset
|
||||
}
|
||||
if ps := _q.order; len(ps) > 0 {
|
||||
_spec.Order = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
return _spec
|
||||
}
|
||||
|
||||
func (_q *SubscriptionPlanQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||
builder := sql.Dialect(_q.driver.Dialect())
|
||||
t1 := builder.Table(subscriptionplan.Table)
|
||||
columns := _q.ctx.Fields
|
||||
if len(columns) == 0 {
|
||||
columns = subscriptionplan.Columns
|
||||
}
|
||||
selector := builder.Select(t1.Columns(columns...)...).From(t1)
|
||||
if _q.sql != nil {
|
||||
selector = _q.sql
|
||||
selector.Select(selector.Columns(columns...)...)
|
||||
}
|
||||
if _q.ctx.Unique != nil && *_q.ctx.Unique {
|
||||
selector.Distinct()
|
||||
}
|
||||
for _, m := range _q.modifiers {
|
||||
m(selector)
|
||||
}
|
||||
for _, p := range _q.predicates {
|
||||
p(selector)
|
||||
}
|
||||
for _, p := range _q.order {
|
||||
p(selector)
|
||||
}
|
||||
if offset := _q.ctx.Offset; offset != nil {
|
||||
// limit is mandatory for offset clause. We start
|
||||
// with default value, and override it below if needed.
|
||||
selector.Offset(*offset).Limit(math.MaxInt32)
|
||||
}
|
||||
if limit := _q.ctx.Limit; limit != nil {
|
||||
selector.Limit(*limit)
|
||||
}
|
||||
return selector
|
||||
}
|
||||
|
||||
// ForUpdate locks the selected rows against concurrent updates, and prevent them from being
|
||||
// updated, deleted or "selected ... for update" by other sessions, until the transaction is
|
||||
// either committed or rolled-back.
|
||||
func (_q *SubscriptionPlanQuery) ForUpdate(opts ...sql.LockOption) *SubscriptionPlanQuery {
|
||||
if _q.driver.Dialect() == dialect.Postgres {
|
||||
_q.Unique(false)
|
||||
}
|
||||
_q.modifiers = append(_q.modifiers, func(s *sql.Selector) {
|
||||
s.ForUpdate(opts...)
|
||||
})
|
||||
return _q
|
||||
}
|
||||
|
||||
// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock
|
||||
// on any rows that are read. Other sessions can read the rows, but cannot modify them
|
||||
// until your transaction commits.
|
||||
func (_q *SubscriptionPlanQuery) ForShare(opts ...sql.LockOption) *SubscriptionPlanQuery {
|
||||
if _q.driver.Dialect() == dialect.Postgres {
|
||||
_q.Unique(false)
|
||||
}
|
||||
_q.modifiers = append(_q.modifiers, func(s *sql.Selector) {
|
||||
s.ForShare(opts...)
|
||||
})
|
||||
return _q
|
||||
}
|
||||
|
||||
// SubscriptionPlanGroupBy is the group-by builder for SubscriptionPlan entities.
|
||||
type SubscriptionPlanGroupBy struct {
|
||||
selector
|
||||
build *SubscriptionPlanQuery
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the group-by query.
|
||||
func (_g *SubscriptionPlanGroupBy) Aggregate(fns ...AggregateFunc) *SubscriptionPlanGroupBy {
|
||||
_g.fns = append(_g.fns, fns...)
|
||||
return _g
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (_g *SubscriptionPlanGroupBy) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
|
||||
if err := _g.build.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*SubscriptionPlanQuery, *SubscriptionPlanGroupBy](ctx, _g.build, _g, _g.build.inters, v)
|
||||
}
|
||||
|
||||
func (_g *SubscriptionPlanGroupBy) sqlScan(ctx context.Context, root *SubscriptionPlanQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx).Select()
|
||||
aggregation := make([]string, 0, len(_g.fns))
|
||||
for _, fn := range _g.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
if len(selector.SelectedColumns()) == 0 {
|
||||
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
|
||||
for _, f := range *_g.flds {
|
||||
columns = append(columns, selector.C(f))
|
||||
}
|
||||
columns = append(columns, aggregation...)
|
||||
selector.Select(columns...)
|
||||
}
|
||||
selector.GroupBy(selector.Columns(*_g.flds...)...)
|
||||
if err := selector.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
|
||||
// SubscriptionPlanSelect is the builder for selecting fields of SubscriptionPlan entities.
|
||||
type SubscriptionPlanSelect struct {
|
||||
*SubscriptionPlanQuery
|
||||
selector
|
||||
}
|
||||
|
||||
// Aggregate adds the given aggregation functions to the selector query.
|
||||
func (_s *SubscriptionPlanSelect) Aggregate(fns ...AggregateFunc) *SubscriptionPlanSelect {
|
||||
_s.fns = append(_s.fns, fns...)
|
||||
return _s
|
||||
}
|
||||
|
||||
// Scan applies the selector query and scans the result into the given value.
|
||||
func (_s *SubscriptionPlanSelect) Scan(ctx context.Context, v any) error {
|
||||
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
|
||||
if err := _s.prepareQuery(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanWithInterceptors[*SubscriptionPlanQuery, *SubscriptionPlanSelect](ctx, _s.SubscriptionPlanQuery, _s, _s.inters, v)
|
||||
}
|
||||
|
||||
func (_s *SubscriptionPlanSelect) sqlScan(ctx context.Context, root *SubscriptionPlanQuery, v any) error {
|
||||
selector := root.sqlQuery(ctx)
|
||||
aggregation := make([]string, 0, len(_s.fns))
|
||||
for _, fn := range _s.fns {
|
||||
aggregation = append(aggregation, fn(selector))
|
||||
}
|
||||
switch n := len(*_s.selector.flds); {
|
||||
case n == 0 && len(aggregation) > 0:
|
||||
selector.Select(aggregation...)
|
||||
case n != 0 && len(aggregation) > 0:
|
||||
selector.AppendSelect(aggregation...)
|
||||
}
|
||||
rows := &sql.Rows{}
|
||||
query, args := selector.Query()
|
||||
if err := _s.driver.Query(ctx, query, args, rows); err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
return sql.ScanSlice(rows, v)
|
||||
}
|
||||
@@ -0,0 +1,750 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
"entgo.io/ent/schema/field"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
)
|
||||
|
||||
// SubscriptionPlanUpdate is the builder for updating SubscriptionPlan entities.
|
||||
type SubscriptionPlanUpdate struct {
|
||||
config
|
||||
hooks []Hook
|
||||
mutation *SubscriptionPlanMutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the SubscriptionPlanUpdate builder.
|
||||
func (_u *SubscriptionPlanUpdate) Where(ps ...predicate.SubscriptionPlan) *SubscriptionPlanUpdate {
|
||||
_u.mutation.Where(ps...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetGroupID sets the "group_id" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetGroupID(v int64) *SubscriptionPlanUpdate {
|
||||
_u.mutation.ResetGroupID()
|
||||
_u.mutation.SetGroupID(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableGroupID sets the "group_id" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableGroupID(v *int64) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetGroupID(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddGroupID adds value to the "group_id" field.
|
||||
func (_u *SubscriptionPlanUpdate) AddGroupID(v int64) *SubscriptionPlanUpdate {
|
||||
_u.mutation.AddGroupID(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetName sets the "name" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetName(v string) *SubscriptionPlanUpdate {
|
||||
_u.mutation.SetName(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableName sets the "name" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableName(v *string) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetName(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetDescription sets the "description" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetDescription(v string) *SubscriptionPlanUpdate {
|
||||
_u.mutation.SetDescription(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableDescription sets the "description" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableDescription(v *string) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetDescription(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetPrice sets the "price" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetPrice(v float64) *SubscriptionPlanUpdate {
|
||||
_u.mutation.ResetPrice()
|
||||
_u.mutation.SetPrice(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillablePrice sets the "price" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillablePrice(v *float64) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetPrice(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddPrice adds value to the "price" field.
|
||||
func (_u *SubscriptionPlanUpdate) AddPrice(v float64) *SubscriptionPlanUpdate {
|
||||
_u.mutation.AddPrice(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetOriginalPrice sets the "original_price" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetOriginalPrice(v float64) *SubscriptionPlanUpdate {
|
||||
_u.mutation.ResetOriginalPrice()
|
||||
_u.mutation.SetOriginalPrice(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableOriginalPrice sets the "original_price" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableOriginalPrice(v *float64) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetOriginalPrice(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddOriginalPrice adds value to the "original_price" field.
|
||||
func (_u *SubscriptionPlanUpdate) AddOriginalPrice(v float64) *SubscriptionPlanUpdate {
|
||||
_u.mutation.AddOriginalPrice(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearOriginalPrice clears the value of the "original_price" field.
|
||||
func (_u *SubscriptionPlanUpdate) ClearOriginalPrice() *SubscriptionPlanUpdate {
|
||||
_u.mutation.ClearOriginalPrice()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetValidityDays sets the "validity_days" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetValidityDays(v int) *SubscriptionPlanUpdate {
|
||||
_u.mutation.ResetValidityDays()
|
||||
_u.mutation.SetValidityDays(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableValidityDays sets the "validity_days" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableValidityDays(v *int) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetValidityDays(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddValidityDays adds value to the "validity_days" field.
|
||||
func (_u *SubscriptionPlanUpdate) AddValidityDays(v int) *SubscriptionPlanUpdate {
|
||||
_u.mutation.AddValidityDays(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetValidityUnit sets the "validity_unit" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetValidityUnit(v string) *SubscriptionPlanUpdate {
|
||||
_u.mutation.SetValidityUnit(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableValidityUnit sets the "validity_unit" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableValidityUnit(v *string) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetValidityUnit(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetFeatures sets the "features" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetFeatures(v string) *SubscriptionPlanUpdate {
|
||||
_u.mutation.SetFeatures(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableFeatures sets the "features" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableFeatures(v *string) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetFeatures(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetProductName sets the "product_name" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetProductName(v string) *SubscriptionPlanUpdate {
|
||||
_u.mutation.SetProductName(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableProductName sets the "product_name" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableProductName(v *string) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetProductName(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetForSale sets the "for_sale" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetForSale(v bool) *SubscriptionPlanUpdate {
|
||||
_u.mutation.SetForSale(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableForSale sets the "for_sale" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableForSale(v *bool) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetForSale(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetSortOrder sets the "sort_order" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetSortOrder(v int) *SubscriptionPlanUpdate {
|
||||
_u.mutation.ResetSortOrder()
|
||||
_u.mutation.SetSortOrder(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableSortOrder sets the "sort_order" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdate) SetNillableSortOrder(v *int) *SubscriptionPlanUpdate {
|
||||
if v != nil {
|
||||
_u.SetSortOrder(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddSortOrder adds value to the "sort_order" field.
|
||||
func (_u *SubscriptionPlanUpdate) AddSortOrder(v int) *SubscriptionPlanUpdate {
|
||||
_u.mutation.AddSortOrder(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetUpdatedAt sets the "updated_at" field.
|
||||
func (_u *SubscriptionPlanUpdate) SetUpdatedAt(v time.Time) *SubscriptionPlanUpdate {
|
||||
_u.mutation.SetUpdatedAt(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Mutation returns the SubscriptionPlanMutation object of the builder.
|
||||
func (_u *SubscriptionPlanUpdate) Mutation() *SubscriptionPlanMutation {
|
||||
return _u.mutation
|
||||
}
|
||||
|
||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||
func (_u *SubscriptionPlanUpdate) Save(ctx context.Context) (int, error) {
|
||||
_u.defaults()
|
||||
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (_u *SubscriptionPlanUpdate) SaveX(ctx context.Context) int {
|
||||
affected, err := _u.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return affected
|
||||
}
|
||||
|
||||
// Exec executes the query.
|
||||
func (_u *SubscriptionPlanUpdate) Exec(ctx context.Context) error {
|
||||
_, err := _u.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_u *SubscriptionPlanUpdate) ExecX(ctx context.Context) {
|
||||
if err := _u.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// defaults sets the default values of the builder before save.
|
||||
func (_u *SubscriptionPlanUpdate) defaults() {
|
||||
if _, ok := _u.mutation.UpdatedAt(); !ok {
|
||||
v := subscriptionplan.UpdateDefaultUpdatedAt()
|
||||
_u.mutation.SetUpdatedAt(v)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (_u *SubscriptionPlanUpdate) check() error {
|
||||
if v, ok := _u.mutation.Name(); ok {
|
||||
if err := subscriptionplan.NameValidator(v); err != nil {
|
||||
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "SubscriptionPlan.name": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.ValidityUnit(); ok {
|
||||
if err := subscriptionplan.ValidityUnitValidator(v); err != nil {
|
||||
return &ValidationError{Name: "validity_unit", err: fmt.Errorf(`ent: validator failed for field "SubscriptionPlan.validity_unit": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.ProductName(); ok {
|
||||
if err := subscriptionplan.ProductNameValidator(v); err != nil {
|
||||
return &ValidationError{Name: "product_name", err: fmt.Errorf(`ent: validator failed for field "SubscriptionPlan.product_name": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_u *SubscriptionPlanUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
if err := _u.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(subscriptionplan.Table, subscriptionplan.Columns, sqlgraph.NewFieldSpec(subscriptionplan.FieldID, field.TypeInt64))
|
||||
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, ok := _u.mutation.GroupID(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldGroupID, field.TypeInt64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedGroupID(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldGroupID, field.TypeInt64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Name(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldName, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Description(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldDescription, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Price(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldPrice, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedPrice(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldPrice, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.OriginalPrice(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldOriginalPrice, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedOriginalPrice(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldOriginalPrice, field.TypeFloat64, value)
|
||||
}
|
||||
if _u.mutation.OriginalPriceCleared() {
|
||||
_spec.ClearField(subscriptionplan.FieldOriginalPrice, field.TypeFloat64)
|
||||
}
|
||||
if value, ok := _u.mutation.ValidityDays(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldValidityDays, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedValidityDays(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldValidityDays, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ValidityUnit(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldValidityUnit, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Features(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldFeatures, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ProductName(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldProductName, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ForSale(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldForSale, field.TypeBool, value)
|
||||
}
|
||||
if value, ok := _u.mutation.SortOrder(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldSortOrder, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedSortOrder(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldSortOrder, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.UpdatedAt(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{subscriptionplan.Label}
|
||||
} else if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
_u.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
|
||||
// SubscriptionPlanUpdateOne is the builder for updating a single SubscriptionPlan entity.
|
||||
type SubscriptionPlanUpdateOne struct {
|
||||
config
|
||||
fields []string
|
||||
hooks []Hook
|
||||
mutation *SubscriptionPlanMutation
|
||||
}
|
||||
|
||||
// SetGroupID sets the "group_id" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetGroupID(v int64) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.ResetGroupID()
|
||||
_u.mutation.SetGroupID(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableGroupID sets the "group_id" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableGroupID(v *int64) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetGroupID(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddGroupID adds value to the "group_id" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) AddGroupID(v int64) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.AddGroupID(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetName sets the "name" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetName(v string) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.SetName(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableName sets the "name" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableName(v *string) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetName(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetDescription sets the "description" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetDescription(v string) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.SetDescription(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableDescription sets the "description" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableDescription(v *string) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetDescription(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetPrice sets the "price" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetPrice(v float64) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.ResetPrice()
|
||||
_u.mutation.SetPrice(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillablePrice sets the "price" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillablePrice(v *float64) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetPrice(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddPrice adds value to the "price" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) AddPrice(v float64) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.AddPrice(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetOriginalPrice sets the "original_price" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetOriginalPrice(v float64) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.ResetOriginalPrice()
|
||||
_u.mutation.SetOriginalPrice(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableOriginalPrice sets the "original_price" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableOriginalPrice(v *float64) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetOriginalPrice(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddOriginalPrice adds value to the "original_price" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) AddOriginalPrice(v float64) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.AddOriginalPrice(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearOriginalPrice clears the value of the "original_price" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) ClearOriginalPrice() *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.ClearOriginalPrice()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetValidityDays sets the "validity_days" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetValidityDays(v int) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.ResetValidityDays()
|
||||
_u.mutation.SetValidityDays(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableValidityDays sets the "validity_days" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableValidityDays(v *int) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetValidityDays(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddValidityDays adds value to the "validity_days" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) AddValidityDays(v int) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.AddValidityDays(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetValidityUnit sets the "validity_unit" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetValidityUnit(v string) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.SetValidityUnit(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableValidityUnit sets the "validity_unit" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableValidityUnit(v *string) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetValidityUnit(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetFeatures sets the "features" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetFeatures(v string) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.SetFeatures(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableFeatures sets the "features" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableFeatures(v *string) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetFeatures(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetProductName sets the "product_name" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetProductName(v string) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.SetProductName(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableProductName sets the "product_name" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableProductName(v *string) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetProductName(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetForSale sets the "for_sale" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetForSale(v bool) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.SetForSale(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableForSale sets the "for_sale" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableForSale(v *bool) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetForSale(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetSortOrder sets the "sort_order" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetSortOrder(v int) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.ResetSortOrder()
|
||||
_u.mutation.SetSortOrder(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableSortOrder sets the "sort_order" field if the given value is not nil.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetNillableSortOrder(v *int) *SubscriptionPlanUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetSortOrder(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddSortOrder adds value to the "sort_order" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) AddSortOrder(v int) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.AddSortOrder(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetUpdatedAt sets the "updated_at" field.
|
||||
func (_u *SubscriptionPlanUpdateOne) SetUpdatedAt(v time.Time) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.SetUpdatedAt(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Mutation returns the SubscriptionPlanMutation object of the builder.
|
||||
func (_u *SubscriptionPlanUpdateOne) Mutation() *SubscriptionPlanMutation {
|
||||
return _u.mutation
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the SubscriptionPlanUpdate builder.
|
||||
func (_u *SubscriptionPlanUpdateOne) Where(ps ...predicate.SubscriptionPlan) *SubscriptionPlanUpdateOne {
|
||||
_u.mutation.Where(ps...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||
// The default is selecting all fields defined in the entity schema.
|
||||
func (_u *SubscriptionPlanUpdateOne) Select(field string, fields ...string) *SubscriptionPlanUpdateOne {
|
||||
_u.fields = append([]string{field}, fields...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// Save executes the query and returns the updated SubscriptionPlan entity.
|
||||
func (_u *SubscriptionPlanUpdateOne) Save(ctx context.Context) (*SubscriptionPlan, error) {
|
||||
_u.defaults()
|
||||
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||
}
|
||||
|
||||
// SaveX is like Save, but panics if an error occurs.
|
||||
func (_u *SubscriptionPlanUpdateOne) SaveX(ctx context.Context) *SubscriptionPlan {
|
||||
node, err := _u.Save(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// Exec executes the query on the entity.
|
||||
func (_u *SubscriptionPlanUpdateOne) Exec(ctx context.Context) error {
|
||||
_, err := _u.Save(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// ExecX is like Exec, but panics if an error occurs.
|
||||
func (_u *SubscriptionPlanUpdateOne) ExecX(ctx context.Context) {
|
||||
if err := _u.Exec(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// defaults sets the default values of the builder before save.
|
||||
func (_u *SubscriptionPlanUpdateOne) defaults() {
|
||||
if _, ok := _u.mutation.UpdatedAt(); !ok {
|
||||
v := subscriptionplan.UpdateDefaultUpdatedAt()
|
||||
_u.mutation.SetUpdatedAt(v)
|
||||
}
|
||||
}
|
||||
|
||||
// check runs all checks and user-defined validators on the builder.
|
||||
func (_u *SubscriptionPlanUpdateOne) check() error {
|
||||
if v, ok := _u.mutation.Name(); ok {
|
||||
if err := subscriptionplan.NameValidator(v); err != nil {
|
||||
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "SubscriptionPlan.name": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.ValidityUnit(); ok {
|
||||
if err := subscriptionplan.ValidityUnitValidator(v); err != nil {
|
||||
return &ValidationError{Name: "validity_unit", err: fmt.Errorf(`ent: validator failed for field "SubscriptionPlan.validity_unit": %w`, err)}
|
||||
}
|
||||
}
|
||||
if v, ok := _u.mutation.ProductName(); ok {
|
||||
if err := subscriptionplan.ProductNameValidator(v); err != nil {
|
||||
return &ValidationError{Name: "product_name", err: fmt.Errorf(`ent: validator failed for field "SubscriptionPlan.product_name": %w`, err)}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_u *SubscriptionPlanUpdateOne) sqlSave(ctx context.Context) (_node *SubscriptionPlan, err error) {
|
||||
if err := _u.check(); err != nil {
|
||||
return _node, err
|
||||
}
|
||||
_spec := sqlgraph.NewUpdateSpec(subscriptionplan.Table, subscriptionplan.Columns, sqlgraph.NewFieldSpec(subscriptionplan.FieldID, field.TypeInt64))
|
||||
id, ok := _u.mutation.ID()
|
||||
if !ok {
|
||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "SubscriptionPlan.id" for update`)}
|
||||
}
|
||||
_spec.Node.ID.Value = id
|
||||
if fields := _u.fields; len(fields) > 0 {
|
||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, subscriptionplan.FieldID)
|
||||
for _, f := range fields {
|
||||
if !subscriptionplan.ValidColumn(f) {
|
||||
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||
}
|
||||
if f != subscriptionplan.FieldID {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||
_spec.Predicate = func(selector *sql.Selector) {
|
||||
for i := range ps {
|
||||
ps[i](selector)
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, ok := _u.mutation.GroupID(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldGroupID, field.TypeInt64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedGroupID(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldGroupID, field.TypeInt64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Name(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldName, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Description(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldDescription, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Price(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldPrice, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedPrice(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldPrice, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.OriginalPrice(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldOriginalPrice, field.TypeFloat64, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedOriginalPrice(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldOriginalPrice, field.TypeFloat64, value)
|
||||
}
|
||||
if _u.mutation.OriginalPriceCleared() {
|
||||
_spec.ClearField(subscriptionplan.FieldOriginalPrice, field.TypeFloat64)
|
||||
}
|
||||
if value, ok := _u.mutation.ValidityDays(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldValidityDays, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedValidityDays(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldValidityDays, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ValidityUnit(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldValidityUnit, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.Features(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldFeatures, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ProductName(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldProductName, field.TypeString, value)
|
||||
}
|
||||
if value, ok := _u.mutation.ForSale(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldForSale, field.TypeBool, value)
|
||||
}
|
||||
if value, ok := _u.mutation.SortOrder(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldSortOrder, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedSortOrder(); ok {
|
||||
_spec.AddField(subscriptionplan.FieldSortOrder, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.UpdatedAt(); ok {
|
||||
_spec.SetField(subscriptionplan.FieldUpdatedAt, field.TypeTime, value)
|
||||
}
|
||||
_node = &SubscriptionPlan{config: _u.config}
|
||||
_spec.Assign = _node.assignValues
|
||||
_spec.ScanValues = _node.scanValues
|
||||
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{subscriptionplan.Label}
|
||||
} else if sqlgraph.IsConstraintError(err) {
|
||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
_u.mutation.done = true
|
||||
return _node, nil
|
||||
}
|
||||
@@ -30,6 +30,12 @@ type Tx struct {
|
||||
Group *GroupClient
|
||||
// IdempotencyRecord is the client for interacting with the IdempotencyRecord builders.
|
||||
IdempotencyRecord *IdempotencyRecordClient
|
||||
// PaymentAuditLog is the client for interacting with the PaymentAuditLog builders.
|
||||
PaymentAuditLog *PaymentAuditLogClient
|
||||
// PaymentOrder is the client for interacting with the PaymentOrder builders.
|
||||
PaymentOrder *PaymentOrderClient
|
||||
// PaymentProviderInstance is the client for interacting with the PaymentProviderInstance builders.
|
||||
PaymentProviderInstance *PaymentProviderInstanceClient
|
||||
// PromoCode is the client for interacting with the PromoCode builders.
|
||||
PromoCode *PromoCodeClient
|
||||
// PromoCodeUsage is the client for interacting with the PromoCodeUsage builders.
|
||||
@@ -42,6 +48,8 @@ type Tx struct {
|
||||
SecuritySecret *SecuritySecretClient
|
||||
// Setting is the client for interacting with the Setting builders.
|
||||
Setting *SettingClient
|
||||
// SubscriptionPlan is the client for interacting with the SubscriptionPlan builders.
|
||||
SubscriptionPlan *SubscriptionPlanClient
|
||||
// TLSFingerprintProfile is the client for interacting with the TLSFingerprintProfile builders.
|
||||
TLSFingerprintProfile *TLSFingerprintProfileClient
|
||||
// UsageCleanupTask is the client for interacting with the UsageCleanupTask builders.
|
||||
@@ -197,12 +205,16 @@ func (tx *Tx) init() {
|
||||
tx.ErrorPassthroughRule = NewErrorPassthroughRuleClient(tx.config)
|
||||
tx.Group = NewGroupClient(tx.config)
|
||||
tx.IdempotencyRecord = NewIdempotencyRecordClient(tx.config)
|
||||
tx.PaymentAuditLog = NewPaymentAuditLogClient(tx.config)
|
||||
tx.PaymentOrder = NewPaymentOrderClient(tx.config)
|
||||
tx.PaymentProviderInstance = NewPaymentProviderInstanceClient(tx.config)
|
||||
tx.PromoCode = NewPromoCodeClient(tx.config)
|
||||
tx.PromoCodeUsage = NewPromoCodeUsageClient(tx.config)
|
||||
tx.Proxy = NewProxyClient(tx.config)
|
||||
tx.RedeemCode = NewRedeemCodeClient(tx.config)
|
||||
tx.SecuritySecret = NewSecuritySecretClient(tx.config)
|
||||
tx.Setting = NewSettingClient(tx.config)
|
||||
tx.SubscriptionPlan = NewSubscriptionPlanClient(tx.config)
|
||||
tx.TLSFingerprintProfile = NewTLSFingerprintProfileClient(tx.config)
|
||||
tx.UsageCleanupTask = NewUsageCleanupTaskClient(tx.config)
|
||||
tx.UsageLog = NewUsageLogClient(tx.config)
|
||||
|
||||
+18
-2
@@ -71,11 +71,13 @@ type UserEdges struct {
|
||||
AttributeValues []*UserAttributeValue `json:"attribute_values,omitempty"`
|
||||
// PromoCodeUsages holds the value of the promo_code_usages edge.
|
||||
PromoCodeUsages []*PromoCodeUsage `json:"promo_code_usages,omitempty"`
|
||||
// PaymentOrders holds the value of the payment_orders edge.
|
||||
PaymentOrders []*PaymentOrder `json:"payment_orders,omitempty"`
|
||||
// UserAllowedGroups holds the value of the user_allowed_groups edge.
|
||||
UserAllowedGroups []*UserAllowedGroup `json:"user_allowed_groups,omitempty"`
|
||||
// loadedTypes holds the information for reporting if a
|
||||
// type was loaded (or requested) in eager-loading or not.
|
||||
loadedTypes [10]bool
|
||||
loadedTypes [11]bool
|
||||
}
|
||||
|
||||
// APIKeysOrErr returns the APIKeys value or an error if the edge
|
||||
@@ -159,10 +161,19 @@ func (e UserEdges) PromoCodeUsagesOrErr() ([]*PromoCodeUsage, error) {
|
||||
return nil, &NotLoadedError{edge: "promo_code_usages"}
|
||||
}
|
||||
|
||||
// PaymentOrdersOrErr returns the PaymentOrders value or an error if the edge
|
||||
// was not loaded in eager-loading.
|
||||
func (e UserEdges) PaymentOrdersOrErr() ([]*PaymentOrder, error) {
|
||||
if e.loadedTypes[9] {
|
||||
return e.PaymentOrders, nil
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "payment_orders"}
|
||||
}
|
||||
|
||||
// UserAllowedGroupsOrErr returns the UserAllowedGroups value or an error if the edge
|
||||
// was not loaded in eager-loading.
|
||||
func (e UserEdges) UserAllowedGroupsOrErr() ([]*UserAllowedGroup, error) {
|
||||
if e.loadedTypes[9] {
|
||||
if e.loadedTypes[10] {
|
||||
return e.UserAllowedGroups, nil
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "user_allowed_groups"}
|
||||
@@ -349,6 +360,11 @@ func (_m *User) QueryPromoCodeUsages() *PromoCodeUsageQuery {
|
||||
return NewUserClient(_m.config).QueryPromoCodeUsages(_m)
|
||||
}
|
||||
|
||||
// QueryPaymentOrders queries the "payment_orders" edge of the User entity.
|
||||
func (_m *User) QueryPaymentOrders() *PaymentOrderQuery {
|
||||
return NewUserClient(_m.config).QueryPaymentOrders(_m)
|
||||
}
|
||||
|
||||
// QueryUserAllowedGroups queries the "user_allowed_groups" edge of the User entity.
|
||||
func (_m *User) QueryUserAllowedGroups() *UserAllowedGroupQuery {
|
||||
return NewUserClient(_m.config).QueryUserAllowedGroups(_m)
|
||||
|
||||
@@ -61,6 +61,8 @@ const (
|
||||
EdgeAttributeValues = "attribute_values"
|
||||
// EdgePromoCodeUsages holds the string denoting the promo_code_usages edge name in mutations.
|
||||
EdgePromoCodeUsages = "promo_code_usages"
|
||||
// EdgePaymentOrders holds the string denoting the payment_orders edge name in mutations.
|
||||
EdgePaymentOrders = "payment_orders"
|
||||
// EdgeUserAllowedGroups holds the string denoting the user_allowed_groups edge name in mutations.
|
||||
EdgeUserAllowedGroups = "user_allowed_groups"
|
||||
// Table holds the table name of the user in the database.
|
||||
@@ -126,6 +128,13 @@ const (
|
||||
PromoCodeUsagesInverseTable = "promo_code_usages"
|
||||
// PromoCodeUsagesColumn is the table column denoting the promo_code_usages relation/edge.
|
||||
PromoCodeUsagesColumn = "user_id"
|
||||
// PaymentOrdersTable is the table that holds the payment_orders relation/edge.
|
||||
PaymentOrdersTable = "payment_orders"
|
||||
// PaymentOrdersInverseTable is the table name for the PaymentOrder entity.
|
||||
// It exists in this package in order to avoid circular dependency with the "paymentorder" package.
|
||||
PaymentOrdersInverseTable = "payment_orders"
|
||||
// PaymentOrdersColumn is the table column denoting the payment_orders relation/edge.
|
||||
PaymentOrdersColumn = "user_id"
|
||||
// UserAllowedGroupsTable is the table that holds the user_allowed_groups relation/edge.
|
||||
UserAllowedGroupsTable = "user_allowed_groups"
|
||||
// UserAllowedGroupsInverseTable is the table name for the UserAllowedGroup entity.
|
||||
@@ -414,6 +423,20 @@ func ByPromoCodeUsages(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
|
||||
}
|
||||
}
|
||||
|
||||
// ByPaymentOrdersCount orders the results by payment_orders count.
|
||||
func ByPaymentOrdersCount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
sqlgraph.OrderByNeighborsCount(s, newPaymentOrdersStep(), opts...)
|
||||
}
|
||||
}
|
||||
|
||||
// ByPaymentOrders orders the results by payment_orders terms.
|
||||
func ByPaymentOrders(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
sqlgraph.OrderByNeighborTerms(s, newPaymentOrdersStep(), append([]sql.OrderTerm{term}, terms...)...)
|
||||
}
|
||||
}
|
||||
|
||||
// ByUserAllowedGroupsCount orders the results by user_allowed_groups count.
|
||||
func ByUserAllowedGroupsCount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
@@ -490,6 +513,13 @@ func newPromoCodeUsagesStep() *sqlgraph.Step {
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, PromoCodeUsagesTable, PromoCodeUsagesColumn),
|
||||
)
|
||||
}
|
||||
func newPaymentOrdersStep() *sqlgraph.Step {
|
||||
return sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(PaymentOrdersInverseTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, PaymentOrdersTable, PaymentOrdersColumn),
|
||||
)
|
||||
}
|
||||
func newUserAllowedGroupsStep() *sqlgraph.Step {
|
||||
return sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
|
||||
@@ -1067,6 +1067,29 @@ func HasPromoCodeUsagesWith(preds ...predicate.PromoCodeUsage) predicate.User {
|
||||
})
|
||||
}
|
||||
|
||||
// HasPaymentOrders applies the HasEdge predicate on the "payment_orders" edge.
|
||||
func HasPaymentOrders() predicate.User {
|
||||
return predicate.User(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, PaymentOrdersTable, PaymentOrdersColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
})
|
||||
}
|
||||
|
||||
// HasPaymentOrdersWith applies the HasEdge predicate on the "payment_orders" edge with a given conditions (other predicates).
|
||||
func HasPaymentOrdersWith(preds ...predicate.PaymentOrder) predicate.User {
|
||||
return predicate.User(func(s *sql.Selector) {
|
||||
step := newPaymentOrdersStep()
|
||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||
for _, p := range preds {
|
||||
p(s)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// HasUserAllowedGroups applies the HasEdge predicate on the "user_allowed_groups" edge.
|
||||
func HasUserAllowedGroups() predicate.User {
|
||||
return predicate.User(func(s *sql.Selector) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/announcementread"
|
||||
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
|
||||
"github.com/Wei-Shaw/sub2api/ent/redeemcode"
|
||||
"github.com/Wei-Shaw/sub2api/ent/usagelog"
|
||||
@@ -345,6 +346,21 @@ func (_c *UserCreate) AddPromoCodeUsages(v ...*PromoCodeUsage) *UserCreate {
|
||||
return _c.AddPromoCodeUsageIDs(ids...)
|
||||
}
|
||||
|
||||
// AddPaymentOrderIDs adds the "payment_orders" edge to the PaymentOrder entity by IDs.
|
||||
func (_c *UserCreate) AddPaymentOrderIDs(ids ...int64) *UserCreate {
|
||||
_c.mutation.AddPaymentOrderIDs(ids...)
|
||||
return _c
|
||||
}
|
||||
|
||||
// AddPaymentOrders adds the "payment_orders" edges to the PaymentOrder entity.
|
||||
func (_c *UserCreate) AddPaymentOrders(v ...*PaymentOrder) *UserCreate {
|
||||
ids := make([]int64, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _c.AddPaymentOrderIDs(ids...)
|
||||
}
|
||||
|
||||
// Mutation returns the UserMutation object of the builder.
|
||||
func (_c *UserCreate) Mutation() *UserMutation {
|
||||
return _c.mutation
|
||||
@@ -718,6 +734,22 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
||||
}
|
||||
_spec.Edges = append(_spec.Edges, edge)
|
||||
}
|
||||
if nodes := _c.mutation.PaymentOrdersIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.PaymentOrdersTable,
|
||||
Columns: []string{user.PaymentOrdersColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges = append(_spec.Edges, edge)
|
||||
}
|
||||
return _node, _spec
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/announcementread"
|
||||
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
|
||||
"github.com/Wei-Shaw/sub2api/ent/redeemcode"
|
||||
@@ -42,6 +43,7 @@ type UserQuery struct {
|
||||
withUsageLogs *UsageLogQuery
|
||||
withAttributeValues *UserAttributeValueQuery
|
||||
withPromoCodeUsages *PromoCodeUsageQuery
|
||||
withPaymentOrders *PaymentOrderQuery
|
||||
withUserAllowedGroups *UserAllowedGroupQuery
|
||||
modifiers []func(*sql.Selector)
|
||||
// intermediate query (i.e. traversal path).
|
||||
@@ -278,6 +280,28 @@ func (_q *UserQuery) QueryPromoCodeUsages() *PromoCodeUsageQuery {
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryPaymentOrders chains the current query on the "payment_orders" edge.
|
||||
func (_q *UserQuery) QueryPaymentOrders() *PaymentOrderQuery {
|
||||
query := (&PaymentOrderClient{config: _q.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector := _q.sqlQuery(ctx)
|
||||
if err := selector.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(user.Table, user.FieldID, selector),
|
||||
sqlgraph.To(paymentorder.Table, paymentorder.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, user.PaymentOrdersTable, user.PaymentOrdersColumn),
|
||||
)
|
||||
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
|
||||
return fromU, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryUserAllowedGroups chains the current query on the "user_allowed_groups" edge.
|
||||
func (_q *UserQuery) QueryUserAllowedGroups() *UserAllowedGroupQuery {
|
||||
query := (&UserAllowedGroupClient{config: _q.config}).Query()
|
||||
@@ -501,6 +525,7 @@ func (_q *UserQuery) Clone() *UserQuery {
|
||||
withUsageLogs: _q.withUsageLogs.Clone(),
|
||||
withAttributeValues: _q.withAttributeValues.Clone(),
|
||||
withPromoCodeUsages: _q.withPromoCodeUsages.Clone(),
|
||||
withPaymentOrders: _q.withPaymentOrders.Clone(),
|
||||
withUserAllowedGroups: _q.withUserAllowedGroups.Clone(),
|
||||
// clone intermediate query.
|
||||
sql: _q.sql.Clone(),
|
||||
@@ -607,6 +632,17 @@ func (_q *UserQuery) WithPromoCodeUsages(opts ...func(*PromoCodeUsageQuery)) *Us
|
||||
return _q
|
||||
}
|
||||
|
||||
// WithPaymentOrders tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "payment_orders" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (_q *UserQuery) WithPaymentOrders(opts ...func(*PaymentOrderQuery)) *UserQuery {
|
||||
query := (&PaymentOrderClient{config: _q.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
_q.withPaymentOrders = query
|
||||
return _q
|
||||
}
|
||||
|
||||
// WithUserAllowedGroups tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "user_allowed_groups" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (_q *UserQuery) WithUserAllowedGroups(opts ...func(*UserAllowedGroupQuery)) *UserQuery {
|
||||
@@ -696,7 +732,7 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
|
||||
var (
|
||||
nodes = []*User{}
|
||||
_spec = _q.querySpec()
|
||||
loadedTypes = [10]bool{
|
||||
loadedTypes = [11]bool{
|
||||
_q.withAPIKeys != nil,
|
||||
_q.withRedeemCodes != nil,
|
||||
_q.withSubscriptions != nil,
|
||||
@@ -706,6 +742,7 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
|
||||
_q.withUsageLogs != nil,
|
||||
_q.withAttributeValues != nil,
|
||||
_q.withPromoCodeUsages != nil,
|
||||
_q.withPaymentOrders != nil,
|
||||
_q.withUserAllowedGroups != nil,
|
||||
}
|
||||
)
|
||||
@@ -795,6 +832,13 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if query := _q.withPaymentOrders; query != nil {
|
||||
if err := _q.loadPaymentOrders(ctx, query, nodes,
|
||||
func(n *User) { n.Edges.PaymentOrders = []*PaymentOrder{} },
|
||||
func(n *User, e *PaymentOrder) { n.Edges.PaymentOrders = append(n.Edges.PaymentOrders, e) }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if query := _q.withUserAllowedGroups; query != nil {
|
||||
if err := _q.loadUserAllowedGroups(ctx, query, nodes,
|
||||
func(n *User) { n.Edges.UserAllowedGroups = []*UserAllowedGroup{} },
|
||||
@@ -1112,6 +1156,36 @@ func (_q *UserQuery) loadPromoCodeUsages(ctx context.Context, query *PromoCodeUs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (_q *UserQuery) loadPaymentOrders(ctx context.Context, query *PaymentOrderQuery, nodes []*User, init func(*User), assign func(*User, *PaymentOrder)) error {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
nodeids := make(map[int64]*User)
|
||||
for i := range nodes {
|
||||
fks = append(fks, nodes[i].ID)
|
||||
nodeids[nodes[i].ID] = nodes[i]
|
||||
if init != nil {
|
||||
init(nodes[i])
|
||||
}
|
||||
}
|
||||
if len(query.ctx.Fields) > 0 {
|
||||
query.ctx.AppendFieldOnce(paymentorder.FieldUserID)
|
||||
}
|
||||
query.Where(predicate.PaymentOrder(func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(s.C(user.PaymentOrdersColumn), fks...))
|
||||
}))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
fk := n.UserID
|
||||
node, ok := nodeids[fk]
|
||||
if !ok {
|
||||
return fmt.Errorf(`unexpected referenced foreign-key "user_id" returned %v for node %v`, fk, n.ID)
|
||||
}
|
||||
assign(node, n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (_q *UserQuery) loadUserAllowedGroups(ctx context.Context, query *UserAllowedGroupQuery, nodes []*User, init func(*User), assign func(*User, *UserAllowedGroup)) error {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
nodeids := make(map[int64]*User)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/Wei-Shaw/sub2api/ent/announcementread"
|
||||
"github.com/Wei-Shaw/sub2api/ent/apikey"
|
||||
"github.com/Wei-Shaw/sub2api/ent/group"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/predicate"
|
||||
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
|
||||
"github.com/Wei-Shaw/sub2api/ent/redeemcode"
|
||||
@@ -377,6 +378,21 @@ func (_u *UserUpdate) AddPromoCodeUsages(v ...*PromoCodeUsage) *UserUpdate {
|
||||
return _u.AddPromoCodeUsageIDs(ids...)
|
||||
}
|
||||
|
||||
// AddPaymentOrderIDs adds the "payment_orders" edge to the PaymentOrder entity by IDs.
|
||||
func (_u *UserUpdate) AddPaymentOrderIDs(ids ...int64) *UserUpdate {
|
||||
_u.mutation.AddPaymentOrderIDs(ids...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddPaymentOrders adds the "payment_orders" edges to the PaymentOrder entity.
|
||||
func (_u *UserUpdate) AddPaymentOrders(v ...*PaymentOrder) *UserUpdate {
|
||||
ids := make([]int64, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _u.AddPaymentOrderIDs(ids...)
|
||||
}
|
||||
|
||||
// Mutation returns the UserMutation object of the builder.
|
||||
func (_u *UserUpdate) Mutation() *UserMutation {
|
||||
return _u.mutation
|
||||
@@ -571,6 +587,27 @@ func (_u *UserUpdate) RemovePromoCodeUsages(v ...*PromoCodeUsage) *UserUpdate {
|
||||
return _u.RemovePromoCodeUsageIDs(ids...)
|
||||
}
|
||||
|
||||
// ClearPaymentOrders clears all "payment_orders" edges to the PaymentOrder entity.
|
||||
func (_u *UserUpdate) ClearPaymentOrders() *UserUpdate {
|
||||
_u.mutation.ClearPaymentOrders()
|
||||
return _u
|
||||
}
|
||||
|
||||
// RemovePaymentOrderIDs removes the "payment_orders" edge to PaymentOrder entities by IDs.
|
||||
func (_u *UserUpdate) RemovePaymentOrderIDs(ids ...int64) *UserUpdate {
|
||||
_u.mutation.RemovePaymentOrderIDs(ids...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// RemovePaymentOrders removes "payment_orders" edges to PaymentOrder entities.
|
||||
func (_u *UserUpdate) RemovePaymentOrders(v ...*PaymentOrder) *UserUpdate {
|
||||
ids := make([]int64, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _u.RemovePaymentOrderIDs(ids...)
|
||||
}
|
||||
|
||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||
func (_u *UserUpdate) Save(ctx context.Context) (int, error) {
|
||||
if err := _u.defaults(); err != nil {
|
||||
@@ -1126,6 +1163,51 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
if _u.mutation.PaymentOrdersCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.PaymentOrdersTable,
|
||||
Columns: []string{user.PaymentOrdersColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := _u.mutation.RemovedPaymentOrdersIDs(); len(nodes) > 0 && !_u.mutation.PaymentOrdersCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.PaymentOrdersTable,
|
||||
Columns: []string{user.PaymentOrdersColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := _u.mutation.PaymentOrdersIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.PaymentOrdersTable,
|
||||
Columns: []string{user.PaymentOrdersColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{user.Label}
|
||||
@@ -1487,6 +1569,21 @@ func (_u *UserUpdateOne) AddPromoCodeUsages(v ...*PromoCodeUsage) *UserUpdateOne
|
||||
return _u.AddPromoCodeUsageIDs(ids...)
|
||||
}
|
||||
|
||||
// AddPaymentOrderIDs adds the "payment_orders" edge to the PaymentOrder entity by IDs.
|
||||
func (_u *UserUpdateOne) AddPaymentOrderIDs(ids ...int64) *UserUpdateOne {
|
||||
_u.mutation.AddPaymentOrderIDs(ids...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddPaymentOrders adds the "payment_orders" edges to the PaymentOrder entity.
|
||||
func (_u *UserUpdateOne) AddPaymentOrders(v ...*PaymentOrder) *UserUpdateOne {
|
||||
ids := make([]int64, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _u.AddPaymentOrderIDs(ids...)
|
||||
}
|
||||
|
||||
// Mutation returns the UserMutation object of the builder.
|
||||
func (_u *UserUpdateOne) Mutation() *UserMutation {
|
||||
return _u.mutation
|
||||
@@ -1681,6 +1778,27 @@ func (_u *UserUpdateOne) RemovePromoCodeUsages(v ...*PromoCodeUsage) *UserUpdate
|
||||
return _u.RemovePromoCodeUsageIDs(ids...)
|
||||
}
|
||||
|
||||
// ClearPaymentOrders clears all "payment_orders" edges to the PaymentOrder entity.
|
||||
func (_u *UserUpdateOne) ClearPaymentOrders() *UserUpdateOne {
|
||||
_u.mutation.ClearPaymentOrders()
|
||||
return _u
|
||||
}
|
||||
|
||||
// RemovePaymentOrderIDs removes the "payment_orders" edge to PaymentOrder entities by IDs.
|
||||
func (_u *UserUpdateOne) RemovePaymentOrderIDs(ids ...int64) *UserUpdateOne {
|
||||
_u.mutation.RemovePaymentOrderIDs(ids...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// RemovePaymentOrders removes "payment_orders" edges to PaymentOrder entities.
|
||||
func (_u *UserUpdateOne) RemovePaymentOrders(v ...*PaymentOrder) *UserUpdateOne {
|
||||
ids := make([]int64, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _u.RemovePaymentOrderIDs(ids...)
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the UserUpdate builder.
|
||||
func (_u *UserUpdateOne) Where(ps ...predicate.User) *UserUpdateOne {
|
||||
_u.mutation.Where(ps...)
|
||||
@@ -2266,6 +2384,51 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
if _u.mutation.PaymentOrdersCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.PaymentOrdersTable,
|
||||
Columns: []string{user.PaymentOrdersColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64),
|
||||
},
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := _u.mutation.RemovedPaymentOrdersIDs(); len(nodes) > 0 && !_u.mutation.PaymentOrdersCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.PaymentOrdersTable,
|
||||
Columns: []string{user.PaymentOrdersColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := _u.mutation.PaymentOrdersIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.PaymentOrdersTable,
|
||||
Columns: []string{user.PaymentOrdersColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64),
|
||||
},
|
||||
}
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||
}
|
||||
_node = &User{config: _u.config}
|
||||
_spec.Assign = _node.assignValues
|
||||
_spec.ScanValues = _node.scanValues
|
||||
|
||||
@@ -155,12 +155,18 @@ require (
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/smartwalle/alipay/v3 v3.2.29 // indirect
|
||||
github.com/smartwalle/ncrypto v1.0.4 // indirect
|
||||
github.com/smartwalle/ngx v1.1.0 // indirect
|
||||
github.com/smartwalle/nsign v1.0.9 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stripe/stripe-go/v82 v82.5.1 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect
|
||||
github.com/testcontainers/testcontainers-go v0.40.0 // indirect
|
||||
@@ -170,6 +176,7 @@ require (
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.21 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
github.com/zclconf/go-cty v1.14.4 // indirect
|
||||
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
|
||||
|
||||
@@ -20,6 +20,7 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
|
||||
github.com/alitto/pond/v2 v2.6.2 h1:Sphe40g0ILeM1pA2c2K+Th0DGU+pt0A/Kprr+WB24Pw=
|
||||
github.com/alitto/pond/v2 v2.6.2/go.mod h1:xkjYEgQ05RSpWdfSd1nM3OVv7TBhLdy7rMp3+2Nq+yE=
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
@@ -217,6 +218,8 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17k
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -361,8 +364,18 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
|
||||
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartwalle/alipay/v3 v3.2.29 h1:roGFqlml8hDa//0TpFmlyxZhndTYs7rbYLu/HlNFNJo=
|
||||
github.com/smartwalle/alipay/v3 v3.2.29/go.mod h1:XarBLuAkwK3ah7mYjVtghRu+ysxzlex9sRkgqNMzMRU=
|
||||
github.com/smartwalle/ncrypto v1.0.4 h1:P2rqQxDepJwgeO5ShoC+wGcK2wNJDmcdBOWAksuIgx8=
|
||||
github.com/smartwalle/ncrypto v1.0.4/go.mod h1:Dwlp6sfeNaPMnOxMNayMTacvC5JGEVln3CVdiVDgbBk=
|
||||
github.com/smartwalle/ngx v1.1.0 h1:q8nANgWSPRGeI/u+ixBoA4mf68DrUq6vZ+n9L5UKv9I=
|
||||
github.com/smartwalle/ngx v1.1.0/go.mod h1:mx/nz2Pk5j+RBs7t6u6k22MPiBG/8CtOMpCnALIG8Y0=
|
||||
github.com/smartwalle/nsign v1.0.9 h1:8poAgG7zBd8HkZy9RQDwasC6XZvJpDGQWSjzL2FZL6E=
|
||||
github.com/smartwalle/nsign v1.0.9/go.mod h1:eY6I4CJlyNdVMP+t6z1H6Jpd4m5/V+8xi44ufSTxXgc=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
@@ -392,6 +405,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stripe/stripe-go/v82 v82.5.1 h1:05q6ZDKoe8PLMpQV072obF74HCgP4XJeJYoNuRSX2+8=
|
||||
github.com/stripe/stripe-go/v82 v82.5.1/go.mod h1:majCQX6AfObAvJiHraPi/5udwHi4ojRvJnnxckvHrX8=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc=
|
||||
@@ -419,6 +434,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.21 h1:uIyMpzvcaHA33W/QPtHstccw+X52HO1gFdvVL9O6Lfs=
|
||||
github.com/wechatpay-apiv3/wechatpay-go v0.2.21/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
|
||||
@@ -33,6 +33,7 @@ type createChannelRequest struct {
|
||||
ModelMapping map[string]map[string]string `json:"model_mapping"`
|
||||
BillingModelSource string `json:"billing_model_source" binding:"omitempty,oneof=requested upstream channel_mapped"`
|
||||
RestrictModels bool `json:"restrict_models"`
|
||||
Features string `json:"features"`
|
||||
}
|
||||
|
||||
type updateChannelRequest struct {
|
||||
@@ -44,6 +45,7 @@ type updateChannelRequest struct {
|
||||
ModelMapping map[string]map[string]string `json:"model_mapping"`
|
||||
BillingModelSource string `json:"billing_model_source" binding:"omitempty,oneof=requested upstream channel_mapped"`
|
||||
RestrictModels *bool `json:"restrict_models"`
|
||||
Features *string `json:"features"`
|
||||
}
|
||||
|
||||
type channelModelPricingRequest struct {
|
||||
@@ -78,6 +80,7 @@ type channelResponse struct {
|
||||
Status string `json:"status"`
|
||||
BillingModelSource string `json:"billing_model_source"`
|
||||
RestrictModels bool `json:"restrict_models"`
|
||||
Features string `json:"features"`
|
||||
GroupIDs []int64 `json:"group_ids"`
|
||||
ModelPricing []channelModelPricingResponse `json:"model_pricing"`
|
||||
ModelMapping map[string]map[string]string `json:"model_mapping"`
|
||||
@@ -122,6 +125,7 @@ func channelToResponse(ch *service.Channel) *channelResponse {
|
||||
Description: ch.Description,
|
||||
Status: ch.Status,
|
||||
RestrictModels: ch.RestrictModels,
|
||||
Features: ch.Features,
|
||||
GroupIDs: ch.GroupIDs,
|
||||
ModelMapping: ch.ModelMapping,
|
||||
CreatedAt: ch.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
@@ -295,6 +299,7 @@ func (h *ChannelHandler) Create(c *gin.Context) {
|
||||
ModelMapping: req.ModelMapping,
|
||||
BillingModelSource: req.BillingModelSource,
|
||||
RestrictModels: req.RestrictModels,
|
||||
Features: req.Features,
|
||||
})
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
@@ -327,6 +332,7 @@ func (h *ChannelHandler) Update(c *gin.Context) {
|
||||
ModelMapping: req.ModelMapping,
|
||||
BillingModelSource: req.BillingModelSource,
|
||||
RestrictModels: req.RestrictModels,
|
||||
Features: req.Features,
|
||||
}
|
||||
if req.ModelPricing != nil {
|
||||
pricing := pricingRequestToService(*req.ModelPricing)
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// PaymentHandler handles admin payment management.
|
||||
type PaymentHandler struct {
|
||||
paymentService *service.PaymentService
|
||||
configService *service.PaymentConfigService
|
||||
}
|
||||
|
||||
// NewPaymentHandler creates a new admin PaymentHandler.
|
||||
func NewPaymentHandler(paymentService *service.PaymentService, configService *service.PaymentConfigService) *PaymentHandler {
|
||||
return &PaymentHandler{
|
||||
paymentService: paymentService,
|
||||
configService: configService,
|
||||
}
|
||||
}
|
||||
|
||||
// --- Dashboard ---
|
||||
|
||||
// GetDashboard returns payment dashboard statistics.
|
||||
// GET /api/v1/admin/payment/dashboard
|
||||
func (h *PaymentHandler) GetDashboard(c *gin.Context) {
|
||||
days := 30
|
||||
if d := c.Query("days"); d != "" {
|
||||
if v, err := strconv.Atoi(d); err == nil && v > 0 {
|
||||
days = v
|
||||
}
|
||||
}
|
||||
stats, err := h.paymentService.GetDashboardStats(c.Request.Context(), days)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, stats)
|
||||
}
|
||||
|
||||
// --- Orders ---
|
||||
|
||||
// ListOrders returns a paginated list of all payment orders.
|
||||
// GET /api/v1/admin/payment/orders
|
||||
func (h *PaymentHandler) ListOrders(c *gin.Context) {
|
||||
page, pageSize := response.ParsePagination(c)
|
||||
var userID int64
|
||||
if uid := c.Query("user_id"); uid != "" {
|
||||
if v, err := strconv.ParseInt(uid, 10, 64); err == nil {
|
||||
userID = v
|
||||
}
|
||||
}
|
||||
orders, total, err := h.paymentService.AdminListOrders(c.Request.Context(), userID, service.OrderListParams{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Status: c.Query("status"),
|
||||
OrderType: c.Query("order_type"),
|
||||
PaymentType: c.Query("payment_type"),
|
||||
})
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Paginated(c, orders, int64(total), page, pageSize)
|
||||
}
|
||||
|
||||
// GetOrderDetail returns detailed information about a single order.
|
||||
// GET /api/v1/admin/payment/orders/:id
|
||||
func (h *PaymentHandler) GetOrderDetail(c *gin.Context) {
|
||||
orderID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid order ID")
|
||||
return
|
||||
}
|
||||
order, err := h.paymentService.GetOrderByID(c.Request.Context(), orderID)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
auditLogs, _ := h.paymentService.GetOrderAuditLogs(c.Request.Context(), orderID)
|
||||
response.Success(c, gin.H{"order": order, "auditLogs": auditLogs})
|
||||
}
|
||||
|
||||
// CancelOrder cancels a pending order (admin).
|
||||
// POST /api/v1/admin/payment/orders/:id/cancel
|
||||
func (h *PaymentHandler) CancelOrder(c *gin.Context) {
|
||||
orderID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid order ID")
|
||||
return
|
||||
}
|
||||
msg, err := h.paymentService.AdminCancelOrder(c.Request.Context(), orderID)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": msg})
|
||||
}
|
||||
|
||||
// RetryFulfillment retries fulfillment for a paid order.
|
||||
// POST /api/v1/admin/payment/orders/:id/retry
|
||||
func (h *PaymentHandler) RetryFulfillment(c *gin.Context) {
|
||||
orderID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid order ID")
|
||||
return
|
||||
}
|
||||
if err := h.paymentService.RetryFulfillment(c.Request.Context(), orderID); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": "fulfillment retried"})
|
||||
}
|
||||
|
||||
// AdminProcessRefundRequest is the request body for admin refund processing.
|
||||
type AdminProcessRefundRequest struct {
|
||||
Amount float64 `json:"amount"`
|
||||
Reason string `json:"reason"`
|
||||
Force bool `json:"force"`
|
||||
DeductBalance bool `json:"deductBalance"`
|
||||
}
|
||||
|
||||
// ProcessRefund processes a refund for an order (admin).
|
||||
// POST /api/v1/admin/payment/orders/:id/refund
|
||||
func (h *PaymentHandler) ProcessRefund(c *gin.Context) {
|
||||
orderID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid order ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req AdminProcessRefundRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
plan, earlyResult, err := h.paymentService.PrepareRefund(c.Request.Context(), orderID, req.Amount, req.Reason, req.Force, req.DeductBalance)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
if earlyResult != nil {
|
||||
response.Success(c, earlyResult)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.paymentService.ExecuteRefund(c.Request.Context(), plan)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, result)
|
||||
}
|
||||
|
||||
// --- Subscription Plans ---
|
||||
|
||||
// ListPlans returns all subscription plans.
|
||||
// GET /api/v1/admin/payment/plans
|
||||
func (h *PaymentHandler) ListPlans(c *gin.Context) {
|
||||
plans, err := h.configService.ListPlans(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, plans)
|
||||
}
|
||||
|
||||
// CreatePlan creates a new subscription plan.
|
||||
// POST /api/v1/admin/payment/plans
|
||||
func (h *PaymentHandler) CreatePlan(c *gin.Context) {
|
||||
var req service.CreatePlanRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
plan, err := h.configService.CreatePlan(c.Request.Context(), req)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Created(c, plan)
|
||||
}
|
||||
|
||||
// UpdatePlan updates an existing subscription plan.
|
||||
// PUT /api/v1/admin/payment/plans/:id
|
||||
func (h *PaymentHandler) UpdatePlan(c *gin.Context) {
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid plan ID")
|
||||
return
|
||||
}
|
||||
var req service.UpdatePlanRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
plan, err := h.configService.UpdatePlan(c.Request.Context(), id, req)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, plan)
|
||||
}
|
||||
|
||||
// DeletePlan deletes a subscription plan.
|
||||
// DELETE /api/v1/admin/payment/plans/:id
|
||||
func (h *PaymentHandler) DeletePlan(c *gin.Context) {
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid plan ID")
|
||||
return
|
||||
}
|
||||
if err := h.configService.DeletePlan(c.Request.Context(), id); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": "deleted"})
|
||||
}
|
||||
|
||||
// --- Provider Instances ---
|
||||
|
||||
// ListProviders returns all payment provider instances.
|
||||
// GET /api/v1/admin/payment/providers
|
||||
func (h *PaymentHandler) ListProviders(c *gin.Context) {
|
||||
providers, err := h.configService.ListProviderInstances(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, providers)
|
||||
}
|
||||
|
||||
// CreateProvider creates a new payment provider instance.
|
||||
// POST /api/v1/admin/payment/providers
|
||||
func (h *PaymentHandler) CreateProvider(c *gin.Context) {
|
||||
var req service.CreateProviderInstanceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
inst, err := h.configService.CreateProviderInstance(c.Request.Context(), req)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Created(c, inst)
|
||||
}
|
||||
|
||||
// UpdateProvider updates an existing payment provider instance.
|
||||
// PUT /api/v1/admin/payment/providers/:id
|
||||
func (h *PaymentHandler) UpdateProvider(c *gin.Context) {
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid provider ID")
|
||||
return
|
||||
}
|
||||
var req service.UpdateProviderInstanceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
inst, err := h.configService.UpdateProviderInstance(c.Request.Context(), id, req)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, inst)
|
||||
}
|
||||
|
||||
// DeleteProvider deletes a payment provider instance.
|
||||
// DELETE /api/v1/admin/payment/providers/:id
|
||||
func (h *PaymentHandler) DeleteProvider(c *gin.Context) {
|
||||
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid provider ID")
|
||||
return
|
||||
}
|
||||
if err := h.configService.DeleteProviderInstance(c.Request.Context(), id); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": "deleted"})
|
||||
}
|
||||
|
||||
// --- Config ---
|
||||
|
||||
// GetConfig returns the payment configuration (admin view).
|
||||
// GET /api/v1/admin/payment/config
|
||||
func (h *PaymentHandler) GetConfig(c *gin.Context) {
|
||||
cfg, err := h.configService.GetPaymentConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, cfg)
|
||||
}
|
||||
|
||||
// UpdateConfig updates the payment configuration.
|
||||
// PUT /api/v1/admin/payment/config
|
||||
func (h *PaymentHandler) UpdateConfig(c *gin.Context) {
|
||||
var req service.UpdatePaymentConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
if err := h.configService.UpdatePaymentConfig(c.Request.Context(), req); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": "updated"})
|
||||
}
|
||||
@@ -31,22 +31,25 @@ type AdminHandlers struct {
|
||||
APIKey *admin.AdminAPIKeyHandler
|
||||
ScheduledTest *admin.ScheduledTestHandler
|
||||
Channel *admin.ChannelHandler
|
||||
Payment *admin.PaymentHandler
|
||||
}
|
||||
|
||||
// Handlers contains all HTTP handlers
|
||||
type Handlers struct {
|
||||
Auth *AuthHandler
|
||||
User *UserHandler
|
||||
APIKey *APIKeyHandler
|
||||
Usage *UsageHandler
|
||||
Redeem *RedeemHandler
|
||||
Subscription *SubscriptionHandler
|
||||
Announcement *AnnouncementHandler
|
||||
Admin *AdminHandlers
|
||||
Gateway *GatewayHandler
|
||||
OpenAIGateway *OpenAIGatewayHandler
|
||||
Setting *SettingHandler
|
||||
Totp *TotpHandler
|
||||
Auth *AuthHandler
|
||||
User *UserHandler
|
||||
APIKey *APIKeyHandler
|
||||
Usage *UsageHandler
|
||||
Redeem *RedeemHandler
|
||||
Subscription *SubscriptionHandler
|
||||
Announcement *AnnouncementHandler
|
||||
Admin *AdminHandlers
|
||||
Gateway *GatewayHandler
|
||||
OpenAIGateway *OpenAIGatewayHandler
|
||||
Setting *SettingHandler
|
||||
Totp *TotpHandler
|
||||
Payment *PaymentHandler
|
||||
PaymentWebhook *PaymentWebhookHandler
|
||||
}
|
||||
|
||||
// BuildInfo contains build-time information
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
|
||||
middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// PaymentHandler handles user-facing payment requests.
|
||||
type PaymentHandler struct {
|
||||
channelService *service.ChannelService
|
||||
paymentService *service.PaymentService
|
||||
configService *service.PaymentConfigService
|
||||
}
|
||||
|
||||
// NewPaymentHandler creates a new PaymentHandler.
|
||||
func NewPaymentHandler(paymentService *service.PaymentService, configService *service.PaymentConfigService, channelService *service.ChannelService) *PaymentHandler {
|
||||
return &PaymentHandler{
|
||||
channelService: channelService,
|
||||
paymentService: paymentService,
|
||||
configService: configService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetPaymentConfig returns the payment system configuration.
|
||||
// GET /api/v1/payment/config
|
||||
func (h *PaymentHandler) GetPaymentConfig(c *gin.Context) {
|
||||
cfg, err := h.configService.GetPaymentConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, cfg)
|
||||
}
|
||||
|
||||
// GetPlans returns subscription plans available for sale.
|
||||
// GET /api/v1/payment/plans
|
||||
func (h *PaymentHandler) GetPlans(c *gin.Context) {
|
||||
plans, err := h.configService.ListPlansForSale(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, plans)
|
||||
}
|
||||
|
||||
// GetChannels returns enabled payment channels.
|
||||
// GET /api/v1/payment/channels
|
||||
func (h *PaymentHandler) GetChannels(c *gin.Context) {
|
||||
channels, _, err := h.channelService.List(c.Request.Context(), pagination.PaginationParams{Page: 1, PageSize: 1000}, "active", "")
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, channels)
|
||||
}
|
||||
|
||||
// GetLimits returns per-payment-type limits.
|
||||
// GET /api/v1/payment/limits
|
||||
func (h *PaymentHandler) GetLimits(c *gin.Context) {
|
||||
cfg, err := h.configService.GetPaymentConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
limits, err := h.configService.GetMethodLimits(c.Request.Context(), cfg.EnabledTypes)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, limits)
|
||||
}
|
||||
|
||||
// CreateOrderRequest is the request body for creating a payment order.
|
||||
type CreateOrderRequest struct {
|
||||
Amount float64 `json:"amount"`
|
||||
PaymentType string `json:"paymentType" binding:"required"`
|
||||
OrderType string `json:"orderType"`
|
||||
PlanID int64 `json:"planId"`
|
||||
}
|
||||
|
||||
// CreateOrder creates a new payment order.
|
||||
// POST /api/v1/payment/orders
|
||||
func (h *PaymentHandler) CreateOrder(c *gin.Context) {
|
||||
subject, ok := middleware2.GetAuthSubjectFromContext(c)
|
||||
if !ok {
|
||||
response.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
var req CreateOrderRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.paymentService.CreateOrder(c.Request.Context(), service.CreateOrderRequest{
|
||||
UserID: subject.UserID,
|
||||
Amount: req.Amount,
|
||||
PaymentType: req.PaymentType,
|
||||
ClientIP: c.ClientIP(),
|
||||
IsMobile: isMobile(c),
|
||||
SrcHost: c.Request.Host,
|
||||
SrcURL: c.Request.Referer(),
|
||||
OrderType: req.OrderType,
|
||||
PlanID: req.PlanID,
|
||||
})
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, result)
|
||||
}
|
||||
|
||||
// GetMyOrders returns the authenticated user's orders.
|
||||
// GET /api/v1/payment/orders/my
|
||||
func (h *PaymentHandler) GetMyOrders(c *gin.Context) {
|
||||
subject, ok := middleware2.GetAuthSubjectFromContext(c)
|
||||
if !ok {
|
||||
response.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
page, pageSize := response.ParsePagination(c)
|
||||
orders, total, err := h.paymentService.GetUserOrders(c.Request.Context(), subject.UserID, service.OrderListParams{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Status: c.Query("status"),
|
||||
OrderType: c.Query("order_type"),
|
||||
PaymentType: c.Query("payment_type"),
|
||||
})
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Paginated(c, orders, int64(total), page, pageSize)
|
||||
}
|
||||
|
||||
// GetOrder returns a single order for the authenticated user.
|
||||
// GET /api/v1/payment/orders/:id
|
||||
func (h *PaymentHandler) GetOrder(c *gin.Context) {
|
||||
subject, ok := middleware2.GetAuthSubjectFromContext(c)
|
||||
if !ok {
|
||||
response.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
orderID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid order ID")
|
||||
return
|
||||
}
|
||||
|
||||
order, err := h.paymentService.GetOrder(c.Request.Context(), orderID, subject.UserID)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, order)
|
||||
}
|
||||
|
||||
// CancelOrder cancels a pending order for the authenticated user.
|
||||
// POST /api/v1/payment/orders/:id/cancel
|
||||
func (h *PaymentHandler) CancelOrder(c *gin.Context) {
|
||||
subject, ok := middleware2.GetAuthSubjectFromContext(c)
|
||||
if !ok {
|
||||
response.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
orderID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid order ID")
|
||||
return
|
||||
}
|
||||
|
||||
msg, err := h.paymentService.CancelOrder(c.Request.Context(), orderID, subject.UserID)
|
||||
if err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": msg})
|
||||
}
|
||||
|
||||
// RefundRequestBody is the request body for requesting a refund.
|
||||
type RefundRequestBody struct {
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// RequestRefund submits a refund request for a completed order.
|
||||
// POST /api/v1/payment/orders/:id/refund-request
|
||||
func (h *PaymentHandler) RequestRefund(c *gin.Context) {
|
||||
subject, ok := middleware2.GetAuthSubjectFromContext(c)
|
||||
if !ok {
|
||||
response.Unauthorized(c, "User not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
orderID, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
response.BadRequest(c, "Invalid order ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req RefundRequestBody
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "Invalid request: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.paymentService.RequestRefund(c.Request.Context(), orderID, subject.UserID, req.Reason); err != nil {
|
||||
response.ErrorFrom(c, err)
|
||||
return
|
||||
}
|
||||
response.Success(c, gin.H{"message": "refund requested"})
|
||||
}
|
||||
|
||||
// isMobile detects mobile user agents.
|
||||
func isMobile(c *gin.Context) bool {
|
||||
ua := strings.ToLower(c.GetHeader("User-Agent"))
|
||||
return strings.Contains(ua, "mobile") || strings.Contains(ua, "android") || strings.Contains(ua, "iphone")
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// PaymentWebhookHandler handles payment provider webhook callbacks.
|
||||
type PaymentWebhookHandler struct {
|
||||
paymentService *service.PaymentService
|
||||
registry *payment.Registry
|
||||
}
|
||||
|
||||
// NewPaymentWebhookHandler creates a new PaymentWebhookHandler.
|
||||
func NewPaymentWebhookHandler(paymentService *service.PaymentService, registry *payment.Registry) *PaymentWebhookHandler {
|
||||
return &PaymentWebhookHandler{
|
||||
paymentService: paymentService,
|
||||
registry: registry,
|
||||
}
|
||||
}
|
||||
|
||||
// EasyPayNotify handles EasyPay payment notifications.
|
||||
// POST /api/v1/payment/webhook/easypay
|
||||
func (h *PaymentWebhookHandler) EasyPayNotify(c *gin.Context) {
|
||||
h.handleNotify(c, "easypay")
|
||||
}
|
||||
|
||||
// AlipayNotify handles Alipay payment notifications.
|
||||
// POST /api/v1/payment/webhook/alipay
|
||||
func (h *PaymentWebhookHandler) AlipayNotify(c *gin.Context) {
|
||||
h.handleNotify(c, "alipay")
|
||||
}
|
||||
|
||||
// WxpayNotify handles WeChat Pay payment notifications.
|
||||
// POST /api/v1/payment/webhook/wxpay
|
||||
func (h *PaymentWebhookHandler) WxpayNotify(c *gin.Context) {
|
||||
h.handleNotify(c, "wxpay")
|
||||
}
|
||||
|
||||
// StripeWebhook handles Stripe webhook events.
|
||||
// POST /api/v1/payment/webhook/stripe
|
||||
func (h *PaymentWebhookHandler) StripeWebhook(c *gin.Context) {
|
||||
h.handleNotify(c, "stripe")
|
||||
}
|
||||
|
||||
// handleNotify is the shared logic for all provider webhook handlers.
|
||||
func (h *PaymentWebhookHandler) handleNotify(c *gin.Context, providerKey string) {
|
||||
body, err := io.ReadAll(io.LimitReader(c.Request.Body, 1<<20)) // 1MB limit
|
||||
if err != nil {
|
||||
slog.Error("[Payment Webhook] failed to read body", "provider", providerKey, "error", err)
|
||||
c.String(http.StatusBadRequest, "failed to read body")
|
||||
return
|
||||
}
|
||||
|
||||
provider, err := h.registry.GetProviderByKey(providerKey)
|
||||
if err != nil {
|
||||
slog.Warn("[Payment Webhook] provider not registered", "provider", providerKey, "error", err)
|
||||
c.String(http.StatusOK, successResponse(providerKey))
|
||||
return
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
for k := range c.Request.Header {
|
||||
headers[k] = c.GetHeader(k)
|
||||
}
|
||||
|
||||
notification, err := provider.VerifyNotification(c.Request.Context(), string(body), headers)
|
||||
if err != nil {
|
||||
slog.Error("[Payment Webhook] verify failed", "provider", providerKey, "error", err)
|
||||
c.String(http.StatusBadRequest, "verify failed")
|
||||
return
|
||||
}
|
||||
|
||||
// nil notification means irrelevant event (e.g. Stripe non-payment event); return success.
|
||||
if notification == nil {
|
||||
c.String(http.StatusOK, successResponse(providerKey))
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.paymentService.HandlePaymentNotification(c.Request.Context(), notification, providerKey); err != nil {
|
||||
slog.Error("[Payment Webhook] handle notification failed", "provider", providerKey, "error", err)
|
||||
c.String(http.StatusInternalServerError, "handle failed")
|
||||
return
|
||||
}
|
||||
|
||||
c.String(http.StatusOK, successResponse(providerKey))
|
||||
}
|
||||
|
||||
// successResponse returns the provider-specific success response string.
|
||||
func successResponse(providerKey string) string {
|
||||
switch providerKey {
|
||||
case "stripe":
|
||||
return ""
|
||||
default:
|
||||
return "success"
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ func ProvideAdminHandlers(
|
||||
apiKeyHandler *admin.AdminAPIKeyHandler,
|
||||
scheduledTestHandler *admin.ScheduledTestHandler,
|
||||
channelHandler *admin.ChannelHandler,
|
||||
paymentHandler *admin.PaymentHandler,
|
||||
) *AdminHandlers {
|
||||
return &AdminHandlers{
|
||||
Dashboard: dashboardHandler,
|
||||
@@ -61,6 +62,7 @@ func ProvideAdminHandlers(
|
||||
APIKey: apiKeyHandler,
|
||||
ScheduledTest: scheduledTestHandler,
|
||||
Channel: channelHandler,
|
||||
Payment: paymentHandler,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,22 +90,26 @@ func ProvideHandlers(
|
||||
openaiGatewayHandler *OpenAIGatewayHandler,
|
||||
settingHandler *SettingHandler,
|
||||
totpHandler *TotpHandler,
|
||||
paymentHandler *PaymentHandler,
|
||||
paymentWebhookHandler *PaymentWebhookHandler,
|
||||
_ *service.IdempotencyCoordinator,
|
||||
_ *service.IdempotencyCleanupService,
|
||||
) *Handlers {
|
||||
return &Handlers{
|
||||
Auth: authHandler,
|
||||
User: userHandler,
|
||||
APIKey: apiKeyHandler,
|
||||
Usage: usageHandler,
|
||||
Redeem: redeemHandler,
|
||||
Subscription: subscriptionHandler,
|
||||
Announcement: announcementHandler,
|
||||
Admin: adminHandlers,
|
||||
Gateway: gatewayHandler,
|
||||
OpenAIGateway: openaiGatewayHandler,
|
||||
Setting: settingHandler,
|
||||
Totp: totpHandler,
|
||||
Auth: authHandler,
|
||||
User: userHandler,
|
||||
APIKey: apiKeyHandler,
|
||||
Usage: usageHandler,
|
||||
Redeem: redeemHandler,
|
||||
Subscription: subscriptionHandler,
|
||||
Announcement: announcementHandler,
|
||||
Admin: adminHandlers,
|
||||
Gateway: gatewayHandler,
|
||||
OpenAIGateway: openaiGatewayHandler,
|
||||
Setting: settingHandler,
|
||||
Totp: totpHandler,
|
||||
Payment: paymentHandler,
|
||||
PaymentWebhook: paymentWebhookHandler,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +127,8 @@ var ProviderSet = wire.NewSet(
|
||||
NewOpenAIGatewayHandler,
|
||||
NewTotpHandler,
|
||||
ProvideSettingHandler,
|
||||
NewPaymentHandler,
|
||||
NewPaymentWebhookHandler,
|
||||
|
||||
// Admin handlers
|
||||
admin.NewDashboardHandler,
|
||||
@@ -148,6 +156,7 @@ var ProviderSet = wire.NewSet(
|
||||
admin.NewAdminAPIKeyHandler,
|
||||
admin.NewScheduledTestHandler,
|
||||
admin.NewChannelHandler,
|
||||
admin.NewPaymentHandler,
|
||||
|
||||
// AdminHandlers and Handlers constructors
|
||||
ProvideAdminHandlers,
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Encrypt encrypts plaintext using AES-256-GCM with the given 32-byte key.
|
||||
// The output format is "iv:authTag:ciphertext" where each component is base64-encoded,
|
||||
// matching the Node.js crypto.ts format for cross-compatibility.
|
||||
func Encrypt(plaintext string, key []byte) (string, error) {
|
||||
if len(key) != 32 {
|
||||
return "", fmt.Errorf("encryption key must be 32 bytes, got %d", len(key))
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create AES cipher: %w", err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create GCM: %w", err)
|
||||
}
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize()) // 12 bytes for GCM
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return "", fmt.Errorf("generate nonce: %w", err)
|
||||
}
|
||||
|
||||
// Seal appends the ciphertext + auth tag
|
||||
sealed := gcm.Seal(nil, nonce, []byte(plaintext), nil)
|
||||
|
||||
// Split sealed into ciphertext and auth tag (last 16 bytes)
|
||||
tagSize := gcm.Overhead()
|
||||
ciphertext := sealed[:len(sealed)-tagSize]
|
||||
authTag := sealed[len(sealed)-tagSize:]
|
||||
|
||||
// Format: iv:authTag:ciphertext (all base64)
|
||||
return fmt.Sprintf("%s:%s:%s",
|
||||
base64.StdEncoding.EncodeToString(nonce),
|
||||
base64.StdEncoding.EncodeToString(authTag),
|
||||
base64.StdEncoding.EncodeToString(ciphertext),
|
||||
), nil
|
||||
}
|
||||
|
||||
// Decrypt decrypts a ciphertext string produced by Encrypt.
|
||||
// The input format is "iv:authTag:ciphertext" where each component is base64-encoded.
|
||||
func Decrypt(ciphertext string, key []byte) (string, error) {
|
||||
if len(key) != 32 {
|
||||
return "", fmt.Errorf("encryption key must be 32 bytes, got %d", len(key))
|
||||
}
|
||||
|
||||
parts := strings.SplitN(ciphertext, ":", 3)
|
||||
if len(parts) != 3 {
|
||||
return "", fmt.Errorf("invalid ciphertext format: expected iv:authTag:ciphertext")
|
||||
}
|
||||
|
||||
nonce, err := base64.StdEncoding.DecodeString(parts[0])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("decode IV: %w", err)
|
||||
}
|
||||
|
||||
authTag, err := base64.StdEncoding.DecodeString(parts[1])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("decode auth tag: %w", err)
|
||||
}
|
||||
|
||||
encrypted, err := base64.StdEncoding.DecodeString(parts[2])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("decode ciphertext: %w", err)
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create AES cipher: %w", err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create GCM: %w", err)
|
||||
}
|
||||
|
||||
// Reconstruct the sealed data: ciphertext + authTag
|
||||
sealed := append(encrypted, authTag...)
|
||||
|
||||
plaintext, err := gcm.Open(nil, nonce, sealed, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("decrypt: %w", err)
|
||||
}
|
||||
|
||||
return string(plaintext), nil
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func makeKey(t *testing.T) []byte {
|
||||
t.Helper()
|
||||
key := make([]byte, 32)
|
||||
if _, err := rand.Read(key); err != nil {
|
||||
t.Fatalf("generate random key: %v", err)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func TestEncryptDecryptRoundTrip(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := makeKey(t)
|
||||
|
||||
plaintexts := []string{
|
||||
"hello world",
|
||||
"short",
|
||||
"a longer string with special chars: !@#$%^&*()",
|
||||
`{"key":"value","num":42}`,
|
||||
"你好世界 unicode test 🎉",
|
||||
strings.Repeat("x", 10000),
|
||||
}
|
||||
|
||||
for _, pt := range plaintexts {
|
||||
encrypted, err := Encrypt(pt, key)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt(%q) error: %v", pt[:min(len(pt), 30)], err)
|
||||
}
|
||||
decrypted, err := Decrypt(encrypted, key)
|
||||
if err != nil {
|
||||
t.Fatalf("Decrypt error for plaintext %q: %v", pt[:min(len(pt), 30)], err)
|
||||
}
|
||||
if decrypted != pt {
|
||||
t.Fatalf("round-trip failed: got %q, want %q", decrypted[:min(len(decrypted), 30)], pt[:min(len(pt), 30)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptProducesDifferentCiphertexts(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := makeKey(t)
|
||||
|
||||
ct1, err := Encrypt("same plaintext", key)
|
||||
if err != nil {
|
||||
t.Fatalf("first Encrypt error: %v", err)
|
||||
}
|
||||
ct2, err := Encrypt("same plaintext", key)
|
||||
if err != nil {
|
||||
t.Fatalf("second Encrypt error: %v", err)
|
||||
}
|
||||
if ct1 == ct2 {
|
||||
t.Fatal("two encryptions of the same plaintext should produce different ciphertexts (random nonce)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecryptWithWrongKeyFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
key1 := makeKey(t)
|
||||
key2 := makeKey(t)
|
||||
|
||||
encrypted, err := Encrypt("secret data", key1)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt error: %v", err)
|
||||
}
|
||||
|
||||
_, err = Decrypt(encrypted, key2)
|
||||
if err == nil {
|
||||
t.Fatal("Decrypt with wrong key should fail, but got nil error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptRejectsInvalidKeyLength(t *testing.T) {
|
||||
t.Parallel()
|
||||
badKeys := [][]byte{
|
||||
nil,
|
||||
make([]byte, 0),
|
||||
make([]byte, 16),
|
||||
make([]byte, 31),
|
||||
make([]byte, 33),
|
||||
make([]byte, 64),
|
||||
}
|
||||
for _, key := range badKeys {
|
||||
_, err := Encrypt("test", key)
|
||||
if err == nil {
|
||||
t.Fatalf("Encrypt should reject key of length %d", len(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecryptRejectsInvalidKeyLength(t *testing.T) {
|
||||
t.Parallel()
|
||||
badKeys := [][]byte{
|
||||
nil,
|
||||
make([]byte, 16),
|
||||
make([]byte, 33),
|
||||
}
|
||||
for _, key := range badKeys {
|
||||
_, err := Decrypt("dummydata:dummydata:dummydata", key)
|
||||
if err == nil {
|
||||
t.Fatalf("Decrypt should reject key of length %d", len(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptEmptyPlaintext(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := makeKey(t)
|
||||
|
||||
encrypted, err := Encrypt("", key)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt empty plaintext error: %v", err)
|
||||
}
|
||||
decrypted, err := Decrypt(encrypted, key)
|
||||
if err != nil {
|
||||
t.Fatalf("Decrypt empty plaintext error: %v", err)
|
||||
}
|
||||
if decrypted != "" {
|
||||
t.Fatalf("expected empty string, got %q", decrypted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptDecryptUnicodeJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := makeKey(t)
|
||||
|
||||
jsonContent := `{"name":"测试用户","email":"test@example.com","balance":100.50}`
|
||||
encrypted, err := Encrypt(jsonContent, key)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt JSON error: %v", err)
|
||||
}
|
||||
decrypted, err := Decrypt(encrypted, key)
|
||||
if err != nil {
|
||||
t.Fatalf("Decrypt JSON error: %v", err)
|
||||
}
|
||||
if decrypted != jsonContent {
|
||||
t.Fatalf("JSON round-trip failed: got %q, want %q", decrypted, jsonContent)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecryptInvalidFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := makeKey(t)
|
||||
|
||||
invalidInputs := []string{
|
||||
"",
|
||||
"nodelimiter",
|
||||
"only:two",
|
||||
"invalid:base64:!!!",
|
||||
}
|
||||
for _, input := range invalidInputs {
|
||||
_, err := Decrypt(input, key)
|
||||
if err == nil {
|
||||
t.Fatalf("Decrypt(%q) should fail but got nil error", input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCiphertextFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := makeKey(t)
|
||||
|
||||
encrypted, err := Encrypt("test", key)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt error: %v", err)
|
||||
}
|
||||
|
||||
parts := strings.SplitN(encrypted, ":", 3)
|
||||
if len(parts) != 3 {
|
||||
t.Fatalf("ciphertext should have format iv:authTag:ciphertext, got %d parts", len(parts))
|
||||
}
|
||||
for i, part := range parts {
|
||||
if part == "" {
|
||||
t.Fatalf("ciphertext part %d is empty", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// CalculatePayAmount computes the total pay amount given a recharge amount and
|
||||
// fee rate (percentage). Fee = amount * feeRate / 100, rounded UP (away from zero)
|
||||
// to 2 decimal places. The returned string is formatted to exactly 2 decimal places.
|
||||
// If feeRate <= 0, the amount is returned as-is (formatted to 2 decimal places).
|
||||
func CalculatePayAmount(rechargeAmount float64, feeRate float64) string {
|
||||
amount := decimal.NewFromFloat(rechargeAmount)
|
||||
if feeRate <= 0 {
|
||||
return amount.StringFixed(2)
|
||||
}
|
||||
rate := decimal.NewFromFloat(feeRate)
|
||||
fee := amount.Mul(rate).Div(decimal.NewFromInt(100)).RoundUp(2)
|
||||
return amount.Add(fee).StringFixed(2)
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCalculatePayAmount(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
amount float64
|
||||
feeRate float64
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "zero fee rate returns same amount",
|
||||
amount: 100.00,
|
||||
feeRate: 0,
|
||||
expected: "100.00",
|
||||
},
|
||||
{
|
||||
name: "negative fee rate returns same amount",
|
||||
amount: 50.00,
|
||||
feeRate: -5,
|
||||
expected: "50.00",
|
||||
},
|
||||
{
|
||||
name: "1 percent fee rate",
|
||||
amount: 100.00,
|
||||
feeRate: 1,
|
||||
expected: "101.00",
|
||||
},
|
||||
{
|
||||
name: "5 percent fee on 200",
|
||||
amount: 200.00,
|
||||
feeRate: 5,
|
||||
expected: "210.00",
|
||||
},
|
||||
{
|
||||
name: "fee rounds UP to 2 decimal places",
|
||||
amount: 100.00,
|
||||
feeRate: 3,
|
||||
expected: "103.00",
|
||||
},
|
||||
{
|
||||
name: "fee rounds UP small remainder",
|
||||
amount: 10.00,
|
||||
feeRate: 3.33,
|
||||
expected: "10.34", // 10 * 3.33 / 100 = 0.333 -> round up -> 0.34
|
||||
},
|
||||
{
|
||||
name: "very small amount",
|
||||
amount: 0.01,
|
||||
feeRate: 1,
|
||||
expected: "0.02", // 0.01 * 1/100 = 0.0001 -> round up -> 0.01 -> total 0.02
|
||||
},
|
||||
{
|
||||
name: "large amount",
|
||||
amount: 99999.99,
|
||||
feeRate: 10,
|
||||
expected: "109999.99", // 99999.99 * 10/100 = 9999.999 -> round up -> 10000.00 -> total 109999.99
|
||||
},
|
||||
{
|
||||
name: "100 percent fee rate doubles amount",
|
||||
amount: 50.00,
|
||||
feeRate: 100,
|
||||
expected: "100.00",
|
||||
},
|
||||
{
|
||||
name: "precision 0.01 fee difference",
|
||||
amount: 100.00,
|
||||
feeRate: 1.01,
|
||||
expected: "101.01", // 100 * 1.01/100 = 1.01
|
||||
},
|
||||
{
|
||||
name: "precision 0.02 fee",
|
||||
amount: 100.00,
|
||||
feeRate: 1.02,
|
||||
expected: "101.02",
|
||||
},
|
||||
{
|
||||
name: "zero amount with positive fee",
|
||||
amount: 0,
|
||||
feeRate: 5,
|
||||
expected: "0.00",
|
||||
},
|
||||
{
|
||||
name: "fractional amount no fee",
|
||||
amount: 19.99,
|
||||
feeRate: 0,
|
||||
expected: "19.99",
|
||||
},
|
||||
{
|
||||
name: "fractional fee that causes rounding up",
|
||||
amount: 33.33,
|
||||
feeRate: 7.77,
|
||||
expected: "35.92", // 33.33 * 7.77 / 100 = 2.589741 -> round up -> 2.59 -> total 35.92
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got := CalculatePayAmount(tt.amount, tt.feeRate)
|
||||
if got != tt.expected {
|
||||
t.Fatalf("CalculatePayAmount(%v, %v) = %q, want %q", tt.amount, tt.feeRate, got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
dbent "github.com/Wei-Shaw/sub2api/ent"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentorder"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
)
|
||||
|
||||
// Strategy represents a load balancing strategy for provider instance selection.
|
||||
type Strategy string
|
||||
|
||||
const (
|
||||
StrategyRoundRobin Strategy = "round_robin"
|
||||
StrategyLeastAmount Strategy = "least_amount"
|
||||
)
|
||||
|
||||
// InstanceLimits holds per-channel limits for a provider instance (JSON).
|
||||
type InstanceLimits map[string]struct {
|
||||
DailyLimit float64 `json:"dailyLimit,omitempty"`
|
||||
SingleMin float64 `json:"singleMin,omitempty"`
|
||||
SingleMax float64 `json:"singleMax,omitempty"`
|
||||
}
|
||||
|
||||
// LoadBalancer selects a provider instance for a given payment type.
|
||||
type LoadBalancer interface {
|
||||
GetInstanceConfig(ctx context.Context, instanceID int64) (map[string]string, error)
|
||||
SelectInstance(ctx context.Context, providerKey string, paymentType PaymentType) (*InstanceSelection, error)
|
||||
}
|
||||
|
||||
// DefaultLoadBalancer implements LoadBalancer using database queries.
|
||||
type DefaultLoadBalancer struct {
|
||||
db *dbent.Client
|
||||
encryptionKey []byte
|
||||
counter atomic.Uint64
|
||||
}
|
||||
|
||||
// NewDefaultLoadBalancer creates a new load balancer.
|
||||
func NewDefaultLoadBalancer(db *dbent.Client, encryptionKey []byte) *DefaultLoadBalancer {
|
||||
return &DefaultLoadBalancer{db: db, encryptionKey: encryptionKey}
|
||||
}
|
||||
|
||||
// SelectInstance picks an enabled instance for the given provider key and payment type.
|
||||
func (lb *DefaultLoadBalancer) SelectInstance(ctx context.Context, providerKey string, paymentType PaymentType) (*InstanceSelection, error) {
|
||||
instances, err := lb.db.PaymentProviderInstance.Query().
|
||||
Where(
|
||||
paymentproviderinstance.ProviderKey(providerKey),
|
||||
paymentproviderinstance.Enabled(true),
|
||||
).
|
||||
Order(dbent.Asc(paymentproviderinstance.FieldSortOrder)).
|
||||
All(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query provider instances: %w", err)
|
||||
}
|
||||
|
||||
// Filter by supported types
|
||||
var candidates []*dbent.PaymentProviderInstance
|
||||
for _, inst := range instances {
|
||||
if inst.SupportedTypes == "" || containsType(inst.SupportedTypes, paymentType) {
|
||||
candidates = append(candidates, inst)
|
||||
}
|
||||
}
|
||||
|
||||
if len(candidates) == 0 {
|
||||
return nil, fmt.Errorf("no enabled instance for provider %s type %s", providerKey, paymentType)
|
||||
}
|
||||
|
||||
// Round-robin selection (default strategy)
|
||||
idx := lb.counter.Add(1) % uint64(len(candidates))
|
||||
selected := candidates[idx]
|
||||
|
||||
// Decrypt config
|
||||
config, err := lb.decryptConfig(selected.Config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decrypt instance %d config: %w", selected.ID, err)
|
||||
}
|
||||
|
||||
return &InstanceSelection{
|
||||
InstanceID: fmt.Sprintf("%d", selected.ID),
|
||||
Config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (lb *DefaultLoadBalancer) decryptConfig(encrypted string) (map[string]string, error) {
|
||||
plaintext, err := Decrypt(encrypted, lb.encryptionKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var config map[string]string
|
||||
if err := json.Unmarshal([]byte(plaintext), &config); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal config: %w", err)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetInstanceDailyAmount returns the total completed order amount for an instance today.
|
||||
func (lb *DefaultLoadBalancer) GetInstanceDailyAmount(ctx context.Context, instanceID string) (float64, error) {
|
||||
now := time.Now()
|
||||
todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
|
||||
var result []struct {
|
||||
Sum float64 `json:"sum"`
|
||||
}
|
||||
err := lb.db.PaymentOrder.Query().
|
||||
Where(
|
||||
paymentorder.ProviderInstanceID(instanceID),
|
||||
paymentorder.StatusIn("COMPLETED", "PAID", "RECHARGING"),
|
||||
paymentorder.PaidAtGTE(todayStart),
|
||||
).
|
||||
Aggregate(dbent.Sum(paymentorder.FieldPayAmount)).
|
||||
Scan(ctx, &result)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("query daily amount: %w", err)
|
||||
}
|
||||
if len(result) > 0 {
|
||||
return result[0].Sum, nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// containsType checks if a comma-separated list contains the given type.
|
||||
func containsType(supportedTypes string, target PaymentType) bool {
|
||||
for _, t := range strings.Split(supportedTypes, ",") {
|
||||
if strings.TrimSpace(t) == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetInstanceConfig decrypts and returns the configuration for a provider instance by ID.
|
||||
func (lb *DefaultLoadBalancer) GetInstanceConfig(ctx context.Context, instanceID int64) (map[string]string, error) {
|
||||
inst, err := lb.db.PaymentProviderInstance.Get(ctx, instanceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get instance %d: %w", instanceID, err)
|
||||
}
|
||||
return lb.decryptConfig(inst.Config)
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestContainsType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
supportedTypes string
|
||||
target PaymentType
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "exact match single type",
|
||||
supportedTypes: "alipay",
|
||||
target: "alipay",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "no match single type",
|
||||
supportedTypes: "wxpay",
|
||||
target: "alipay",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "match in comma-separated list",
|
||||
supportedTypes: "alipay,wxpay,stripe",
|
||||
target: "wxpay",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "first in comma-separated list",
|
||||
supportedTypes: "alipay,wxpay",
|
||||
target: "alipay",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "last in comma-separated list",
|
||||
supportedTypes: "alipay,wxpay,stripe",
|
||||
target: "stripe",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "no match in comma-separated list",
|
||||
supportedTypes: "alipay,wxpay",
|
||||
target: "stripe",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "empty target",
|
||||
supportedTypes: "alipay,wxpay",
|
||||
target: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "types with spaces are trimmed",
|
||||
supportedTypes: " alipay , wxpay ",
|
||||
target: "alipay",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "partial match should not succeed",
|
||||
supportedTypes: "alipay_direct",
|
||||
target: "alipay",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "empty supported types string matches nothing",
|
||||
supportedTypes: "",
|
||||
target: "alipay",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got := containsType(tt.supportedTypes, tt.target)
|
||||
if got != tt.expected {
|
||||
t.Fatalf("containsType(%q, %q) = %v, want %v", tt.supportedTypes, tt.target, got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
"github.com/smartwalle/alipay/v3"
|
||||
)
|
||||
|
||||
// Alipay implements payment.Provider and payment.CancelableProvider using the smartwalle/alipay SDK.
|
||||
type Alipay struct {
|
||||
instanceID string
|
||||
config map[string]string // appId, privateKey, publicKey (or alipayPublicKey), notifyUrl, returnUrl
|
||||
|
||||
mu sync.Mutex
|
||||
client *alipay.Client
|
||||
}
|
||||
|
||||
// NewAlipay creates a new Alipay provider instance.
|
||||
func NewAlipay(instanceID string, config map[string]string) (*Alipay, error) {
|
||||
required := []string{"appId", "privateKey"}
|
||||
for _, k := range required {
|
||||
if config[k] == "" {
|
||||
return nil, fmt.Errorf("alipay config missing required key: %s", k)
|
||||
}
|
||||
}
|
||||
return &Alipay{
|
||||
instanceID: instanceID,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *Alipay) getClient() (*alipay.Client, error) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if a.client != nil {
|
||||
return a.client, nil
|
||||
}
|
||||
client, err := alipay.New(a.config["appId"], a.config["privateKey"], true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay init client: %w", err)
|
||||
}
|
||||
pubKey := a.config["publicKey"]
|
||||
if pubKey == "" {
|
||||
pubKey = a.config["alipayPublicKey"]
|
||||
}
|
||||
if pubKey != "" {
|
||||
if err := client.LoadAliPayPublicKey(pubKey); err != nil {
|
||||
return nil, fmt.Errorf("alipay load public key: %w", err)
|
||||
}
|
||||
}
|
||||
a.client = client
|
||||
return a.client, nil
|
||||
}
|
||||
|
||||
func (a *Alipay) Name() string { return "Alipay" }
|
||||
func (a *Alipay) ProviderKey() string { return "alipay" }
|
||||
func (a *Alipay) SupportedTypes() []payment.PaymentType {
|
||||
return []payment.PaymentType{payment.TypeAlipayDirect}
|
||||
}
|
||||
|
||||
// CreatePayment creates an Alipay payment page URL.
|
||||
func (a *Alipay) CreatePayment(_ context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) {
|
||||
client, err := a.getClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
notifyURL := a.config["notifyUrl"]
|
||||
if req.NotifyURL != "" {
|
||||
notifyURL = req.NotifyURL
|
||||
}
|
||||
returnURL := a.config["returnUrl"]
|
||||
if req.ReturnURL != "" {
|
||||
returnURL = req.ReturnURL
|
||||
}
|
||||
|
||||
if req.IsMobile {
|
||||
return a.createWapPayment(client, req, notifyURL, returnURL)
|
||||
}
|
||||
return a.createPagePayment(client, req, notifyURL, returnURL)
|
||||
}
|
||||
|
||||
func (a *Alipay) createPagePayment(client *alipay.Client, req payment.CreatePaymentRequest, notifyURL, returnURL string) (*payment.CreatePaymentResponse, error) {
|
||||
param := alipay.TradePagePay{}
|
||||
param.OutTradeNo = req.OrderID
|
||||
param.TotalAmount = req.Amount
|
||||
param.Subject = req.Subject
|
||||
param.ProductCode = "FAST_INSTANT_TRADE_PAY"
|
||||
param.NotifyURL = notifyURL
|
||||
param.ReturnURL = returnURL
|
||||
|
||||
payURL, err := client.TradePagePay(param)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay TradePagePay: %w", err)
|
||||
}
|
||||
|
||||
return &payment.CreatePaymentResponse{
|
||||
TradeNo: req.OrderID,
|
||||
PayURL: payURL.String(),
|
||||
QRCode: payURL.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *Alipay) createWapPayment(client *alipay.Client, req payment.CreatePaymentRequest, notifyURL, returnURL string) (*payment.CreatePaymentResponse, error) {
|
||||
param := alipay.TradeWapPay{}
|
||||
param.OutTradeNo = req.OrderID
|
||||
param.TotalAmount = req.Amount
|
||||
param.Subject = req.Subject
|
||||
param.ProductCode = "QUICK_WAP_WAY"
|
||||
param.NotifyURL = notifyURL
|
||||
param.ReturnURL = returnURL
|
||||
|
||||
payURL, err := client.TradeWapPay(param)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay TradeWapPay: %w", err)
|
||||
}
|
||||
|
||||
return &payment.CreatePaymentResponse{
|
||||
TradeNo: req.OrderID,
|
||||
PayURL: payURL.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// QueryOrder queries the trade status via Alipay.
|
||||
func (a *Alipay) QueryOrder(ctx context.Context, tradeNo string) (*payment.QueryOrderResponse, error) {
|
||||
client, err := a.getClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, err := client.TradeQuery(ctx, alipay.TradeQuery{OutTradeNo: tradeNo})
|
||||
if err != nil {
|
||||
if isTradeNotExist(err) {
|
||||
return &payment.QueryOrderResponse{
|
||||
TradeNo: tradeNo,
|
||||
Status: "pending",
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("alipay TradeQuery: %w", err)
|
||||
}
|
||||
|
||||
status := "pending"
|
||||
switch result.TradeStatus {
|
||||
case alipay.TradeStatusSuccess, alipay.TradeStatusFinished:
|
||||
status = "paid"
|
||||
case alipay.TradeStatusClosed:
|
||||
status = "failed"
|
||||
}
|
||||
|
||||
amount, _ := strconv.ParseFloat(result.TotalAmount, 64)
|
||||
|
||||
return &payment.QueryOrderResponse{
|
||||
TradeNo: result.TradeNo,
|
||||
Status: status,
|
||||
Amount: amount,
|
||||
PaidAt: result.SendPayDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// VerifyNotification decodes and verifies an Alipay async notification.
|
||||
func (a *Alipay) VerifyNotification(ctx context.Context, rawBody string, _ map[string]string) (*payment.PaymentNotification, error) {
|
||||
client, err := a.getClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
values, err := url.ParseQuery(rawBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay parse notification: %w", err)
|
||||
}
|
||||
|
||||
notification, err := client.DecodeNotification(ctx, values)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay verify notification: %w", err)
|
||||
}
|
||||
|
||||
status := "failed"
|
||||
if notification.TradeStatus == alipay.TradeStatusSuccess || notification.TradeStatus == alipay.TradeStatusFinished {
|
||||
status = "success"
|
||||
}
|
||||
|
||||
amount, _ := strconv.ParseFloat(notification.TotalAmount, 64)
|
||||
|
||||
return &payment.PaymentNotification{
|
||||
TradeNo: notification.TradeNo,
|
||||
OrderID: notification.OutTradeNo,
|
||||
Amount: amount,
|
||||
Status: status,
|
||||
RawData: rawBody,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Refund requests a refund through Alipay.
|
||||
func (a *Alipay) Refund(ctx context.Context, req payment.RefundRequest) (*payment.RefundResponse, error) {
|
||||
client, err := a.getClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, err := client.TradeRefund(ctx, alipay.TradeRefund{
|
||||
OutTradeNo: req.OrderID,
|
||||
RefundAmount: req.Amount,
|
||||
RefundReason: req.Reason,
|
||||
OutRequestNo: fmt.Sprintf("%s-refund-%d", req.OrderID, time.Now().UnixNano()),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("alipay TradeRefund: %w", err)
|
||||
}
|
||||
|
||||
refundStatus := "pending"
|
||||
if result.FundChange == "Y" {
|
||||
refundStatus = "success"
|
||||
}
|
||||
|
||||
refundID := result.TradeNo
|
||||
if refundID == "" {
|
||||
refundID = req.OrderID + "-refund"
|
||||
}
|
||||
|
||||
return &payment.RefundResponse{
|
||||
RefundID: refundID,
|
||||
Status: refundStatus,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CancelPayment closes a pending trade on Alipay.
|
||||
func (a *Alipay) CancelPayment(ctx context.Context, tradeNo string) error {
|
||||
client, err := a.getClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.TradeClose(ctx, alipay.TradeClose{OutTradeNo: tradeNo})
|
||||
if err != nil {
|
||||
if isTradeNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("alipay TradeClose: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isTradeNotExist(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(err.Error(), "ACQ.TRADE_NOT_EXIST")
|
||||
}
|
||||
|
||||
// Ensure interface compliance.
|
||||
var (
|
||||
_ payment.Provider = (*Alipay)(nil)
|
||||
_ payment.CancelableProvider = (*Alipay)(nil)
|
||||
)
|
||||
@@ -0,0 +1,211 @@
|
||||
// Package provider contains concrete payment provider implementations.
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
)
|
||||
|
||||
// EasyPay implements payment.Provider for the EasyPay aggregation platform.
|
||||
type EasyPay struct {
|
||||
instanceID string
|
||||
config map[string]string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// NewEasyPay creates a new EasyPay provider.
|
||||
// config keys: pid, pkey, apiBase, notifyUrl, returnUrl, cid, cidAlipay, cidWxpay
|
||||
func NewEasyPay(instanceID string, config map[string]string) (*EasyPay, error) {
|
||||
for _, k := range []string{"pid", "pkey", "apiBase", "notifyUrl", "returnUrl"} {
|
||||
if config[k] == "" {
|
||||
return nil, fmt.Errorf("easypay config missing required key: %s", k)
|
||||
}
|
||||
}
|
||||
return &EasyPay{
|
||||
instanceID: instanceID,
|
||||
config: config,
|
||||
httpClient: &http.Client{Timeout: 10 * time.Second},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *EasyPay) Name() string { return "EasyPay" }
|
||||
func (e *EasyPay) ProviderKey() string { return "easypay" }
|
||||
func (e *EasyPay) SupportedTypes() []payment.PaymentType {
|
||||
return []payment.PaymentType{payment.TypeAlipay, payment.TypeWxpay}
|
||||
}
|
||||
|
||||
func (e *EasyPay) CreatePayment(ctx context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) {
|
||||
params := map[string]string{
|
||||
"pid": e.config["pid"], "type": req.PaymentType,
|
||||
"out_trade_no": req.OrderID, "notify_url": req.NotifyURL,
|
||||
"return_url": req.ReturnURL, "name": req.Subject,
|
||||
"money": req.Amount, "clientip": req.ClientIP,
|
||||
}
|
||||
if cid := e.resolveCID(req.PaymentType); cid != "" {
|
||||
params["cid"] = cid
|
||||
}
|
||||
if req.IsMobile {
|
||||
params["device"] = "mobile"
|
||||
}
|
||||
params["sign"] = easyPaySign(params, e.config["pkey"])
|
||||
params["sign_type"] = "MD5"
|
||||
|
||||
body, err := e.post(ctx, e.config["apiBase"]+"/mapi.php", params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("easypay create: %w", err)
|
||||
}
|
||||
var resp struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
TradeNo string `json:"trade_no"`
|
||||
PayURL string `json:"payurl"`
|
||||
QRCode string `json:"qrcode"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &resp); err != nil {
|
||||
return nil, fmt.Errorf("easypay parse: %w", err)
|
||||
}
|
||||
if resp.Code != 1 {
|
||||
return nil, fmt.Errorf("easypay error: %s", resp.Msg)
|
||||
}
|
||||
return &payment.CreatePaymentResponse{TradeNo: resp.TradeNo, PayURL: resp.PayURL, QRCode: resp.QRCode}, nil
|
||||
}
|
||||
|
||||
func (e *EasyPay) QueryOrder(ctx context.Context, tradeNo string) (*payment.QueryOrderResponse, error) {
|
||||
params := map[string]string{
|
||||
"act": "order", "pid": e.config["pid"],
|
||||
"key": e.config["pkey"], "out_trade_no": tradeNo,
|
||||
}
|
||||
body, err := e.post(ctx, e.config["apiBase"]+"/api.php", params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("easypay query: %w", err)
|
||||
}
|
||||
var resp struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &resp); err != nil {
|
||||
return nil, fmt.Errorf("easypay parse query: %w", err)
|
||||
}
|
||||
status := "pending"
|
||||
if resp.Status == 1 {
|
||||
status = "paid"
|
||||
}
|
||||
return &payment.QueryOrderResponse{TradeNo: tradeNo, Status: status}, nil
|
||||
}
|
||||
|
||||
func (e *EasyPay) VerifyNotification(_ context.Context, rawBody string, _ map[string]string) (*payment.PaymentNotification, error) {
|
||||
values, err := url.ParseQuery(rawBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse notify: %w", err)
|
||||
}
|
||||
params := make(map[string]string)
|
||||
for k := range values {
|
||||
params[k] = values.Get(k)
|
||||
}
|
||||
sign := params["sign"]
|
||||
if sign == "" {
|
||||
return nil, fmt.Errorf("missing sign")
|
||||
}
|
||||
if !easyPayVerifySign(params, e.config["pkey"], sign) {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
}
|
||||
status := "failed"
|
||||
if params["trade_status"] == "TRADE_SUCCESS" {
|
||||
status = "success"
|
||||
}
|
||||
return &payment.PaymentNotification{
|
||||
TradeNo: params["trade_no"], OrderID: params["out_trade_no"],
|
||||
Status: status, RawData: rawBody,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *EasyPay) Refund(ctx context.Context, req payment.RefundRequest) (*payment.RefundResponse, error) {
|
||||
params := map[string]string{
|
||||
"pid": e.config["pid"], "key": e.config["pkey"],
|
||||
"trade_no": req.TradeNo, "out_trade_no": req.OrderID, "money": req.Amount,
|
||||
}
|
||||
body, err := e.post(ctx, e.config["apiBase"]+"/api.php?act=refund", params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("easypay refund: %w", err)
|
||||
}
|
||||
var resp struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &resp); err != nil {
|
||||
return nil, fmt.Errorf("easypay parse refund: %w", err)
|
||||
}
|
||||
if resp.Code != 1 {
|
||||
return nil, fmt.Errorf("easypay refund failed: %s", resp.Msg)
|
||||
}
|
||||
return &payment.RefundResponse{RefundID: req.TradeNo, Status: "success"}, nil
|
||||
}
|
||||
|
||||
func (e *EasyPay) resolveCID(paymentType string) string {
|
||||
if strings.HasPrefix(paymentType, "alipay") {
|
||||
if v := e.config["cidAlipay"]; v != "" {
|
||||
return v
|
||||
}
|
||||
return e.config["cid"]
|
||||
}
|
||||
if v := e.config["cidWxpay"]; v != "" {
|
||||
return v
|
||||
}
|
||||
return e.config["cid"]
|
||||
}
|
||||
|
||||
func (e *EasyPay) post(ctx context.Context, endpoint string, params map[string]string) ([]byte, error) {
|
||||
form := url.Values{}
|
||||
for k, v := range params {
|
||||
form.Set(k, v)
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, strings.NewReader(form.Encode()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
resp, err := e.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
func easyPaySign(params map[string]string, pkey string) string {
|
||||
keys := make([]string, 0, len(params))
|
||||
for k, v := range params {
|
||||
if k == "sign" || k == "sign_type" || v == "" {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
var buf strings.Builder
|
||||
for i, k := range keys {
|
||||
if i > 0 {
|
||||
buf.WriteByte('&')
|
||||
}
|
||||
buf.WriteString(k + "=" + params[k])
|
||||
}
|
||||
buf.WriteString(pkey)
|
||||
hash := md5.Sum([]byte(buf.String()))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
func easyPayVerifySign(params map[string]string, pkey string, sign string) bool {
|
||||
return hmac.Equal([]byte(easyPaySign(params, pkey)), []byte(sign))
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEasyPaySignConsistentOutput(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "alipay",
|
||||
"out_trade_no": "ORDER123",
|
||||
"name": "Test Product",
|
||||
"money": "10.00",
|
||||
}
|
||||
pkey := "test_secret_key"
|
||||
|
||||
sign1 := easyPaySign(params, pkey)
|
||||
sign2 := easyPaySign(params, pkey)
|
||||
if sign1 != sign2 {
|
||||
t.Fatalf("easyPaySign should be deterministic: %q != %q", sign1, sign2)
|
||||
}
|
||||
if len(sign1) != 32 {
|
||||
t.Fatalf("MD5 hex should be 32 chars, got %d", len(sign1))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEasyPaySignExcludesSignAndSignType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pkey := "my_key"
|
||||
base := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "alipay",
|
||||
}
|
||||
withSign := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "alipay",
|
||||
"sign": "should_be_ignored",
|
||||
"sign_type": "MD5",
|
||||
}
|
||||
|
||||
signBase := easyPaySign(base, pkey)
|
||||
signWithExtra := easyPaySign(withSign, pkey)
|
||||
|
||||
if signBase != signWithExtra {
|
||||
t.Fatalf("sign and sign_type should be excluded: base=%q, withExtra=%q", signBase, signWithExtra)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEasyPaySignExcludesEmptyValues(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pkey := "key123"
|
||||
base := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "alipay",
|
||||
}
|
||||
withEmpty := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "alipay",
|
||||
"device": "",
|
||||
"clientip": "",
|
||||
}
|
||||
|
||||
signBase := easyPaySign(base, pkey)
|
||||
signWithEmpty := easyPaySign(withEmpty, pkey)
|
||||
|
||||
if signBase != signWithEmpty {
|
||||
t.Fatalf("empty values should be excluded: base=%q, withEmpty=%q", signBase, signWithEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEasyPayVerifySignValid(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "alipay",
|
||||
"out_trade_no": "ORDER456",
|
||||
"money": "25.00",
|
||||
}
|
||||
pkey := "secret"
|
||||
|
||||
sign := easyPaySign(params, pkey)
|
||||
|
||||
// Add sign to params (as would come in a real callback)
|
||||
params["sign"] = sign
|
||||
params["sign_type"] = "MD5"
|
||||
|
||||
if !easyPayVerifySign(params, pkey, sign) {
|
||||
t.Fatal("easyPayVerifySign should return true for a valid signature")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEasyPayVerifySignTampered(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "alipay",
|
||||
"out_trade_no": "ORDER789",
|
||||
"money": "50.00",
|
||||
}
|
||||
pkey := "secret"
|
||||
|
||||
sign := easyPaySign(params, pkey)
|
||||
|
||||
// Tamper with the amount
|
||||
params["money"] = "99.99"
|
||||
|
||||
if easyPayVerifySign(params, pkey, sign) {
|
||||
t.Fatal("easyPayVerifySign should return false for tampered params")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEasyPayVerifySignWrongKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "wxpay",
|
||||
}
|
||||
|
||||
sign := easyPaySign(params, "correct_key")
|
||||
|
||||
if easyPayVerifySign(params, "wrong_key", sign) {
|
||||
t.Fatal("easyPayVerifySign should return false with wrong key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEasyPaySignEmptyParams(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
sign := easyPaySign(map[string]string{}, "key123")
|
||||
if sign == "" {
|
||||
t.Fatal("easyPaySign with empty params should still produce a hash")
|
||||
}
|
||||
if len(sign) != 32 {
|
||||
t.Fatalf("MD5 hex should be 32 chars, got %d", len(sign))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEasyPaySignSortOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pkey := "test_key"
|
||||
params1 := map[string]string{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
"c": "3",
|
||||
}
|
||||
params2 := map[string]string{
|
||||
"c": "3",
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
}
|
||||
|
||||
sign1 := easyPaySign(params1, pkey)
|
||||
sign2 := easyPaySign(params2, pkey)
|
||||
|
||||
if sign1 != sign2 {
|
||||
t.Fatalf("easyPaySign should be order-independent: %q != %q", sign1, sign2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEasyPayVerifySignWrongSignValue(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
params := map[string]string{
|
||||
"pid": "1001",
|
||||
"type": "alipay",
|
||||
}
|
||||
pkey := "key"
|
||||
|
||||
if easyPayVerifySign(params, pkey, "00000000000000000000000000000000") {
|
||||
t.Fatal("easyPayVerifySign should return false for an incorrect sign value")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
)
|
||||
|
||||
// CreateProvider creates a Provider from a provider key, instance ID and decrypted config.
|
||||
func CreateProvider(providerKey string, instanceID string, config map[string]string) (payment.Provider, error) {
|
||||
switch providerKey {
|
||||
case "easypay":
|
||||
return NewEasyPay(instanceID, config)
|
||||
case "alipay":
|
||||
return NewAlipay(instanceID, config)
|
||||
case "wxpay":
|
||||
return NewWxpay(instanceID, config)
|
||||
case "stripe":
|
||||
return NewStripe(instanceID, config)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown provider key: %s", providerKey)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
stripe "github.com/stripe/stripe-go/v82"
|
||||
"github.com/stripe/stripe-go/v82/client"
|
||||
"github.com/stripe/stripe-go/v82/webhook"
|
||||
)
|
||||
|
||||
// Stripe implements the payment.CancelableProvider interface for Stripe payments.
|
||||
type Stripe struct {
|
||||
instanceID string
|
||||
config map[string]string
|
||||
|
||||
mu sync.Mutex
|
||||
initialized bool
|
||||
api *client.API
|
||||
}
|
||||
|
||||
// NewStripe creates a new Stripe provider instance.
|
||||
func NewStripe(instanceID string, config map[string]string) (*Stripe, error) {
|
||||
if config["secretKey"] == "" {
|
||||
return nil, fmt.Errorf("stripe config missing required key: secretKey")
|
||||
}
|
||||
return &Stripe{
|
||||
instanceID: instanceID,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Stripe) ensureInit() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if !s.initialized {
|
||||
s.api = &client.API{}
|
||||
s.api.Init(s.config["secretKey"], nil)
|
||||
s.initialized = true
|
||||
}
|
||||
}
|
||||
|
||||
// GetPublishableKey returns the publishable key for frontend use.
|
||||
func (s *Stripe) GetPublishableKey() string {
|
||||
return s.config["publishableKey"]
|
||||
}
|
||||
|
||||
func (s *Stripe) Name() string { return "Stripe" }
|
||||
func (s *Stripe) ProviderKey() string { return "stripe" }
|
||||
func (s *Stripe) SupportedTypes() []payment.PaymentType {
|
||||
return []payment.PaymentType{payment.TypeStripe}
|
||||
}
|
||||
|
||||
// yuanToCents converts a CNY yuan string to cents (int64).
|
||||
func yuanToCents(amountStr string) (int64, error) {
|
||||
amount, err := strconv.ParseFloat(amountStr, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid amount: %s", amountStr)
|
||||
}
|
||||
return int64(math.Round(amount * 100)), nil
|
||||
}
|
||||
|
||||
// CreatePayment creates a Stripe PaymentIntent.
|
||||
func (s *Stripe) CreatePayment(ctx context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) {
|
||||
s.ensureInit()
|
||||
|
||||
amountInCents, err := yuanToCents(req.Amount)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stripe create payment: %w", err)
|
||||
}
|
||||
|
||||
params := &stripe.PaymentIntentParams{
|
||||
Amount: stripe.Int64(amountInCents),
|
||||
Currency: stripe.String("cny"),
|
||||
AutomaticPaymentMethods: &stripe.PaymentIntentAutomaticPaymentMethodsParams{
|
||||
Enabled: stripe.Bool(true),
|
||||
},
|
||||
Description: stripe.String(req.Subject),
|
||||
Metadata: map[string]string{"orderId": req.OrderID},
|
||||
}
|
||||
params.SetIdempotencyKey(fmt.Sprintf("pi-%s", req.OrderID))
|
||||
params.Context = ctx
|
||||
|
||||
pi, err := s.api.PaymentIntents.New(params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stripe create payment: %w", err)
|
||||
}
|
||||
|
||||
return &payment.CreatePaymentResponse{
|
||||
TradeNo: pi.ID,
|
||||
ClientSecret: pi.ClientSecret,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// QueryOrder retrieves a PaymentIntent by ID.
|
||||
func (s *Stripe) QueryOrder(ctx context.Context, tradeNo string) (*payment.QueryOrderResponse, error) {
|
||||
s.ensureInit()
|
||||
|
||||
params := &stripe.PaymentIntentParams{}
|
||||
params.Context = ctx
|
||||
|
||||
pi, err := s.api.PaymentIntents.Get(tradeNo, params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stripe query order: %w", err)
|
||||
}
|
||||
|
||||
status := "pending"
|
||||
switch pi.Status {
|
||||
case stripe.PaymentIntentStatusSucceeded:
|
||||
status = "paid"
|
||||
case stripe.PaymentIntentStatusCanceled:
|
||||
status = "failed"
|
||||
}
|
||||
|
||||
return &payment.QueryOrderResponse{
|
||||
TradeNo: pi.ID,
|
||||
Status: status,
|
||||
Amount: float64(pi.Amount) / 100,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// VerifyNotification verifies a Stripe webhook event.
|
||||
func (s *Stripe) VerifyNotification(_ context.Context, rawBody string, headers map[string]string) (*payment.PaymentNotification, error) {
|
||||
s.ensureInit()
|
||||
|
||||
webhookSecret := s.config["webhookSecret"]
|
||||
if webhookSecret == "" {
|
||||
return nil, fmt.Errorf("stripe webhookSecret not configured")
|
||||
}
|
||||
|
||||
sig := headers["stripe-signature"]
|
||||
if sig == "" {
|
||||
return nil, fmt.Errorf("stripe notification missing stripe-signature header")
|
||||
}
|
||||
|
||||
event, err := webhook.ConstructEvent([]byte(rawBody), sig, webhookSecret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stripe verify notification: %w", err)
|
||||
}
|
||||
|
||||
switch event.Type {
|
||||
case "payment_intent.succeeded":
|
||||
return parseStripePaymentIntent(&event, "success", rawBody)
|
||||
case "payment_intent.payment_failed":
|
||||
return parseStripePaymentIntent(&event, "failed", rawBody)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func parseStripePaymentIntent(event *stripe.Event, status string, rawBody string) (*payment.PaymentNotification, error) {
|
||||
var pi stripe.PaymentIntent
|
||||
if err := json.Unmarshal(event.Data.Raw, &pi); err != nil {
|
||||
return nil, fmt.Errorf("stripe parse payment_intent: %w", err)
|
||||
}
|
||||
return &payment.PaymentNotification{
|
||||
TradeNo: pi.ID,
|
||||
OrderID: pi.Metadata["orderId"],
|
||||
Amount: float64(pi.Amount) / 100,
|
||||
Status: status,
|
||||
RawData: rawBody,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Refund creates a Stripe refund.
|
||||
func (s *Stripe) Refund(ctx context.Context, req payment.RefundRequest) (*payment.RefundResponse, error) {
|
||||
s.ensureInit()
|
||||
|
||||
amountInCents, err := yuanToCents(req.Amount)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stripe refund: %w", err)
|
||||
}
|
||||
|
||||
params := &stripe.RefundParams{
|
||||
PaymentIntent: stripe.String(req.TradeNo),
|
||||
Amount: stripe.Int64(amountInCents),
|
||||
Reason: stripe.String(string(stripe.RefundReasonRequestedByCustomer)),
|
||||
}
|
||||
params.Context = ctx
|
||||
|
||||
r, err := s.api.Refunds.New(params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stripe refund: %w", err)
|
||||
}
|
||||
|
||||
refundStatus := "pending"
|
||||
if r.Status == stripe.RefundStatusSucceeded {
|
||||
refundStatus = "success"
|
||||
}
|
||||
|
||||
return &payment.RefundResponse{
|
||||
RefundID: r.ID,
|
||||
Status: refundStatus,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CancelPayment cancels a pending PaymentIntent.
|
||||
func (s *Stripe) CancelPayment(ctx context.Context, tradeNo string) error {
|
||||
s.ensureInit()
|
||||
|
||||
params := &stripe.PaymentIntentCancelParams{}
|
||||
params.Context = ctx
|
||||
|
||||
_, err := s.api.PaymentIntents.Cancel(tradeNo, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stripe cancel payment: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ensure interface compliance.
|
||||
var (
|
||||
_ payment.Provider = (*Stripe)(nil)
|
||||
_ payment.CancelableProvider = (*Stripe)(nil)
|
||||
)
|
||||
@@ -0,0 +1,312 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/h5"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
||||
)
|
||||
|
||||
type Wxpay struct {
|
||||
instanceID string
|
||||
config map[string]string
|
||||
mu sync.Mutex
|
||||
coreClient *core.Client
|
||||
notifyHandler *notify.Handler
|
||||
}
|
||||
|
||||
func NewWxpay(instanceID string, config map[string]string) (*Wxpay, error) {
|
||||
required := []string{"appId", "mchId", "privateKey", "apiV3Key", "publicKey", "publicKeyId"}
|
||||
for _, k := range required {
|
||||
if config[k] == "" {
|
||||
return nil, fmt.Errorf("wxpay config missing required key: %s", k)
|
||||
}
|
||||
}
|
||||
if len(config["apiV3Key"]) != 32 {
|
||||
return nil, fmt.Errorf("wxpay apiV3Key must be exactly 32 bytes, got %d", len(config["apiV3Key"]))
|
||||
}
|
||||
return &Wxpay{instanceID: instanceID, config: config}, nil
|
||||
}
|
||||
|
||||
func (w *Wxpay) Name() string { return "Wxpay" }
|
||||
func (w *Wxpay) ProviderKey() string { return "wxpay" }
|
||||
func (w *Wxpay) SupportedTypes() []payment.PaymentType {
|
||||
return []payment.PaymentType{payment.TypeWxpayDirect}
|
||||
}
|
||||
|
||||
func formatPEM(key, keyType string) string {
|
||||
key = strings.TrimSpace(key)
|
||||
if strings.HasPrefix(key, "-----BEGIN") {
|
||||
return key
|
||||
}
|
||||
return fmt.Sprintf("-----BEGIN %s-----\n%s\n-----END %s-----", keyType, key, keyType)
|
||||
}
|
||||
|
||||
func (w *Wxpay) ensureClient() (*core.Client, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if w.coreClient != nil {
|
||||
return w.coreClient, nil
|
||||
}
|
||||
privateKey, err := utils.LoadPrivateKey(formatPEM(w.config["privateKey"], "PRIVATE KEY"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay load private key: %w", err)
|
||||
}
|
||||
publicKey, err := utils.LoadPublicKey(formatPEM(w.config["publicKey"], "PUBLIC KEY"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay load public key: %w", err)
|
||||
}
|
||||
certSerial := w.config["certSerial"]
|
||||
if certSerial == "" {
|
||||
certSerial = w.config["publicKeyId"]
|
||||
}
|
||||
verifier := verifiers.NewSHA256WithRSAPubkeyVerifier(w.config["publicKeyId"], *publicKey)
|
||||
client, err := core.NewClient(context.Background(),
|
||||
option.WithMerchantCredential(w.config["mchId"], certSerial, privateKey),
|
||||
option.WithVerifier(verifier))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay init client: %w", err)
|
||||
}
|
||||
handler, err := notify.NewRSANotifyHandler(w.config["apiV3Key"], verifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay init notify handler: %w", err)
|
||||
}
|
||||
w.notifyHandler = handler
|
||||
w.coreClient = client
|
||||
return w.coreClient, nil
|
||||
}
|
||||
|
||||
func yuanToFen(s string) (int64, error) {
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid amount: %s", s)
|
||||
}
|
||||
return int64(math.Round(f * 100)), nil
|
||||
}
|
||||
|
||||
func (w *Wxpay) CreatePayment(ctx context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) {
|
||||
client, err := w.ensureClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
notifyURL := w.config["notifyUrl"]
|
||||
if notifyURL == "" {
|
||||
notifyURL = req.NotifyURL
|
||||
}
|
||||
if notifyURL == "" {
|
||||
return nil, fmt.Errorf("wxpay notifyUrl is required")
|
||||
}
|
||||
totalFen, err := yuanToFen(req.Amount)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay create payment: %w", err)
|
||||
}
|
||||
if req.IsMobile && req.ClientIP != "" {
|
||||
resp, err := w.createH5Order(ctx, client, req, notifyURL, totalFen)
|
||||
if err == nil {
|
||||
return resp, nil
|
||||
}
|
||||
if !strings.Contains(err.Error(), "NO_AUTH") {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return w.createNativeOrder(ctx, client, req, notifyURL, totalFen)
|
||||
}
|
||||
|
||||
func (w *Wxpay) createNativeOrder(ctx context.Context, c *core.Client, req payment.CreatePaymentRequest, notifyURL string, totalFen int64) (*payment.CreatePaymentResponse, error) {
|
||||
svc := native.NativeApiService{Client: c}
|
||||
cur := "CNY"
|
||||
resp, _, err := svc.Prepay(ctx, native.PrepayRequest{
|
||||
Appid: core.String(w.config["appId"]), Mchid: core.String(w.config["mchId"]),
|
||||
Description: core.String(req.Subject), OutTradeNo: core.String(req.OrderID),
|
||||
NotifyUrl: core.String(notifyURL),
|
||||
Amount: &native.Amount{Total: core.Int64(totalFen), Currency: &cur},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay native prepay: %w", err)
|
||||
}
|
||||
codeURL := ""
|
||||
if resp.CodeUrl != nil {
|
||||
codeURL = *resp.CodeUrl
|
||||
}
|
||||
return &payment.CreatePaymentResponse{TradeNo: req.OrderID, QRCode: codeURL}, nil
|
||||
}
|
||||
|
||||
func (w *Wxpay) createH5Order(ctx context.Context, c *core.Client, req payment.CreatePaymentRequest, notifyURL string, totalFen int64) (*payment.CreatePaymentResponse, error) {
|
||||
svc := h5.H5ApiService{Client: c}
|
||||
cur := "CNY"
|
||||
tp := "Wap"
|
||||
resp, _, err := svc.Prepay(ctx, h5.PrepayRequest{
|
||||
Appid: core.String(w.config["appId"]), Mchid: core.String(w.config["mchId"]),
|
||||
Description: core.String(req.Subject), OutTradeNo: core.String(req.OrderID),
|
||||
NotifyUrl: core.String(notifyURL),
|
||||
Amount: &h5.Amount{Total: core.Int64(totalFen), Currency: &cur},
|
||||
SceneInfo: &h5.SceneInfo{PayerClientIp: core.String(req.ClientIP), H5Info: &h5.H5Info{Type: &tp}},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay h5 prepay: %w", err)
|
||||
}
|
||||
h5URL := ""
|
||||
if resp.H5Url != nil {
|
||||
h5URL = *resp.H5Url
|
||||
}
|
||||
return &payment.CreatePaymentResponse{TradeNo: req.OrderID, PayURL: h5URL}, nil
|
||||
}
|
||||
|
||||
func wxSV(s *string) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return *s
|
||||
}
|
||||
|
||||
func mapWxState(s string) string {
|
||||
switch s {
|
||||
case "SUCCESS":
|
||||
return "paid"
|
||||
case "REFUND":
|
||||
return "refunded"
|
||||
case "CLOSED", "PAYERROR":
|
||||
return "failed"
|
||||
default:
|
||||
return "pending"
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Wxpay) QueryOrder(ctx context.Context, tradeNo string) (*payment.QueryOrderResponse, error) {
|
||||
c, err := w.ensureClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
svc := native.NativeApiService{Client: c}
|
||||
tx, _, err := svc.QueryOrderByOutTradeNo(ctx, native.QueryOrderByOutTradeNoRequest{
|
||||
OutTradeNo: core.String(tradeNo), Mchid: core.String(w.config["mchId"]),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay query order: %w", err)
|
||||
}
|
||||
var amt float64
|
||||
if tx.Amount != nil && tx.Amount.Total != nil {
|
||||
amt = float64(*tx.Amount.Total) / 100
|
||||
}
|
||||
id := tradeNo
|
||||
if tx.TransactionId != nil {
|
||||
id = *tx.TransactionId
|
||||
}
|
||||
pa := ""
|
||||
if tx.SuccessTime != nil {
|
||||
pa = *tx.SuccessTime
|
||||
}
|
||||
return &payment.QueryOrderResponse{TradeNo: id, Status: mapWxState(wxSV(tx.TradeState)), Amount: amt, PaidAt: pa}, nil
|
||||
}
|
||||
|
||||
func (w *Wxpay) VerifyNotification(ctx context.Context, rawBody string, headers map[string]string) (*payment.PaymentNotification, error) {
|
||||
if _, err := w.ensureClient(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := http.NewRequestWithContext(ctx, http.MethodPost, "/", io.NopCloser(bytes.NewBufferString(rawBody)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay construct request: %w", err)
|
||||
}
|
||||
for k, v := range headers {
|
||||
r.Header.Set(k, v)
|
||||
}
|
||||
var tx payments.Transaction
|
||||
nr, err := w.notifyHandler.ParseNotifyRequest(ctx, r, &tx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay verify notification: %w", err)
|
||||
}
|
||||
if nr.EventType != "TRANSACTION.SUCCESS" {
|
||||
return nil, nil
|
||||
}
|
||||
var amt float64
|
||||
if tx.Amount != nil && tx.Amount.Total != nil {
|
||||
amt = float64(*tx.Amount.Total) / 100
|
||||
}
|
||||
st := "failed"
|
||||
if wxSV(tx.TradeState) == "SUCCESS" {
|
||||
st = "success"
|
||||
}
|
||||
return &payment.PaymentNotification{
|
||||
TradeNo: wxSV(tx.TransactionId), OrderID: wxSV(tx.OutTradeNo),
|
||||
Amount: amt, Status: st, RawData: rawBody,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *Wxpay) Refund(ctx context.Context, req payment.RefundRequest) (*payment.RefundResponse, error) {
|
||||
c, err := w.ensureClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rf, err := yuanToFen(req.Amount)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay refund amount: %w", err)
|
||||
}
|
||||
svc := native.NativeApiService{Client: c}
|
||||
tx, _, err := svc.QueryOrderByOutTradeNo(ctx, native.QueryOrderByOutTradeNoRequest{
|
||||
OutTradeNo: core.String(req.OrderID), Mchid: core.String(w.config["mchId"]),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay refund query order: %w", err)
|
||||
}
|
||||
var tf int64
|
||||
if tx.Amount != nil && tx.Amount.Total != nil {
|
||||
tf = *tx.Amount.Total
|
||||
}
|
||||
rs := refunddomestic.RefundsApiService{Client: c}
|
||||
cur := "CNY"
|
||||
res, _, err := rs.Create(ctx, refunddomestic.CreateRequest{
|
||||
OutTradeNo: core.String(req.OrderID),
|
||||
OutRefundNo: core.String(fmt.Sprintf("%s-refund-%d", req.OrderID, time.Now().UnixNano())),
|
||||
Reason: core.String(req.Reason),
|
||||
Amount: &refunddomestic.AmountReq{Refund: core.Int64(rf), Total: core.Int64(tf), Currency: &cur},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wxpay refund: %w", err)
|
||||
}
|
||||
rid := wxSV(res.RefundId)
|
||||
if rid == "" {
|
||||
rid = fmt.Sprintf("%s-refund", req.OrderID)
|
||||
}
|
||||
st := "pending"
|
||||
if res.Status != nil && *res.Status == refunddomestic.STATUS_SUCCESS {
|
||||
st = "success"
|
||||
}
|
||||
return &payment.RefundResponse{RefundID: rid, Status: st}, nil
|
||||
}
|
||||
|
||||
func (w *Wxpay) CancelPayment(ctx context.Context, tradeNo string) error {
|
||||
c, err := w.ensureClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
svc := native.NativeApiService{Client: c}
|
||||
_, err = svc.CloseOrder(ctx, native.CloseOrderRequest{
|
||||
OutTradeNo: core.String(tradeNo), Mchid: core.String(w.config["mchId"]),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("wxpay cancel payment: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ payment.Provider = (*Wxpay)(nil)
|
||||
_ payment.CancelableProvider = (*Wxpay)(nil)
|
||||
)
|
||||
@@ -0,0 +1,88 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
|
||||
)
|
||||
|
||||
// Registry is a thread-safe registry mapping PaymentType to Provider.
|
||||
type Registry struct {
|
||||
mu sync.RWMutex
|
||||
providers map[PaymentType]Provider
|
||||
}
|
||||
|
||||
// ErrProviderNotFound is returned when a requested payment provider is not registered.
|
||||
var ErrProviderNotFound = infraerrors.NotFound("PROVIDER_NOT_FOUND", "payment provider not registered")
|
||||
|
||||
// NewRegistry creates a new empty provider registry.
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{
|
||||
providers: make(map[PaymentType]Provider),
|
||||
}
|
||||
}
|
||||
|
||||
// Register adds a provider for each of its supported payment types.
|
||||
// If a type was previously registered, it is overwritten.
|
||||
func (r *Registry) Register(p Provider) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
for _, t := range p.SupportedTypes() {
|
||||
r.providers[t] = p
|
||||
}
|
||||
}
|
||||
|
||||
// GetProvider returns the provider registered for the given payment type.
|
||||
func (r *Registry) GetProvider(t PaymentType) (Provider, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
p, ok := r.providers[t]
|
||||
if !ok {
|
||||
return nil, ErrProviderNotFound
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// GetProviderByKey returns the first provider whose ProviderKey matches the given key.
|
||||
func (r *Registry) GetProviderByKey(key string) (Provider, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
seen := make(map[string]bool)
|
||||
for _, p := range r.providers {
|
||||
k := p.ProviderKey()
|
||||
if k == key && !seen[k] {
|
||||
return p, nil
|
||||
}
|
||||
seen[k] = true
|
||||
}
|
||||
return nil, ErrProviderNotFound
|
||||
}
|
||||
|
||||
// GetProviderKey returns the provider key for the given payment type, or empty string if not found.
|
||||
func (r *Registry) GetProviderKey(t PaymentType) string {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
p, ok := r.providers[t]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return p.ProviderKey()
|
||||
}
|
||||
|
||||
// SupportedTypes returns all currently registered payment types.
|
||||
func (r *Registry) SupportedTypes() []PaymentType {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
types := make([]PaymentType, 0, len(r.providers))
|
||||
for t := range r.providers {
|
||||
types = append(types, t)
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
// Clear removes all registered providers.
|
||||
func (r *Registry) Clear() {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.providers = make(map[PaymentType]Provider)
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// mockProvider implements the Provider interface for testing.
|
||||
type mockProvider struct {
|
||||
name string
|
||||
key string
|
||||
supportedTypes []PaymentType
|
||||
}
|
||||
|
||||
func (m *mockProvider) Name() string { return m.name }
|
||||
func (m *mockProvider) ProviderKey() string { return m.key }
|
||||
func (m *mockProvider) SupportedTypes() []PaymentType { return m.supportedTypes }
|
||||
func (m *mockProvider) CreatePayment(_ context.Context, _ CreatePaymentRequest) (*CreatePaymentResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (m *mockProvider) QueryOrder(_ context.Context, _ string) (*QueryOrderResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (m *mockProvider) VerifyNotification(_ context.Context, _ string, _ map[string]string) (*PaymentNotification, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (m *mockProvider) Refund(_ context.Context, _ RefundRequest) (*RefundResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestRegistryRegisterAndGetProvider(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
p := &mockProvider{
|
||||
name: "TestPay",
|
||||
key: "testpay",
|
||||
supportedTypes: []PaymentType{TypeAlipay, TypeWxpay},
|
||||
}
|
||||
r.Register(p)
|
||||
|
||||
got, err := r.GetProvider(TypeAlipay)
|
||||
if err != nil {
|
||||
t.Fatalf("GetProvider(alipay) error: %v", err)
|
||||
}
|
||||
if got.ProviderKey() != "testpay" {
|
||||
t.Fatalf("GetProvider(alipay) key = %q, want %q", got.ProviderKey(), "testpay")
|
||||
}
|
||||
|
||||
got2, err := r.GetProvider(TypeWxpay)
|
||||
if err != nil {
|
||||
t.Fatalf("GetProvider(wxpay) error: %v", err)
|
||||
}
|
||||
if got2.ProviderKey() != "testpay" {
|
||||
t.Fatalf("GetProvider(wxpay) key = %q, want %q", got2.ProviderKey(), "testpay")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryGetProviderNotFound(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
_, err := r.GetProvider("nonexistent")
|
||||
if err == nil {
|
||||
t.Fatal("GetProvider for unregistered type should return error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryGetProviderByKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
p := &mockProvider{
|
||||
name: "EasyPay",
|
||||
key: "easypay",
|
||||
supportedTypes: []PaymentType{TypeAlipay},
|
||||
}
|
||||
r.Register(p)
|
||||
|
||||
got, err := r.GetProviderByKey("easypay")
|
||||
if err != nil {
|
||||
t.Fatalf("GetProviderByKey error: %v", err)
|
||||
}
|
||||
if got.Name() != "EasyPay" {
|
||||
t.Fatalf("GetProviderByKey name = %q, want %q", got.Name(), "EasyPay")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryGetProviderByKeyNotFound(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
_, err := r.GetProviderByKey("nonexistent")
|
||||
if err == nil {
|
||||
t.Fatal("GetProviderByKey for unknown key should return error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryGetProviderKeyUnknownType(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
key := r.GetProviderKey("unknown_type")
|
||||
if key != "" {
|
||||
t.Fatalf("GetProviderKey for unknown type should return empty, got %q", key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryGetProviderKeyKnownType(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
p := &mockProvider{
|
||||
name: "Stripe",
|
||||
key: "stripe",
|
||||
supportedTypes: []PaymentType{TypeStripe},
|
||||
}
|
||||
r.Register(p)
|
||||
|
||||
key := r.GetProviderKey(TypeStripe)
|
||||
if key != "stripe" {
|
||||
t.Fatalf("GetProviderKey(stripe) = %q, want %q", key, "stripe")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistrySupportedTypes(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
p1 := &mockProvider{
|
||||
name: "EasyPay",
|
||||
key: "easypay",
|
||||
supportedTypes: []PaymentType{TypeAlipay, TypeWxpay},
|
||||
}
|
||||
p2 := &mockProvider{
|
||||
name: "Stripe",
|
||||
key: "stripe",
|
||||
supportedTypes: []PaymentType{TypeStripe},
|
||||
}
|
||||
r.Register(p1)
|
||||
r.Register(p2)
|
||||
|
||||
types := r.SupportedTypes()
|
||||
if len(types) != 3 {
|
||||
t.Fatalf("SupportedTypes() len = %d, want 3", len(types))
|
||||
}
|
||||
|
||||
typeSet := make(map[PaymentType]bool)
|
||||
for _, tp := range types {
|
||||
typeSet[tp] = true
|
||||
}
|
||||
for _, expected := range []PaymentType{TypeAlipay, TypeWxpay, TypeStripe} {
|
||||
if !typeSet[expected] {
|
||||
t.Fatalf("SupportedTypes() missing %q", expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistrySupportedTypesEmpty(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
types := r.SupportedTypes()
|
||||
if len(types) != 0 {
|
||||
t.Fatalf("SupportedTypes() on empty registry should be empty, got %d", len(types))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryOverwriteExisting(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
p1 := &mockProvider{
|
||||
name: "OldPay",
|
||||
key: "old",
|
||||
supportedTypes: []PaymentType{TypeAlipay},
|
||||
}
|
||||
p2 := &mockProvider{
|
||||
name: "NewPay",
|
||||
key: "new",
|
||||
supportedTypes: []PaymentType{TypeAlipay},
|
||||
}
|
||||
r.Register(p1)
|
||||
r.Register(p2)
|
||||
|
||||
got, err := r.GetProvider(TypeAlipay)
|
||||
if err != nil {
|
||||
t.Fatalf("GetProvider error: %v", err)
|
||||
}
|
||||
if got.Name() != "NewPay" {
|
||||
t.Fatalf("expected overwritten provider, got %q", got.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryConcurrentAccess(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := NewRegistry()
|
||||
|
||||
const goroutines = 50
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(goroutines * 2)
|
||||
|
||||
// Concurrent writers
|
||||
for i := 0; i < goroutines; i++ {
|
||||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
p := &mockProvider{
|
||||
name: fmt.Sprintf("Provider-%d", idx),
|
||||
key: fmt.Sprintf("key-%d", idx),
|
||||
supportedTypes: []PaymentType{PaymentType(fmt.Sprintf("type-%d", idx))},
|
||||
}
|
||||
r.Register(p)
|
||||
}(i)
|
||||
}
|
||||
|
||||
// Concurrent readers
|
||||
for i := 0; i < goroutines; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_ = r.SupportedTypes()
|
||||
_, _ = r.GetProvider("some-type")
|
||||
_ = r.GetProviderKey("some-type")
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
types := r.SupportedTypes()
|
||||
if len(types) != goroutines {
|
||||
t.Fatalf("after concurrent registration, expected %d types, got %d", goroutines, len(types))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// Package payment provides the core payment provider abstraction,
|
||||
// registry, load balancing, and shared utilities for the payment subsystem.
|
||||
package payment
|
||||
|
||||
import "context"
|
||||
|
||||
// PaymentType represents a supported payment method.
|
||||
type PaymentType = string
|
||||
|
||||
// Supported payment type constants.
|
||||
const (
|
||||
TypeAlipay PaymentType = "alipay"
|
||||
TypeWxpay PaymentType = "wxpay"
|
||||
TypeAlipayDirect PaymentType = "alipay_direct"
|
||||
TypeWxpayDirect PaymentType = "wxpay_direct"
|
||||
TypeStripe PaymentType = "stripe"
|
||||
)
|
||||
|
||||
// GetBasePaymentType extracts the base payment method from a composite key.
|
||||
// For example, "alipay_direct" -> "alipay".
|
||||
func GetBasePaymentType(t string) string {
|
||||
switch {
|
||||
case len(t) >= 6 && t[:6] == "alipay":
|
||||
return "alipay"
|
||||
case len(t) >= 5 && t[:5] == "wxpay":
|
||||
return "wxpay"
|
||||
case len(t) >= 6 && t[:6] == "stripe":
|
||||
return "stripe"
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
// CreatePaymentRequest holds the parameters for creating a new payment.
|
||||
type CreatePaymentRequest struct {
|
||||
OrderID string // Internal order ID
|
||||
Amount string // Pay amount in CNY (formatted to 2 decimal places)
|
||||
PaymentType string // e.g. "alipay", "wxpay"
|
||||
Subject string // Product description
|
||||
NotifyURL string // Webhook callback URL
|
||||
ReturnURL string // Browser redirect URL after payment
|
||||
ClientIP string // Payer's IP address
|
||||
IsMobile bool // Whether the request comes from a mobile device
|
||||
}
|
||||
|
||||
// CreatePaymentResponse is returned after successfully initiating a payment.
|
||||
type CreatePaymentResponse struct {
|
||||
TradeNo string // Third-party transaction ID
|
||||
PayURL string // H5 payment URL (alipay/wxpay)
|
||||
QRCode string // QR code content for scanning
|
||||
ClientSecret string // Stripe PaymentIntent client secret
|
||||
}
|
||||
|
||||
// QueryOrderResponse describes the payment status from the upstream provider.
|
||||
type QueryOrderResponse struct {
|
||||
TradeNo string
|
||||
Status string // "pending", "paid", "failed", "refunded"
|
||||
Amount float64 // Amount in CNY
|
||||
PaidAt string // RFC3339 timestamp or empty
|
||||
}
|
||||
|
||||
// PaymentNotification is the parsed result of a webhook/notify callback.
|
||||
type PaymentNotification struct {
|
||||
TradeNo string
|
||||
OrderID string
|
||||
Amount float64
|
||||
Status string // "success" or "failed"
|
||||
RawData string // Raw notification body for audit
|
||||
}
|
||||
|
||||
// RefundRequest contains the parameters for requesting a refund.
|
||||
type RefundRequest struct {
|
||||
TradeNo string
|
||||
OrderID string
|
||||
Amount string // Refund amount formatted to 2 decimal places
|
||||
Reason string
|
||||
}
|
||||
|
||||
// RefundResponse is returned after a refund request.
|
||||
type RefundResponse struct {
|
||||
RefundID string
|
||||
Status string // "success", "pending", "failed"
|
||||
}
|
||||
|
||||
// InstanceSelection holds the selected provider instance and its decrypted config.
|
||||
type InstanceSelection struct {
|
||||
InstanceID string
|
||||
Config map[string]string
|
||||
}
|
||||
|
||||
// Provider defines the interface that all payment providers must implement.
|
||||
type Provider interface {
|
||||
// Name returns a human-readable name for this provider.
|
||||
Name() string
|
||||
// ProviderKey returns the unique key identifying this provider type (e.g. "easypay").
|
||||
ProviderKey() string
|
||||
// SupportedTypes returns the list of payment types this provider handles.
|
||||
SupportedTypes() []PaymentType
|
||||
// CreatePayment initiates a payment and returns the upstream response.
|
||||
CreatePayment(ctx context.Context, req CreatePaymentRequest) (*CreatePaymentResponse, error)
|
||||
// QueryOrder queries the payment status of the given trade number.
|
||||
QueryOrder(ctx context.Context, tradeNo string) (*QueryOrderResponse, error)
|
||||
// VerifyNotification parses and verifies a webhook callback.
|
||||
// Returns nil for unrecognized or irrelevant events (caller should return 200).
|
||||
VerifyNotification(ctx context.Context, rawBody string, headers map[string]string) (*PaymentNotification, error)
|
||||
// Refund requests a refund from the upstream provider.
|
||||
Refund(ctx context.Context, req RefundRequest) (*RefundResponse, error)
|
||||
}
|
||||
|
||||
// CancelableProvider extends Provider with the ability to cancel pending payments.
|
||||
type CancelableProvider interface {
|
||||
Provider
|
||||
// CancelPayment cancels/expires a pending payment on the upstream platform.
|
||||
CancelPayment(ctx context.Context, tradeNo string) error
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
dbent "github.com/Wei-Shaw/sub2api/ent"
|
||||
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// EncryptionKey is a named type for the payment encryption key (AES-256, 32 bytes).
|
||||
// Using a named type avoids Wire ambiguity with other []byte parameters.
|
||||
type EncryptionKey []byte
|
||||
|
||||
// ProvideEncryptionKey derives the payment encryption key from the TOTP encryption key in config.
|
||||
func ProvideEncryptionKey(cfg *config.Config) EncryptionKey {
|
||||
key, _ := hex.DecodeString(cfg.Totp.EncryptionKey)
|
||||
return EncryptionKey(key)
|
||||
}
|
||||
|
||||
// ProvideRegistry creates an empty payment provider registry.
|
||||
// Providers are registered at runtime after application startup.
|
||||
func ProvideRegistry() *Registry {
|
||||
return NewRegistry()
|
||||
}
|
||||
|
||||
// ProvideDefaultLoadBalancer creates a DefaultLoadBalancer backed by the ent client.
|
||||
func ProvideDefaultLoadBalancer(client *dbent.Client, key EncryptionKey) *DefaultLoadBalancer {
|
||||
return NewDefaultLoadBalancer(client, []byte(key))
|
||||
}
|
||||
|
||||
// ProviderSet is the Wire provider set for the payment package.
|
||||
var ProviderSet = wire.NewSet(
|
||||
ProvideEncryptionKey,
|
||||
ProvideRegistry,
|
||||
ProvideDefaultLoadBalancer,
|
||||
wire.Bind(new(LoadBalancer), new(*DefaultLoadBalancer)),
|
||||
)
|
||||
@@ -42,9 +42,9 @@ func (r *channelRepository) Create(ctx context.Context, channel *service.Channel
|
||||
return err
|
||||
}
|
||||
err = tx.QueryRowContext(ctx,
|
||||
`INSERT INTO channels (name, description, status, model_mapping, billing_model_source, restrict_models) VALUES ($1, $2, $3, $4, $5, $6)
|
||||
`INSERT INTO channels (name, description, status, model_mapping, billing_model_source, restrict_models, features) VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id, created_at, updated_at`,
|
||||
channel.Name, channel.Description, channel.Status, modelMappingJSON, channel.BillingModelSource, channel.RestrictModels,
|
||||
channel.Name, channel.Description, channel.Status, modelMappingJSON, channel.BillingModelSource, channel.RestrictModels, channel.Features,
|
||||
).Scan(&channel.ID, &channel.CreatedAt, &channel.UpdatedAt)
|
||||
if err != nil {
|
||||
if isUniqueViolation(err) {
|
||||
@@ -75,9 +75,9 @@ func (r *channelRepository) GetByID(ctx context.Context, id int64) (*service.Cha
|
||||
ch := &service.Channel{}
|
||||
var modelMappingJSON []byte
|
||||
err := r.db.QueryRowContext(ctx,
|
||||
`SELECT id, name, description, status, model_mapping, billing_model_source, restrict_models, created_at, updated_at
|
||||
`SELECT id, name, description, status, model_mapping, billing_model_source, restrict_models, features, created_at, updated_at
|
||||
FROM channels WHERE id = $1`, id,
|
||||
).Scan(&ch.ID, &ch.Name, &ch.Description, &ch.Status, &modelMappingJSON, &ch.BillingModelSource, &ch.RestrictModels, &ch.CreatedAt, &ch.UpdatedAt)
|
||||
).Scan(&ch.ID, &ch.Name, &ch.Description, &ch.Status, &modelMappingJSON, &ch.BillingModelSource, &ch.RestrictModels, &ch.Features, &ch.CreatedAt, &ch.UpdatedAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, service.ErrChannelNotFound
|
||||
}
|
||||
@@ -108,9 +108,9 @@ func (r *channelRepository) Update(ctx context.Context, channel *service.Channel
|
||||
return err
|
||||
}
|
||||
result, err := tx.ExecContext(ctx,
|
||||
`UPDATE channels SET name = $1, description = $2, status = $3, model_mapping = $4, billing_model_source = $5, restrict_models = $6, updated_at = NOW()
|
||||
WHERE id = $7`,
|
||||
channel.Name, channel.Description, channel.Status, modelMappingJSON, channel.BillingModelSource, channel.RestrictModels, channel.ID,
|
||||
`UPDATE channels SET name = $1, description = $2, status = $3, model_mapping = $4, billing_model_source = $5, restrict_models = $6, features = $7, updated_at = NOW()
|
||||
WHERE id = $8`,
|
||||
channel.Name, channel.Description, channel.Status, modelMappingJSON, channel.BillingModelSource, channel.RestrictModels, channel.Features, channel.ID,
|
||||
)
|
||||
if err != nil {
|
||||
if isUniqueViolation(err) {
|
||||
@@ -204,7 +204,7 @@ func (r *channelRepository) List(ctx context.Context, params pagination.Paginati
|
||||
for rows.Next() {
|
||||
var ch service.Channel
|
||||
var modelMappingJSON []byte
|
||||
if err := rows.Scan(&ch.ID, &ch.Name, &ch.Description, &ch.Status, &modelMappingJSON, &ch.BillingModelSource, &ch.RestrictModels, &ch.CreatedAt, &ch.UpdatedAt); err != nil {
|
||||
if err := rows.Scan(&ch.ID, &ch.Name, &ch.Description, &ch.Status, &modelMappingJSON, &ch.BillingModelSource, &ch.RestrictModels, &ch.Features, &ch.CreatedAt, &ch.UpdatedAt); err != nil {
|
||||
return nil, nil, fmt.Errorf("scan channel: %w", err)
|
||||
}
|
||||
ch.ModelMapping = unmarshalModelMapping(modelMappingJSON)
|
||||
@@ -248,7 +248,7 @@ func (r *channelRepository) List(ctx context.Context, params pagination.Paginati
|
||||
|
||||
func (r *channelRepository) ListAll(ctx context.Context) ([]service.Channel, error) {
|
||||
rows, err := r.db.QueryContext(ctx,
|
||||
`SELECT id, name, description, status, model_mapping, billing_model_source, restrict_models, created_at, updated_at FROM channels ORDER BY id`,
|
||||
`SELECT id, name, description, status, model_mapping, billing_model_source, restrict_models, features, created_at, updated_at FROM channels ORDER BY id`,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query all channels: %w", err)
|
||||
@@ -260,7 +260,7 @@ func (r *channelRepository) ListAll(ctx context.Context) ([]service.Channel, err
|
||||
for rows.Next() {
|
||||
var ch service.Channel
|
||||
var modelMappingJSON []byte
|
||||
if err := rows.Scan(&ch.ID, &ch.Name, &ch.Description, &ch.Status, &modelMappingJSON, &ch.BillingModelSource, &ch.RestrictModels, &ch.CreatedAt, &ch.UpdatedAt); err != nil {
|
||||
if err := rows.Scan(&ch.ID, &ch.Name, &ch.Description, &ch.Status, &modelMappingJSON, &ch.BillingModelSource, &ch.RestrictModels, &ch.Features, &ch.CreatedAt, &ch.UpdatedAt); err != nil {
|
||||
return nil, fmt.Errorf("scan channel: %w", err)
|
||||
}
|
||||
ch.ModelMapping = unmarshalModelMapping(modelMappingJSON)
|
||||
|
||||
@@ -111,4 +111,5 @@ func registerRoutes(
|
||||
routes.RegisterUserRoutes(v1, h, jwtAuth, settingService)
|
||||
routes.RegisterAdminRoutes(v1, h, adminAuth)
|
||||
routes.RegisterGatewayRoutes(r, h, apiKeyAuth, apiKeyService, subscriptionService, opsService, settingService, cfg)
|
||||
routes.RegisterPaymentRoutes(v1, h.Payment, h.PaymentWebhook, h.Admin.Payment, jwtAuth, adminAuth, settingService)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/Wei-Shaw/sub2api/internal/handler"
|
||||
"github.com/Wei-Shaw/sub2api/internal/handler/admin"
|
||||
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// RegisterPaymentRoutes registers all payment-related routes:
|
||||
// user-facing endpoints, webhook endpoints, and admin endpoints.
|
||||
func RegisterPaymentRoutes(
|
||||
v1 *gin.RouterGroup,
|
||||
paymentHandler *handler.PaymentHandler,
|
||||
webhookHandler *handler.PaymentWebhookHandler,
|
||||
adminPaymentHandler *admin.PaymentHandler,
|
||||
jwtAuth middleware.JWTAuthMiddleware,
|
||||
adminAuth middleware.AdminAuthMiddleware,
|
||||
settingService *service.SettingService,
|
||||
) {
|
||||
// --- User-facing payment endpoints (authenticated) ---
|
||||
authenticated := v1.Group("/payment")
|
||||
authenticated.Use(gin.HandlerFunc(jwtAuth))
|
||||
authenticated.Use(middleware.BackendModeUserGuard(settingService))
|
||||
{
|
||||
authenticated.GET("/config", paymentHandler.GetPaymentConfig)
|
||||
authenticated.GET("/plans", paymentHandler.GetPlans)
|
||||
authenticated.GET("/channels", paymentHandler.GetChannels)
|
||||
authenticated.GET("/limits", paymentHandler.GetLimits)
|
||||
|
||||
orders := authenticated.Group("/orders")
|
||||
{
|
||||
orders.POST("", paymentHandler.CreateOrder)
|
||||
orders.GET("/my", paymentHandler.GetMyOrders)
|
||||
orders.GET("/:id", paymentHandler.GetOrder)
|
||||
orders.POST("/:id/cancel", paymentHandler.CancelOrder)
|
||||
orders.POST("/:id/refund-request", paymentHandler.RequestRefund)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Webhook endpoints (no auth) ---
|
||||
webhook := v1.Group("/payment/webhook")
|
||||
{
|
||||
webhook.POST("/easypay", webhookHandler.EasyPayNotify)
|
||||
webhook.POST("/alipay", webhookHandler.AlipayNotify)
|
||||
webhook.POST("/wxpay", webhookHandler.WxpayNotify)
|
||||
webhook.POST("/stripe", webhookHandler.StripeWebhook)
|
||||
}
|
||||
|
||||
// --- Admin payment endpoints (admin auth) ---
|
||||
adminGroup := v1.Group("/admin/payment")
|
||||
adminGroup.Use(gin.HandlerFunc(adminAuth))
|
||||
{
|
||||
// Dashboard
|
||||
adminGroup.GET("/dashboard", adminPaymentHandler.GetDashboard)
|
||||
|
||||
// Config
|
||||
adminGroup.GET("/config", adminPaymentHandler.GetConfig)
|
||||
adminGroup.PUT("/config", adminPaymentHandler.UpdateConfig)
|
||||
|
||||
// Orders
|
||||
adminOrders := adminGroup.Group("/orders")
|
||||
{
|
||||
adminOrders.GET("", adminPaymentHandler.ListOrders)
|
||||
adminOrders.GET("/:id", adminPaymentHandler.GetOrderDetail)
|
||||
adminOrders.POST("/:id/cancel", adminPaymentHandler.CancelOrder)
|
||||
adminOrders.POST("/:id/retry", adminPaymentHandler.RetryFulfillment)
|
||||
adminOrders.POST("/:id/refund", adminPaymentHandler.ProcessRefund)
|
||||
}
|
||||
|
||||
|
||||
// Subscription Plans
|
||||
plans := adminGroup.Group("/plans")
|
||||
{
|
||||
plans.GET("", adminPaymentHandler.ListPlans)
|
||||
plans.POST("", adminPaymentHandler.CreatePlan)
|
||||
plans.PUT("/:id", adminPaymentHandler.UpdatePlan)
|
||||
plans.DELETE("/:id", adminPaymentHandler.DeletePlan)
|
||||
}
|
||||
|
||||
// Provider Instances
|
||||
providers := adminGroup.Group("/providers")
|
||||
{
|
||||
providers.GET("", adminPaymentHandler.ListProviders)
|
||||
providers.POST("", adminPaymentHandler.CreateProvider)
|
||||
providers.PUT("/:id", adminPaymentHandler.UpdateProvider)
|
||||
providers.DELETE("/:id", adminPaymentHandler.DeleteProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ type Channel struct {
|
||||
Status string
|
||||
BillingModelSource string // "requested", "upstream", or "channel_mapped"
|
||||
RestrictModels bool // 是否限制模型(仅允许定价列表中的模型)
|
||||
Features string // 渠道特性描述(JSON 数组),用于支付页面展示
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
|
||||
|
||||
@@ -665,6 +665,7 @@ func (s *ChannelService) Create(ctx context.Context, input *CreateChannelInput)
|
||||
GroupIDs: input.GroupIDs,
|
||||
ModelPricing: input.ModelPricing,
|
||||
ModelMapping: input.ModelMapping,
|
||||
Features: input.Features,
|
||||
}
|
||||
if channel.BillingModelSource == "" {
|
||||
channel.BillingModelSource = BillingModelSourceChannelMapped
|
||||
@@ -735,6 +736,9 @@ func (s *ChannelService) applyUpdateInput(ctx context.Context, channel *Channel,
|
||||
if input.RestrictModels != nil {
|
||||
channel.RestrictModels = *input.RestrictModels
|
||||
}
|
||||
if input.Features != nil {
|
||||
channel.Features = *input.Features
|
||||
}
|
||||
if input.GroupIDs != nil {
|
||||
if err := s.checkGroupConflicts(ctx, channel.ID, *input.GroupIDs); err != nil {
|
||||
return err
|
||||
@@ -923,6 +927,7 @@ type CreateChannelInput struct {
|
||||
ModelMapping map[string]map[string]string // platform → {src→dst}
|
||||
BillingModelSource string
|
||||
RestrictModels bool
|
||||
Features string
|
||||
}
|
||||
|
||||
// UpdateChannelInput 更新渠道输入
|
||||
@@ -935,4 +940,5 @@ type UpdateChannelInput struct {
|
||||
ModelMapping map[string]map[string]string // platform → {src→dst}
|
||||
BillingModelSource string
|
||||
RestrictModels *bool
|
||||
Features *string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,509 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
dbent "github.com/Wei-Shaw/sub2api/ent"
|
||||
"github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance"
|
||||
"github.com/Wei-Shaw/sub2api/ent/subscriptionplan"
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
SettingPaymentEnabled = "payment_enabled"
|
||||
SettingMinRechargeAmount = "MIN_RECHARGE_AMOUNT"
|
||||
SettingMaxRechargeAmount = "MAX_RECHARGE_AMOUNT"
|
||||
SettingDailyRechargeLimit = "DAILY_RECHARGE_LIMIT"
|
||||
SettingOrderTimeoutMinutes = "ORDER_TIMEOUT_MINUTES"
|
||||
SettingMaxPendingOrders = "MAX_PENDING_ORDERS"
|
||||
SettingEnabledPaymentTypes = "ENABLED_PAYMENT_TYPES"
|
||||
SettingLoadBalanceStrategy = "LOAD_BALANCE_STRATEGY"
|
||||
SettingBalancePayDisabled = "BALANCE_PAYMENT_DISABLED"
|
||||
SettingProductNamePrefix = "PRODUCT_NAME_PREFIX"
|
||||
SettingProductNameSuffix = "PRODUCT_NAME_SUFFIX"
|
||||
SettingCancelRateLimitOn = "CANCEL_RATE_LIMIT_ENABLED"
|
||||
SettingCancelRateLimitMax = "CANCEL_RATE_LIMIT_MAX"
|
||||
SettingCancelWindowSize = "CANCEL_RATE_LIMIT_WINDOW"
|
||||
SettingCancelWindowUnit = "CANCEL_RATE_LIMIT_UNIT"
|
||||
SettingCancelWindowMode = "CANCEL_RATE_LIMIT_WINDOW_MODE"
|
||||
)
|
||||
|
||||
// PaymentConfig holds the payment system configuration.
|
||||
type PaymentConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
MinAmount float64 `json:"min_amount"`
|
||||
MaxAmount float64 `json:"max_amount"`
|
||||
DailyLimit float64 `json:"daily_limit"`
|
||||
OrderTimeoutMin int `json:"order_timeout_minutes"`
|
||||
MaxPendingOrders int `json:"max_pending_orders"`
|
||||
EnabledTypes []string `json:"enabled_payment_types"`
|
||||
BalanceDisabled bool `json:"balance_disabled"`
|
||||
LoadBalanceStrategy string `json:"load_balance_strategy"`
|
||||
ProductNamePrefix string `json:"product_name_prefix"`
|
||||
ProductNameSuffix string `json:"product_name_suffix"`
|
||||
}
|
||||
|
||||
// UpdatePaymentConfigRequest contains fields to update payment configuration.
|
||||
type UpdatePaymentConfigRequest struct {
|
||||
Enabled *bool `json:"enabled"`
|
||||
MinAmount *float64 `json:"min_amount"`
|
||||
MaxAmount *float64 `json:"max_amount"`
|
||||
DailyLimit *float64 `json:"daily_limit"`
|
||||
OrderTimeoutMin *int `json:"order_timeout_minutes"`
|
||||
MaxPendingOrders *int `json:"max_pending_orders"`
|
||||
EnabledTypes []string `json:"enabled_payment_types"`
|
||||
BalanceDisabled *bool `json:"balance_disabled"`
|
||||
LoadBalanceStrategy *string `json:"load_balance_strategy"`
|
||||
ProductNamePrefix *string `json:"product_name_prefix"`
|
||||
ProductNameSuffix *string `json:"product_name_suffix"`
|
||||
}
|
||||
|
||||
// MethodLimits holds per-payment-type limits.
|
||||
type MethodLimits struct {
|
||||
PaymentType string `json:"paymentType"`
|
||||
FeeRate float64 `json:"feeRate"`
|
||||
DailyLimit float64 `json:"daily_limit"`
|
||||
SingleMin float64 `json:"singleMin"`
|
||||
SingleMax float64 `json:"singleMax"`
|
||||
}
|
||||
|
||||
type CreateProviderInstanceRequest struct {
|
||||
ProviderKey string `json:"providerKey"`
|
||||
Name string `json:"name"`
|
||||
Config map[string]string `json:"config"`
|
||||
SupportedTypes string `json:"supportedTypes"`
|
||||
Enabled bool `json:"enabled"`
|
||||
SortOrder int `json:"sortOrder"`
|
||||
Limits string `json:"limits"`
|
||||
RefundEnabled bool `json:"refundEnabled"`
|
||||
}
|
||||
|
||||
type UpdateProviderInstanceRequest struct {
|
||||
Name *string `json:"name"`
|
||||
Config map[string]string `json:"config"`
|
||||
SupportedTypes *string `json:"supportedTypes"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
SortOrder *int `json:"sortOrder"`
|
||||
Limits *string `json:"limits"`
|
||||
RefundEnabled *bool `json:"refundEnabled"`
|
||||
}
|
||||
type CreatePlanRequest struct {
|
||||
GroupID int64 `json:"groupId"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Price float64 `json:"price"`
|
||||
OriginalPrice *float64 `json:"originalPrice"`
|
||||
ValidityDays int `json:"validityDays"`
|
||||
ValidityUnit string `json:"validityUnit"`
|
||||
Features string `json:"features"`
|
||||
ProductName string `json:"productName"`
|
||||
ForSale bool `json:"forSale"`
|
||||
SortOrder int `json:"sortOrder"`
|
||||
}
|
||||
|
||||
type UpdatePlanRequest struct {
|
||||
GroupID *int64 `json:"groupId"`
|
||||
Name *string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
Price *float64 `json:"price"`
|
||||
OriginalPrice *float64 `json:"originalPrice"`
|
||||
ValidityDays *int `json:"validityDays"`
|
||||
ValidityUnit *string `json:"validityUnit"`
|
||||
Features *string `json:"features"`
|
||||
ProductName *string `json:"productName"`
|
||||
ForSale *bool `json:"forSale"`
|
||||
SortOrder *int `json:"sortOrder"`
|
||||
}
|
||||
|
||||
// PaymentConfigService manages payment configuration and CRUD for
|
||||
// provider instances, channels, and subscription plans.
|
||||
type PaymentConfigService struct {
|
||||
entClient *dbent.Client
|
||||
settingRepo SettingRepository
|
||||
encryptionKey []byte
|
||||
}
|
||||
|
||||
// NewPaymentConfigService creates a new PaymentConfigService.
|
||||
func NewPaymentConfigService(entClient *dbent.Client, settingRepo SettingRepository, encryptionKey []byte) *PaymentConfigService {
|
||||
return &PaymentConfigService{entClient: entClient, settingRepo: settingRepo, encryptionKey: encryptionKey}
|
||||
}
|
||||
|
||||
// IsPaymentEnabled returns whether the payment system is enabled.
|
||||
func (s *PaymentConfigService) IsPaymentEnabled(ctx context.Context) bool {
|
||||
val, err := s.settingRepo.GetValue(ctx, SettingPaymentEnabled)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return val == "true"
|
||||
}
|
||||
|
||||
// GetPaymentConfig returns the full payment configuration.
|
||||
func (s *PaymentConfigService) GetPaymentConfig(ctx context.Context) (*PaymentConfig, error) {
|
||||
keys := []string{
|
||||
SettingPaymentEnabled, SettingMinRechargeAmount, SettingMaxRechargeAmount,
|
||||
SettingDailyRechargeLimit, SettingOrderTimeoutMinutes, SettingMaxPendingOrders,
|
||||
SettingEnabledPaymentTypes, SettingBalancePayDisabled, SettingLoadBalanceStrategy,
|
||||
SettingProductNamePrefix, SettingProductNameSuffix,
|
||||
}
|
||||
vals, err := s.settingRepo.GetMultiple(ctx, keys)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get payment config settings: %w", err)
|
||||
}
|
||||
return s.parsePaymentConfig(vals), nil
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) parsePaymentConfig(vals map[string]string) *PaymentConfig {
|
||||
cfg := &PaymentConfig{
|
||||
Enabled: vals[SettingPaymentEnabled] == "true",
|
||||
MinAmount: pcParseFloat(vals[SettingMinRechargeAmount], 1),
|
||||
MaxAmount: pcParseFloat(vals[SettingMaxRechargeAmount], 99999999.99),
|
||||
DailyLimit: pcParseFloat(vals[SettingDailyRechargeLimit], 0),
|
||||
OrderTimeoutMin: pcParseInt(vals[SettingOrderTimeoutMinutes], 30),
|
||||
MaxPendingOrders: pcParseInt(vals[SettingMaxPendingOrders], 3),
|
||||
BalanceDisabled: vals[SettingBalancePayDisabled] == "true",
|
||||
LoadBalanceStrategy: vals[SettingLoadBalanceStrategy],
|
||||
ProductNamePrefix: vals[SettingProductNamePrefix],
|
||||
ProductNameSuffix: vals[SettingProductNameSuffix],
|
||||
}
|
||||
if cfg.LoadBalanceStrategy == "" {
|
||||
cfg.LoadBalanceStrategy = "round-robin"
|
||||
}
|
||||
if raw := vals[SettingEnabledPaymentTypes]; raw != "" {
|
||||
for _, t := range strings.Split(raw, ",") {
|
||||
t = strings.TrimSpace(t)
|
||||
if t != "" {
|
||||
cfg.EnabledTypes = append(cfg.EnabledTypes, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
// UpdatePaymentConfig updates the payment configuration settings.
|
||||
func (s *PaymentConfigService) UpdatePaymentConfig(ctx context.Context, req UpdatePaymentConfigRequest) error {
|
||||
m := make(map[string]string)
|
||||
if req.Enabled != nil {
|
||||
m[SettingPaymentEnabled] = strconv.FormatBool(*req.Enabled)
|
||||
}
|
||||
if req.MinAmount != nil {
|
||||
m[SettingMinRechargeAmount] = strconv.FormatFloat(*req.MinAmount, 'f', 2, 64)
|
||||
}
|
||||
if req.MaxAmount != nil {
|
||||
m[SettingMaxRechargeAmount] = strconv.FormatFloat(*req.MaxAmount, 'f', 2, 64)
|
||||
}
|
||||
if req.DailyLimit != nil {
|
||||
m[SettingDailyRechargeLimit] = strconv.FormatFloat(*req.DailyLimit, 'f', 2, 64)
|
||||
}
|
||||
if req.OrderTimeoutMin != nil {
|
||||
m[SettingOrderTimeoutMinutes] = strconv.Itoa(*req.OrderTimeoutMin)
|
||||
}
|
||||
if req.MaxPendingOrders != nil {
|
||||
m[SettingMaxPendingOrders] = strconv.Itoa(*req.MaxPendingOrders)
|
||||
}
|
||||
if req.EnabledTypes != nil {
|
||||
m[SettingEnabledPaymentTypes] = strings.Join(req.EnabledTypes, ",")
|
||||
}
|
||||
if req.BalanceDisabled != nil {
|
||||
m[SettingBalancePayDisabled] = strconv.FormatBool(*req.BalanceDisabled)
|
||||
}
|
||||
if req.LoadBalanceStrategy != nil {
|
||||
m[SettingLoadBalanceStrategy] = *req.LoadBalanceStrategy
|
||||
}
|
||||
if req.ProductNamePrefix != nil {
|
||||
m[SettingProductNamePrefix] = *req.ProductNamePrefix
|
||||
}
|
||||
if req.ProductNameSuffix != nil {
|
||||
m[SettingProductNameSuffix] = *req.ProductNameSuffix
|
||||
}
|
||||
if len(m) == 0 {
|
||||
return nil
|
||||
}
|
||||
return s.settingRepo.SetMultiple(ctx, m)
|
||||
}
|
||||
|
||||
// --- Provider Instance CRUD ---
|
||||
|
||||
func (s *PaymentConfigService) ListProviderInstances(ctx context.Context) ([]*dbent.PaymentProviderInstance, error) {
|
||||
return s.entClient.PaymentProviderInstance.Query().Order(paymentproviderinstance.BySortOrder()).All(ctx)
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) CreateProviderInstance(ctx context.Context, req CreateProviderInstanceRequest) (*dbent.PaymentProviderInstance, error) {
|
||||
enc, err := s.encryptConfig(req.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.entClient.PaymentProviderInstance.Create().
|
||||
SetProviderKey(req.ProviderKey).SetName(req.Name).SetConfig(enc).
|
||||
SetSupportedTypes(req.SupportedTypes).SetEnabled(req.Enabled).
|
||||
SetSortOrder(req.SortOrder).SetLimits(req.Limits).SetRefundEnabled(req.RefundEnabled).
|
||||
Save(ctx)
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) UpdateProviderInstance(ctx context.Context, id int64, req UpdateProviderInstanceRequest) (*dbent.PaymentProviderInstance, error) {
|
||||
u := s.entClient.PaymentProviderInstance.UpdateOneID(id)
|
||||
if req.Name != nil {
|
||||
u.SetName(*req.Name)
|
||||
}
|
||||
if req.Config != nil {
|
||||
enc, err := s.encryptConfig(req.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.SetConfig(enc)
|
||||
}
|
||||
if req.SupportedTypes != nil {
|
||||
u.SetSupportedTypes(*req.SupportedTypes)
|
||||
}
|
||||
if req.Enabled != nil {
|
||||
u.SetEnabled(*req.Enabled)
|
||||
}
|
||||
if req.SortOrder != nil {
|
||||
u.SetSortOrder(*req.SortOrder)
|
||||
}
|
||||
if req.Limits != nil {
|
||||
u.SetLimits(*req.Limits)
|
||||
}
|
||||
if req.RefundEnabled != nil {
|
||||
u.SetRefundEnabled(*req.RefundEnabled)
|
||||
}
|
||||
return u.Save(ctx)
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) DeleteProviderInstance(ctx context.Context, id int64) error {
|
||||
return s.entClient.PaymentProviderInstance.DeleteOneID(id).Exec(ctx)
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) encryptConfig(cfg map[string]string) (string, error) {
|
||||
data, err := json.Marshal(cfg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal config: %w", err)
|
||||
}
|
||||
enc, err := payment.Encrypt(string(data), s.encryptionKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("encrypt config: %w", err)
|
||||
}
|
||||
return enc, nil
|
||||
}
|
||||
|
||||
// --- Channel CRUD ---
|
||||
|
||||
|
||||
// --- Plan CRUD ---
|
||||
|
||||
func (s *PaymentConfigService) ListPlans(ctx context.Context) ([]*dbent.SubscriptionPlan, error) {
|
||||
return s.entClient.SubscriptionPlan.Query().Order(subscriptionplan.BySortOrder()).All(ctx)
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) ListPlansForSale(ctx context.Context) ([]*dbent.SubscriptionPlan, error) {
|
||||
return s.entClient.SubscriptionPlan.Query().Where(subscriptionplan.ForSaleEQ(true)).Order(subscriptionplan.BySortOrder()).All(ctx)
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) CreatePlan(ctx context.Context, req CreatePlanRequest) (*dbent.SubscriptionPlan, error) {
|
||||
b := s.entClient.SubscriptionPlan.Create().
|
||||
SetGroupID(req.GroupID).SetName(req.Name).SetDescription(req.Description).
|
||||
SetPrice(req.Price).SetValidityDays(req.ValidityDays).SetValidityUnit(req.ValidityUnit).
|
||||
SetFeatures(req.Features).SetProductName(req.ProductName).
|
||||
SetForSale(req.ForSale).SetSortOrder(req.SortOrder)
|
||||
if req.OriginalPrice != nil {
|
||||
b.SetOriginalPrice(*req.OriginalPrice)
|
||||
}
|
||||
return b.Save(ctx)
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) UpdatePlan(ctx context.Context, id int64, req UpdatePlanRequest) (*dbent.SubscriptionPlan, error) {
|
||||
u := s.entClient.SubscriptionPlan.UpdateOneID(id)
|
||||
if req.GroupID != nil {
|
||||
u.SetGroupID(*req.GroupID)
|
||||
}
|
||||
if req.Name != nil {
|
||||
u.SetName(*req.Name)
|
||||
}
|
||||
if req.Description != nil {
|
||||
u.SetDescription(*req.Description)
|
||||
}
|
||||
if req.Price != nil {
|
||||
u.SetPrice(*req.Price)
|
||||
}
|
||||
if req.OriginalPrice != nil {
|
||||
u.SetOriginalPrice(*req.OriginalPrice)
|
||||
}
|
||||
if req.ValidityDays != nil {
|
||||
u.SetValidityDays(*req.ValidityDays)
|
||||
}
|
||||
if req.ValidityUnit != nil {
|
||||
u.SetValidityUnit(*req.ValidityUnit)
|
||||
}
|
||||
if req.Features != nil {
|
||||
u.SetFeatures(*req.Features)
|
||||
}
|
||||
if req.ProductName != nil {
|
||||
u.SetProductName(*req.ProductName)
|
||||
}
|
||||
if req.ForSale != nil {
|
||||
u.SetForSale(*req.ForSale)
|
||||
}
|
||||
if req.SortOrder != nil {
|
||||
u.SetSortOrder(*req.SortOrder)
|
||||
}
|
||||
return u.Save(ctx)
|
||||
}
|
||||
|
||||
func (s *PaymentConfigService) DeletePlan(ctx context.Context, id int64) error {
|
||||
return s.entClient.SubscriptionPlan.DeleteOneID(id).Exec(ctx)
|
||||
}
|
||||
|
||||
// GetPlan returns a subscription plan by ID.
|
||||
func (s *PaymentConfigService) GetPlan(ctx context.Context, id int64) (*dbent.SubscriptionPlan, error) {
|
||||
plan, err := s.entClient.SubscriptionPlan.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, infraerrors.NotFound("PLAN_NOT_FOUND", "subscription plan not found")
|
||||
}
|
||||
return plan, nil
|
||||
}
|
||||
|
||||
// GetMethodLimits returns per-payment-type limits from enabled provider instances.
|
||||
func (s *PaymentConfigService) GetMethodLimits(ctx context.Context, types []string) ([]MethodLimits, error) {
|
||||
instances, err := s.entClient.PaymentProviderInstance.Query().
|
||||
Where(paymentproviderinstance.EnabledEQ(true)).All(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query provider instances: %w", err)
|
||||
}
|
||||
result := make([]MethodLimits, 0, len(types))
|
||||
for _, pt := range types {
|
||||
ml := MethodLimits{PaymentType: pt}
|
||||
for _, inst := range instances {
|
||||
if !pcInstanceSupportsType(inst, pt) {
|
||||
continue
|
||||
}
|
||||
pcApplyInstanceLimits(inst, pt, &ml)
|
||||
}
|
||||
result = append(result, ml)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func pcInstanceSupportsType(inst *dbent.PaymentProviderInstance, pt string) bool {
|
||||
if inst.SupportedTypes == "" {
|
||||
return true
|
||||
}
|
||||
for _, t := range strings.Split(inst.SupportedTypes, ",") {
|
||||
if strings.TrimSpace(t) == pt {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func pcApplyInstanceLimits(inst *dbent.PaymentProviderInstance, pt string, ml *MethodLimits) {
|
||||
if inst.Limits == "" {
|
||||
return
|
||||
}
|
||||
var limits payment.InstanceLimits
|
||||
if err := json.Unmarshal([]byte(inst.Limits), &limits); err != nil {
|
||||
return
|
||||
}
|
||||
cl, ok := limits[pt]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if cl.DailyLimit > 0 && (ml.DailyLimit == 0 || cl.DailyLimit < ml.DailyLimit) {
|
||||
ml.DailyLimit = cl.DailyLimit
|
||||
}
|
||||
if cl.SingleMin > 0 && (ml.SingleMin == 0 || cl.SingleMin > ml.SingleMin) {
|
||||
ml.SingleMin = cl.SingleMin
|
||||
}
|
||||
if cl.SingleMax > 0 && (ml.SingleMax == 0 || cl.SingleMax < ml.SingleMax) {
|
||||
ml.SingleMax = cl.SingleMax
|
||||
}
|
||||
}
|
||||
|
||||
func pcParseFloat(s string, defaultVal float64) float64 {
|
||||
if s == "" {
|
||||
return defaultVal
|
||||
}
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return defaultVal
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func pcParseInt(s string, defaultVal int) int {
|
||||
if s == "" {
|
||||
return defaultVal
|
||||
}
|
||||
v, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return defaultVal
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// MigrateLegacyPurchaseURL checks if the old purchase_subscription_url setting
|
||||
// exists and is enabled, and if so, migrates it to a custom_menu_item entry.
|
||||
// This is a one-time migration that runs at startup.
|
||||
func (s *PaymentConfigService) MigrateLegacyPurchaseURL(ctx context.Context) error {
|
||||
enabled, _ := s.settingRepo.GetValue(ctx, SettingKeyPurchaseSubscriptionEnabled)
|
||||
if enabled != "true" {
|
||||
return nil
|
||||
}
|
||||
url, _ := s.settingRepo.GetValue(ctx, SettingKeyPurchaseSubscriptionURL)
|
||||
url = strings.TrimSpace(url)
|
||||
if url == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read current custom_menu_items
|
||||
raw, _ := s.settingRepo.GetValue(ctx, SettingKeyCustomMenuItems)
|
||||
type menuItem struct {
|
||||
ID string `json:"id"`
|
||||
Label string `json:"label"`
|
||||
IconSVG string `json:"icon_svg"`
|
||||
URL string `json:"url"`
|
||||
Visibility string `json:"visibility"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
var items []menuItem
|
||||
if raw != "" {
|
||||
_ = json.Unmarshal([]byte(raw), &items)
|
||||
}
|
||||
|
||||
// Check if already migrated (same URL exists)
|
||||
for _, item := range items {
|
||||
if item.URL == url {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Append migrated item
|
||||
items = append(items, menuItem{
|
||||
ID: "migrated_purchase_subscription",
|
||||
Label: "Purchase Subscription",
|
||||
IconSVG: "",
|
||||
URL: url,
|
||||
Visibility: "user",
|
||||
SortOrder: 0,
|
||||
})
|
||||
|
||||
data, err := json.Marshal(items)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal custom_menu_items: %w", err)
|
||||
}
|
||||
|
||||
// Save updated menu items and clear old settings
|
||||
if err := s.settingRepo.SetMultiple(ctx, map[string]string{
|
||||
SettingKeyCustomMenuItems: string(data),
|
||||
SettingKeyPurchaseSubscriptionEnabled: "false",
|
||||
}); err != nil {
|
||||
return fmt.Errorf("save migrated settings: %w", err)
|
||||
}
|
||||
|
||||
slog.Info("[payment] Migrated legacy purchase_subscription_url to custom menu item", "url", url)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPcParseFloat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
defaultVal float64
|
||||
expected float64
|
||||
}{
|
||||
{"empty string returns default", "", 1.0, 1.0},
|
||||
{"valid float", "3.14", 0, 3.14},
|
||||
{"valid integer as float", "42", 0, 42.0},
|
||||
{"invalid string returns default", "notanumber", 9.99, 9.99},
|
||||
{"zero value", "0", 5.0, 0},
|
||||
{"negative value", "-10.5", 0, -10.5},
|
||||
{"very large value", "99999999.99", 0, 99999999.99},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got := pcParseFloat(tt.input, tt.defaultVal)
|
||||
if got != tt.expected {
|
||||
t.Fatalf("pcParseFloat(%q, %v) = %v, want %v", tt.input, tt.defaultVal, got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPcParseInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
defaultVal int
|
||||
expected int
|
||||
}{
|
||||
{"empty string returns default", "", 30, 30},
|
||||
{"valid int", "10", 0, 10},
|
||||
{"invalid string returns default", "abc", 5, 5},
|
||||
{"float string returns default", "3.14", 0, 0},
|
||||
{"zero value", "0", 99, 0},
|
||||
{"negative value", "-1", 0, -1},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got := pcParseInt(tt.input, tt.defaultVal)
|
||||
if got != tt.expected {
|
||||
t.Fatalf("pcParseInt(%q, %v) = %v, want %v", tt.input, tt.defaultVal, got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePaymentConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := &PaymentConfigService{}
|
||||
|
||||
t.Run("empty vals uses defaults", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
cfg := svc.parsePaymentConfig(map[string]string{})
|
||||
if cfg.Enabled {
|
||||
t.Fatal("expected Enabled=false by default")
|
||||
}
|
||||
if cfg.MinAmount != 1 {
|
||||
t.Fatalf("expected MinAmount=1, got %v", cfg.MinAmount)
|
||||
}
|
||||
if cfg.MaxAmount != 99999999.99 {
|
||||
t.Fatalf("expected MaxAmount=99999999.99, got %v", cfg.MaxAmount)
|
||||
}
|
||||
if cfg.OrderTimeoutMin != 30 {
|
||||
t.Fatalf("expected OrderTimeoutMin=30, got %v", cfg.OrderTimeoutMin)
|
||||
}
|
||||
if cfg.MaxPendingOrders != 3 {
|
||||
t.Fatalf("expected MaxPendingOrders=3, got %v", cfg.MaxPendingOrders)
|
||||
}
|
||||
if cfg.LoadBalanceStrategy != "round-robin" {
|
||||
t.Fatalf("expected LoadBalanceStrategy=round-robin, got %q", cfg.LoadBalanceStrategy)
|
||||
}
|
||||
if len(cfg.EnabledTypes) != 0 {
|
||||
t.Fatalf("expected empty EnabledTypes, got %v", cfg.EnabledTypes)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("all values populated", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
vals := map[string]string{
|
||||
SettingPaymentEnabled: "true",
|
||||
SettingMinRechargeAmount: "5.00",
|
||||
SettingMaxRechargeAmount: "1000.00",
|
||||
SettingDailyRechargeLimit: "5000.00",
|
||||
SettingOrderTimeoutMinutes: "15",
|
||||
SettingMaxPendingOrders: "5",
|
||||
SettingEnabledPaymentTypes: "alipay,wxpay,stripe",
|
||||
SettingBalancePayDisabled: "true",
|
||||
SettingLoadBalanceStrategy: "least_amount",
|
||||
SettingProductNamePrefix: "PRE",
|
||||
SettingProductNameSuffix: "SUF",
|
||||
}
|
||||
cfg := svc.parsePaymentConfig(vals)
|
||||
|
||||
if !cfg.Enabled {
|
||||
t.Fatal("expected Enabled=true")
|
||||
}
|
||||
if cfg.MinAmount != 5 {
|
||||
t.Fatalf("MinAmount = %v, want 5", cfg.MinAmount)
|
||||
}
|
||||
if cfg.MaxAmount != 1000 {
|
||||
t.Fatalf("MaxAmount = %v, want 1000", cfg.MaxAmount)
|
||||
}
|
||||
if cfg.DailyLimit != 5000 {
|
||||
t.Fatalf("DailyLimit = %v, want 5000", cfg.DailyLimit)
|
||||
}
|
||||
if cfg.OrderTimeoutMin != 15 {
|
||||
t.Fatalf("OrderTimeoutMin = %v, want 15", cfg.OrderTimeoutMin)
|
||||
}
|
||||
if cfg.MaxPendingOrders != 5 {
|
||||
t.Fatalf("MaxPendingOrders = %v, want 5", cfg.MaxPendingOrders)
|
||||
}
|
||||
if len(cfg.EnabledTypes) != 3 {
|
||||
t.Fatalf("EnabledTypes len = %d, want 3", len(cfg.EnabledTypes))
|
||||
}
|
||||
if cfg.EnabledTypes[0] != "alipay" || cfg.EnabledTypes[1] != "wxpay" || cfg.EnabledTypes[2] != "stripe" {
|
||||
t.Fatalf("EnabledTypes = %v, want [alipay wxpay stripe]", cfg.EnabledTypes)
|
||||
}
|
||||
if !cfg.BalanceDisabled {
|
||||
t.Fatal("expected BalanceDisabled=true")
|
||||
}
|
||||
if cfg.LoadBalanceStrategy != "least_amount" {
|
||||
t.Fatalf("LoadBalanceStrategy = %q, want %q", cfg.LoadBalanceStrategy, "least_amount")
|
||||
}
|
||||
if cfg.ProductNamePrefix != "PRE" {
|
||||
t.Fatalf("ProductNamePrefix = %q, want %q", cfg.ProductNamePrefix, "PRE")
|
||||
}
|
||||
if cfg.ProductNameSuffix != "SUF" {
|
||||
t.Fatalf("ProductNameSuffix = %q, want %q", cfg.ProductNameSuffix, "SUF")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("enabled types with spaces are trimmed", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
vals := map[string]string{
|
||||
SettingEnabledPaymentTypes: " alipay , wxpay ",
|
||||
}
|
||||
cfg := svc.parsePaymentConfig(vals)
|
||||
if len(cfg.EnabledTypes) != 2 {
|
||||
t.Fatalf("EnabledTypes len = %d, want 2", len(cfg.EnabledTypes))
|
||||
}
|
||||
if cfg.EnabledTypes[0] != "alipay" || cfg.EnabledTypes[1] != "wxpay" {
|
||||
t.Fatalf("EnabledTypes = %v, want [alipay wxpay]", cfg.EnabledTypes)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("empty enabled types string", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
vals := map[string]string{
|
||||
SettingEnabledPaymentTypes: "",
|
||||
}
|
||||
cfg := svc.parsePaymentConfig(vals)
|
||||
if len(cfg.EnabledTypes) != 0 {
|
||||
t.Fatalf("expected empty EnabledTypes for empty string, got %v", cfg.EnabledTypes)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetBasePaymentType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Import from the payment package is not needed since GetBasePaymentType
|
||||
// is in a different package. This test covers parsePaymentConfig which
|
||||
// is the core pure function in this service.
|
||||
// Integration tests for DB-dependent methods would go in a separate file.
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PaymentOrderExpiryService periodically expires timed-out payment orders.
|
||||
type PaymentOrderExpiryService struct {
|
||||
paymentSvc *PaymentService
|
||||
interval time.Duration
|
||||
stopCh chan struct{}
|
||||
stopOnce sync.Once
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func NewPaymentOrderExpiryService(paymentSvc *PaymentService, interval time.Duration) *PaymentOrderExpiryService {
|
||||
return &PaymentOrderExpiryService{
|
||||
paymentSvc: paymentSvc,
|
||||
interval: interval,
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PaymentOrderExpiryService) Start() {
|
||||
if s == nil || s.paymentSvc == nil || s.interval <= 0 {
|
||||
return
|
||||
}
|
||||
s.wg.Add(1)
|
||||
go func() {
|
||||
defer s.wg.Done()
|
||||
ticker := time.NewTicker(s.interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
s.runOnce()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
s.runOnce()
|
||||
case <-s.stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *PaymentOrderExpiryService) Stop() {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.stopOnce.Do(func() {
|
||||
close(s.stopCh)
|
||||
})
|
||||
s.wg.Wait()
|
||||
}
|
||||
|
||||
func (s *PaymentOrderExpiryService) runOnce() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
expired, err := s.paymentSvc.ExpireTimedOutOrders(ctx)
|
||||
if err != nil {
|
||||
slog.Error("[PaymentOrderExpiry] failed to expire orders", "error", err)
|
||||
return
|
||||
}
|
||||
if expired > 0 {
|
||||
slog.Info("[PaymentOrderExpiry] expired timed-out orders", "count", expired)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,9 @@ import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
dbent "github.com/Wei-Shaw/sub2api/ent"
|
||||
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||
"github.com/Wei-Shaw/sub2api/internal/payment"
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/logger"
|
||||
"github.com/google/wire"
|
||||
"github.com/redis/go-redis/v9"
|
||||
@@ -460,4 +462,20 @@ var ProviderSet = wire.NewSet(
|
||||
NewGroupCapacityService,
|
||||
NewChannelService,
|
||||
NewModelPricingResolver,
|
||||
ProvidePaymentConfigService,
|
||||
NewPaymentService,
|
||||
ProvidePaymentOrderExpiryService,
|
||||
)
|
||||
|
||||
// ProvidePaymentConfigService wraps NewPaymentConfigService to accept the named
|
||||
// payment.EncryptionKey type instead of raw []byte, avoiding Wire ambiguity.
|
||||
func ProvidePaymentConfigService(entClient *dbent.Client, settingRepo SettingRepository, key payment.EncryptionKey) *PaymentConfigService {
|
||||
return NewPaymentConfigService(entClient, settingRepo, []byte(key))
|
||||
}
|
||||
|
||||
// ProvidePaymentOrderExpiryService creates and starts PaymentOrderExpiryService.
|
||||
func ProvidePaymentOrderExpiryService(paymentSvc *PaymentService) *PaymentOrderExpiryService {
|
||||
svc := NewPaymentOrderExpiryService(paymentSvc, 60*time.Second)
|
||||
svc.Start()
|
||||
return svc
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
CREATE TABLE IF NOT EXISTS payment_orders (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
user_email VARCHAR(255) NOT NULL DEFAULT '',
|
||||
user_name VARCHAR(100) NOT NULL DEFAULT '',
|
||||
user_notes TEXT,
|
||||
amount DECIMAL(20,2) NOT NULL,
|
||||
pay_amount DECIMAL(20,2) NOT NULL,
|
||||
fee_rate DECIMAL(10,4) NOT NULL DEFAULT 0,
|
||||
recharge_code VARCHAR(64) NOT NULL DEFAULT '',
|
||||
payment_type VARCHAR(30) NOT NULL DEFAULT '',
|
||||
payment_trade_no VARCHAR(128) NOT NULL DEFAULT '',
|
||||
pay_url TEXT,
|
||||
qr_code TEXT,
|
||||
qr_code_img TEXT,
|
||||
order_type VARCHAR(20) NOT NULL DEFAULT 'balance',
|
||||
plan_id BIGINT,
|
||||
subscription_group_id BIGINT,
|
||||
subscription_days INT,
|
||||
provider_instance_id VARCHAR(64),
|
||||
status VARCHAR(30) NOT NULL DEFAULT 'PENDING',
|
||||
refund_amount DECIMAL(20,2) NOT NULL DEFAULT 0,
|
||||
refund_reason TEXT,
|
||||
refund_at TIMESTAMPTZ,
|
||||
force_refund BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
refund_requested_at TIMESTAMPTZ,
|
||||
refund_request_reason TEXT,
|
||||
refund_requested_by VARCHAR(20),
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
paid_at TIMESTAMPTZ,
|
||||
completed_at TIMESTAMPTZ,
|
||||
failed_at TIMESTAMPTZ,
|
||||
failed_reason TEXT,
|
||||
client_ip VARCHAR(50) NOT NULL DEFAULT '',
|
||||
src_host VARCHAR(255) NOT NULL DEFAULT '',
|
||||
src_url TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
-- Indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_orders_user_id ON payment_orders(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_orders_status ON payment_orders(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_orders_expires_at ON payment_orders(expires_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_orders_created_at ON payment_orders(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_orders_paid_at ON payment_orders(paid_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_orders_type_paid ON payment_orders(payment_type, paid_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_orders_order_type ON payment_orders(order_type);
|
||||
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE IF NOT EXISTS payment_audit_logs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
order_id VARCHAR(64) NOT NULL,
|
||||
action VARCHAR(50) NOT NULL,
|
||||
detail TEXT NOT NULL DEFAULT '',
|
||||
operator VARCHAR(100) NOT NULL DEFAULT 'system',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_audit_logs_order_id ON payment_audit_logs(order_id);
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Migration 092: payment_channels table was removed before release.
|
||||
-- This file is a no-op placeholder to maintain migration numbering continuity.
|
||||
-- The payment system now uses the existing channels table (migration 081).
|
||||
SELECT 1;
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE IF NOT EXISTS subscription_plans (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
group_id BIGINT NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
price DECIMAL(20,2) NOT NULL,
|
||||
original_price DECIMAL(20,2),
|
||||
validity_days INT NOT NULL DEFAULT 30,
|
||||
validity_unit VARCHAR(10) NOT NULL DEFAULT 'day',
|
||||
features TEXT NOT NULL DEFAULT '',
|
||||
product_name VARCHAR(100) NOT NULL DEFAULT '',
|
||||
for_sale BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_subscription_plans_group_id ON subscription_plans(group_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_subscription_plans_for_sale ON subscription_plans(for_sale);
|
||||
@@ -0,0 +1,15 @@
|
||||
CREATE TABLE IF NOT EXISTS payment_provider_instances (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
provider_key VARCHAR(30) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL DEFAULT '',
|
||||
config TEXT NOT NULL,
|
||||
supported_types VARCHAR(200) NOT NULL DEFAULT '',
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
limits TEXT NOT NULL DEFAULT '',
|
||||
refund_enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_provider_instances_provider_key ON payment_provider_instances(provider_key);
|
||||
CREATE INDEX IF NOT EXISTS idx_payment_provider_instances_enabled ON payment_provider_instances(enabled);
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE channels ADD COLUMN IF NOT EXISTS features TEXT NOT NULL DEFAULT '';
|
||||
COMMENT ON COLUMN channels.features IS '渠道特性描述,JSON 数组格式,用于支付页面展示';
|
||||
@@ -0,0 +1,298 @@
|
||||
# 支付系统 Go 后端实现计划
|
||||
|
||||
> 将 sub2apipay (TypeScript/Prisma) 后端逻辑迁移到 sub2api (Go/Ent)
|
||||
>
|
||||
> 分支: `feature/payment` (基于 upstream `Wei-Shaw/sub2api:main`)
|
||||
|
||||
---
|
||||
|
||||
## 一、新增 Ent Schema (5 个)
|
||||
|
||||
| Schema | 表名 | 说明 |
|
||||
|--------|------|------|
|
||||
| PaymentOrder | payment_orders | 充值/订阅订单 |
|
||||
| PaymentAuditLog | payment_audit_logs | 订单审计日志 |
|
||||
| PaymentChannel | payment_channels | 展示渠道 |
|
||||
| SubscriptionPlan | subscription_plans | 订阅套餐 |
|
||||
| PaymentProviderInstance | payment_provider_instances | 支付服务商实例 |
|
||||
|
||||
所有表使用 `payment_` 前缀避免与现有表冲突。
|
||||
|
||||
### PaymentOrder 字段
|
||||
|
||||
- user_id, user_email, user_name, user_notes
|
||||
- amount(充值额), pay_amount(实付), fee_rate, recharge_code
|
||||
- payment_type, payment_trade_no, pay_url, qr_code, qr_code_img
|
||||
- order_type(balance/subscription), plan_id, subscription_group_id, subscription_days
|
||||
- provider_instance_id
|
||||
- status (PENDING/PAID/RECHARGING/COMPLETED/EXPIRED/CANCELLED/FAILED/REFUND_REQUESTED/REFUNDING/PARTIALLY_REFUNDED/REFUNDED/REFUND_FAILED)
|
||||
- refund_amount, refund_reason, refund_at, force_refund, refund_requested_at, refund_request_reason, refund_requested_by
|
||||
- expires_at, paid_at, completed_at, failed_at, failed_reason
|
||||
- client_ip, src_host, src_url
|
||||
- created_at, updated_at
|
||||
- 索引: user_id, status, expires_at, created_at, paid_at, (payment_type,paid_at), order_type
|
||||
|
||||
### PaymentAuditLog 字段
|
||||
|
||||
- order_id, action, detail, operator, created_at
|
||||
|
||||
### PaymentChannel 字段
|
||||
|
||||
- group_id(关联sub2api Group), name, platform, rate_multiplier, description, models(JSON), features(JSON), sort_order, enabled, created_at, updated_at
|
||||
|
||||
### SubscriptionPlan 字段
|
||||
|
||||
- group_id, name, description, price, original_price, validity_days, validity_unit(day/week/month), features(JSON), product_name, for_sale, sort_order, created_at, updated_at
|
||||
|
||||
### PaymentProviderInstance 字段
|
||||
|
||||
- provider_key(easypay/alipay/wxpay/stripe), name, config(AES加密JSON), supported_types, enabled, sort_order, limits(JSON), refund_enabled, created_at, updated_at
|
||||
|
||||
---
|
||||
|
||||
## 二、Go 接口定义
|
||||
|
||||
### 2.1 Provider 接口
|
||||
|
||||
```go
|
||||
// internal/payment/types.go
|
||||
type Provider interface {
|
||||
Name() string
|
||||
ProviderKey() string
|
||||
SupportedTypes() []PaymentType
|
||||
CreatePayment(ctx context.Context, req CreatePaymentRequest) (*CreatePaymentResponse, error)
|
||||
QueryOrder(ctx context.Context, tradeNo string) (*QueryOrderResponse, error)
|
||||
VerifyNotification(ctx context.Context, body []byte, headers map[string]string) (*PaymentNotification, error)
|
||||
Refund(ctx context.Context, req RefundRequest) (*RefundResponse, error)
|
||||
}
|
||||
|
||||
type CancelableProvider interface {
|
||||
Provider
|
||||
CancelPayment(ctx context.Context, tradeNo string) error
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Registry
|
||||
|
||||
```go
|
||||
// internal/payment/registry.go
|
||||
type Registry struct {
|
||||
providers map[string]Provider // providerKey -> Provider
|
||||
typeMap map[PaymentType]string // paymentType -> providerKey
|
||||
}
|
||||
|
||||
func (r *Registry) Register(p Provider)
|
||||
func (r *Registry) GetProvider(paymentType PaymentType) (Provider, error)
|
||||
func (r *Registry) GetProviderKey(paymentType PaymentType) string
|
||||
func (r *Registry) SupportedTypes() []PaymentType
|
||||
```
|
||||
|
||||
### 2.3 LoadBalancer
|
||||
|
||||
```go
|
||||
// internal/payment/load_balancer.go
|
||||
type LoadBalancer interface {
|
||||
SelectInstance(ctx context.Context, providerKey string, paymentType PaymentType) (*InstanceSelection, error)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、Service 层
|
||||
|
||||
### 3.1 PaymentService — 订单全生命周期
|
||||
|
||||
```go
|
||||
// 直接注入现有 service,不走 HTTP
|
||||
type PaymentService struct {
|
||||
db *ent.Client
|
||||
registry *payment.Registry
|
||||
loadBalancer payment.LoadBalancer
|
||||
redeemService *RedeemService // 余额充值直接调用
|
||||
subscriptionSvc *SubscriptionService // 订阅激活直接调用
|
||||
adminService AdminService // 余额扣减
|
||||
configService *PaymentConfigService
|
||||
}
|
||||
|
||||
// 订单
|
||||
CreateOrder / GetOrder / GetUserOrders / CancelOrder / AdminCancelOrder
|
||||
// 支付确认 & 履约
|
||||
HandlePaymentNotification / ExecuteBalanceFulfillment / ExecuteSubscriptionFulfillment / RetryFulfillment
|
||||
// 退款三阶段
|
||||
RequestRefund / PrepareRefund / ExecuteRefund / RollbackRefund
|
||||
// 超时
|
||||
ExpireTimedOutOrders
|
||||
// 统计
|
||||
GetDashboardStats
|
||||
```
|
||||
|
||||
### 3.2 PaymentConfigService — 配置 & CRUD
|
||||
|
||||
```go
|
||||
type PaymentConfigService struct {
|
||||
db *ent.Client
|
||||
settingService *SettingService // 复用现有 Setting 表
|
||||
encryptionKey []byte
|
||||
}
|
||||
|
||||
// 系统配置
|
||||
IsPaymentEnabled / GetPaymentConfig / UpdatePaymentConfig
|
||||
// 服务商实例 CRUD
|
||||
ListProviderInstances / CreateProviderInstance / UpdateProviderInstance / DeleteProviderInstance
|
||||
// 渠道 CRUD
|
||||
ListChannels / CreateChannel / UpdateChannel / DeleteChannel
|
||||
// 套餐 CRUD
|
||||
ListPlans / CreatePlan / UpdatePlan / DeletePlan
|
||||
// 手续费 & 限额
|
||||
GetMethodLimits / CalculatePayAmount
|
||||
```
|
||||
|
||||
### 3.3 关键差异 vs sub2apipay
|
||||
|
||||
| 维度 | sub2apipay (TS) | sub2api (Go) |
|
||||
|------|-----------------|-------------|
|
||||
| 余额充值 | HTTP 调 sub2api API | 直接调 RedeemService |
|
||||
| 订阅激活 | HTTP 调 sub2api API | 直接调 SubscriptionService |
|
||||
| 用户验证 | HTTP 调 /api/v1/auth/me | JWT middleware 已处理 |
|
||||
| Decimal | Prisma.Decimal | shopspring/decimal |
|
||||
| 加密 | Node.js crypto | Go crypto/aes + cipher |
|
||||
| 配置存储 | SystemConfig 表 | 复用现有 Setting 表 |
|
||||
|
||||
---
|
||||
|
||||
## 四、Handler 层 & API 端点
|
||||
|
||||
### 4.1 用户端 (9 个)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | /api/v1/payment/config | 支付配置 |
|
||||
| GET | /api/v1/payment/plans | 套餐列表 |
|
||||
| GET | /api/v1/payment/channels | 渠道列表 |
|
||||
| GET | /api/v1/payment/limits | 支付方式限额 |
|
||||
| POST | /api/v1/payment/orders | 创建订单 |
|
||||
| GET | /api/v1/payment/orders/my | 用户订单列表 |
|
||||
| GET | /api/v1/payment/orders/:id | 订单详情 |
|
||||
| POST | /api/v1/payment/orders/:id/cancel | 取消订单 |
|
||||
| POST | /api/v1/payment/orders/:id/refund-request | 申请退款 |
|
||||
|
||||
### 4.2 Webhook (4 个,无需认证)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | /api/v1/payment/webhook/easypay | EasyPay 回调 |
|
||||
| POST | /api/v1/payment/webhook/alipay | 支付宝回调 |
|
||||
| POST | /api/v1/payment/webhook/wxpay | 微信支付回调 |
|
||||
| POST | /api/v1/payment/webhook/stripe | Stripe Webhook |
|
||||
|
||||
### 4.3 管理端 (18 个)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | /admin/payment/dashboard | 仪表盘 |
|
||||
| GET | /admin/payment/orders | 订单列表 |
|
||||
| GET | /admin/payment/orders/:id | 订单详情 |
|
||||
| POST | /admin/payment/orders/:id/cancel | 取消订单 |
|
||||
| POST | /admin/payment/orders/:id/retry | 重试充值 |
|
||||
| POST | /admin/payment/orders/:id/refund | 处理退款 |
|
||||
| GET/POST | /admin/payment/channels | 渠道列表/创建 |
|
||||
| PUT/DELETE | /admin/payment/channels/:id | 更新/删除 |
|
||||
| GET/POST | /admin/payment/plans | 套餐列表/创建 |
|
||||
| PUT/DELETE | /admin/payment/plans/:id | 更新/删除 |
|
||||
| GET/POST | /admin/payment/providers | 实例列表/创建 |
|
||||
| PUT/DELETE | /admin/payment/providers/:id | 更新/删除 |
|
||||
|
||||
---
|
||||
|
||||
## 五、Provider 实现
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
internal/payment/
|
||||
├── types.go, registry.go, load_balancer.go, fee.go, crypto.go, wire.go
|
||||
├── provider_factory.go
|
||||
└── provider/
|
||||
├── easypay.go # 纯 HTTP + MD5 (无需 SDK)
|
||||
├── alipay.go # smartwalle/alipay/v3 SDK
|
||||
├── wxpay.go # wechatpay-apiv3/wechatpay-go 官方 SDK
|
||||
└── stripe.go # stripe/stripe-go 官方 SDK
|
||||
```
|
||||
|
||||
### Go 依赖
|
||||
|
||||
| 包 | 用途 |
|
||||
|----|------|
|
||||
| github.com/stripe/stripe-go/v82 | Stripe 官方 |
|
||||
| github.com/wechatpay-apiv3/wechatpay-go | 微信支付官方 |
|
||||
| github.com/smartwalle/alipay/v3 | 支付宝 |
|
||||
| github.com/shopspring/decimal | 精确十进制 |
|
||||
|
||||
---
|
||||
|
||||
## 六、数据库迁移 (5 个 SQL 文件)
|
||||
|
||||
```
|
||||
migrations/090_payment_orders.sql
|
||||
migrations/091_payment_audit_logs.sql
|
||||
migrations/092_payment_channels.sql
|
||||
migrations/093_subscription_plans.sql
|
||||
migrations/094_payment_provider_instances.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、Wire DI
|
||||
|
||||
```go
|
||||
// internal/payment/wire.go
|
||||
var ProviderSet = wire.NewSet(
|
||||
NewRegistry, NewLoadBalancer,
|
||||
NewPaymentConfigService, NewPaymentService,
|
||||
NewPaymentHandler, NewPaymentAdminHandler, NewPaymentWebhookHandler,
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、路由注册
|
||||
|
||||
```go
|
||||
// internal/server/routes/payment.go
|
||||
func RegisterPaymentRoutes(v1 *gin.RouterGroup, h *handler.Handlers, jwtAuth, adminAuth middleware)
|
||||
```
|
||||
|
||||
在 router.go 的 registerRoutes() 中新增:
|
||||
```go
|
||||
routes.RegisterPaymentRoutes(v1, h, jwtAuth, adminAuth)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、新增文件清单 (~25 个 Go + 5 个 SQL)
|
||||
|
||||
**payment 核心 (8)**:
|
||||
- internal/payment/types.go, registry.go, load_balancer.go
|
||||
- internal/payment/fee.go, crypto.go, wire.go, provider_factory.go
|
||||
|
||||
**provider 实现 (4)**:
|
||||
- internal/payment/provider/easypay.go, alipay.go, wxpay.go, stripe.go
|
||||
|
||||
**service (2)**:
|
||||
- internal/service/payment_service.go, payment_config_service.go
|
||||
|
||||
**handler (3)**:
|
||||
- internal/handler/payment_handler.go, payment_webhook_handler.go
|
||||
- internal/handler/admin/payment_handler.go
|
||||
|
||||
**routes (1)**:
|
||||
- internal/server/routes/payment.go
|
||||
|
||||
**schema (5)**:
|
||||
- ent/schema/payment_order.go, payment_audit_log.go, payment_channel.go
|
||||
- ent/schema/subscription_plan.go, payment_provider_instance.go
|
||||
|
||||
**migration (5)**:
|
||||
- migrations/090-094
|
||||
|
||||
**Ent generate**: 运行 `go generate ./ent` 生成 CRUD 代码
|
||||
@@ -0,0 +1,730 @@
|
||||
# 支付系统前端迁移计划
|
||||
|
||||
> 将 sub2apipay (Next.js/React) 的支付功能原生集成到 sub2api (Vue3) 前端中
|
||||
>
|
||||
> 分支: `feature/payment` (基于 upstream `Wei-Shaw/sub2api:main`)
|
||||
|
||||
---
|
||||
|
||||
## 一、迁移概述
|
||||
|
||||
### 1.1 现状
|
||||
|
||||
当前 sub2api 通过 **iframe 嵌入外部 URL** 的方式提供充值/订阅功能:
|
||||
|
||||
- 管理员在 `系统设置 → General tab` 中配置 `purchase_subscription_url`
|
||||
- 用户侧边栏出现"充值/订阅"菜单项(受 `purchase_subscription_enabled` 控制)
|
||||
- 点击后在 `PurchaseSubscriptionView.vue` 中以 iframe 加载外部页面
|
||||
- 外部页面(sub2apipay)通过 URL 参数接收 `user_id`, `token`, `theme`, `lang`
|
||||
|
||||
**现有关键文件:**
|
||||
|
||||
| 文件 | 作用 |
|
||||
|------|------|
|
||||
| `src/components/layout/AppSidebar.vue` | 侧边栏菜单定义(~700行) |
|
||||
| `src/views/user/PurchaseSubscriptionView.vue` | iframe 嵌入页(~159行��� |
|
||||
| `src/views/admin/SettingsView.vue` | 管理后台设置页(~2500行) |
|
||||
| `src/stores/app.ts` | 公共设置存储(含 `purchase_subscription_enabled`) |
|
||||
| `src/stores/adminSettings.ts` | 管理设置存储 |
|
||||
| `src/router/index.ts` | 路由定义 |
|
||||
| `src/i18n/locales/en.ts` / `zh.ts` | 国际化文本 |
|
||||
| `src/utils/embedded-url.ts` | iframe URL 构建工具 |
|
||||
|
||||
### 1.2 目标
|
||||
|
||||
将 sub2apipay 的所有前端功能原生实现为 Vue3 组件,集成到 sub2api 项目中:
|
||||
|
||||
- **消除 iframe** — 所有支付、订单页面变为原生 Vue 组件
|
||||
- **消除外部依赖** — 不再需要独立部署 sub2apipay
|
||||
- **直接调用后端 API** — 替代 HTTP 跨域调用
|
||||
- **统一认证** — 复用 sub2api 的 JWT 认证,无需 URL 传 token
|
||||
- **统一 UI** — 使用 sub2api 现有的 TailwindCSS 设计系统和组件库
|
||||
|
||||
---
|
||||
|
||||
## 二、菜单结构变更
|
||||
|
||||
### 2.1 管理员侧边栏 (`adminNavItems`)
|
||||
|
||||
**当前菜单(upstream main):**
|
||||
|
||||
```
|
||||
仪表盘 /admin/dashboard
|
||||
运维监控 /admin/ops (ops_monitoring_enabled 控制)
|
||||
用户管理 /admin/users
|
||||
分组管理 /admin/groups
|
||||
渠道管理 /admin/channels
|
||||
订阅管理 /admin/subscriptions
|
||||
账号管理 /admin/accounts
|
||||
公告管理 /admin/announcements
|
||||
代理管理 /admin/proxies
|
||||
充值码管理 /admin/redeem
|
||||
推广码管理 /admin/promo-codes
|
||||
用量统计 /admin/usage
|
||||
系统设置 /admin/settings
|
||||
[自定义菜单]
|
||||
```
|
||||
|
||||
**迁移后菜单:**
|
||||
|
||||
```
|
||||
仪表盘 /admin/dashboard
|
||||
运维监控 /admin/ops (ops_monitoring_enabled 控制)
|
||||
用户管理 /admin/users
|
||||
分组管理 /admin/groups
|
||||
渠道管理 /admin/channels
|
||||
订阅管理 /admin/subscriptions
|
||||
账号管理 /admin/accounts
|
||||
公告管理 /admin/announcements
|
||||
代理管理 /admin/proxies
|
||||
充值码管理 /admin/redeem
|
||||
推广码管理 /admin/promo-codes
|
||||
+ 订单管理 /admin/orders ← 新增(payment_enabled 控制可见性)
|
||||
用量统计 /admin/usage
|
||||
系统设置 /admin/settings
|
||||
[自定义菜单]
|
||||
```
|
||||
|
||||
**新增"订单管理"菜单及子菜单:**
|
||||
|
||||
"订单管理"作为一级菜单项,点击后页面内部提供 tab 导航:
|
||||
|
||||
| 子菜单 | 路由 | 说明 |
|
||||
|--------|------|------|
|
||||
| 订单概览 | `/admin/orders` | 订单统计仪表盘(日收入、支付方式分布、排行榜) |
|
||||
| 订单列表 | `/admin/orders/list` | 订单搜索/筛选/详情/退款操作 |
|
||||
| 渠道管理 | `/admin/orders/channels` | 支付渠道定义(展示名称、倍率、描述) |
|
||||
| 订阅套餐 | `/admin/orders/plans` | 订阅计划管理(价格、有效期、分组绑定) |
|
||||
|
||||
> **可见性规则**: 仅当系统设置中"充值/订阅功能"开启时,"订单管理"菜单才可见。
|
||||
|
||||
### 2.2 用户侧边栏 (`userNavItems`)
|
||||
|
||||
**当前菜单:**
|
||||
|
||||
```
|
||||
仪表盘 /dashboard
|
||||
API密钥 /keys
|
||||
用量统计 /usage
|
||||
我的订阅 /subscriptions
|
||||
[Sora] /sora (sora_client_enabled 控制)
|
||||
[充值/订阅] /purchase (purchase_subscription_enabled 控制, iframe)
|
||||
兑换码 /redeem
|
||||
个人设置 /profile
|
||||
[自定义菜单]
|
||||
```
|
||||
|
||||
**迁移后菜单:**
|
||||
|
||||
```
|
||||
仪表盘 /dashboard
|
||||
API密钥 /keys
|
||||
用量统计 /usage
|
||||
我的订阅 /subscriptions
|
||||
[Sora] /sora (sora_client_enabled 控制)
|
||||
- [充值/订阅] /purchase ← 替换: 不再是 iframe
|
||||
+ 充值/订阅 /purchase ← 原生 Vue 页面(payment_enabled 控制)
|
||||
+ 我的订单 /orders ← 新增(payment_enabled 控制)
|
||||
兑换码 /redeem
|
||||
个人设置 /profile
|
||||
[自定义菜单]
|
||||
```
|
||||
|
||||
**变更要点:**
|
||||
|
||||
1. `/purchase` 路由保持不变,但组件从 iframe 替换为原生 `PaymentView.vue`
|
||||
2. 新增 `/orders` 路由 — "我的订单"页面
|
||||
3. 菜单可见性条件从 `purchase_subscription_enabled` 变更为 `payment_enabled`
|
||||
4. 移除 `purchase_subscription_url` 设置项
|
||||
|
||||
### 2.3 管理员"我的账户"区域 (`personalNavItems`)
|
||||
|
||||
与 `userNavItems` 保持一致的变更:增加"我的订单",替换"充值/订阅"为原生页面。
|
||||
|
||||
---
|
||||
|
||||
## 三、系统设置变更
|
||||
|
||||
### 3.1 Settings Tab 变更
|
||||
|
||||
**当前 tabs:**
|
||||
|
||||
```
|
||||
general | security | users | gateway | email | backup | data
|
||||
```
|
||||
|
||||
**迁移后 tabs:**
|
||||
|
||||
```
|
||||
general | security | users | gateway | payment | email | backup | data
|
||||
```
|
||||
|
||||
新增 **`payment`** tab,在 `gateway` 之后、`email` 之前。
|
||||
|
||||
### 3.2 `payment` Tab 内容
|
||||
|
||||
此 tab 替代原 `general` tab 中的"充值/订阅页面"配置区块。
|
||||
|
||||
**配置项设计:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 充值/订阅功能 │
|
||||
│ ───────────────────────────────────── │
|
||||
│ 启用充值/订阅 [Toggle] │
|
||||
│ 说明: 开启后用户可通过在线支付充值余额或购买订阅。 │
|
||||
│ 同时"订单管理"菜单将对管理员可见。 │
|
||||
│ │
|
||||
│ (以下配置仅在功能启用后显示) │
|
||||
│ │
|
||||
│ ┌─ 基本设置 ──────────────────────────────────────────┐ │
|
||||
│ │ 最低充值金额 [___] 元 │ │
|
||||
│ │ 最高充值金额 [___] 元 │ │
|
||||
│ │ 每日充值限额 [___] 元 │ │
|
||||
│ │ 最大待支付订单数 [___] │ │
|
||||
│ │ 订单超时时间 [___] 分钟 │ │
|
||||
│ │ 禁用余额支付 [Toggle] │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ 支付服务商 ────────────────────────────────────────┐ │
|
||||
│ │ 启用的支付方式 [☑ 支付宝] [☑ 微信支付] [☑ Stripe] │ │
|
||||
│ │ │ │
|
||||
│ │ 服务商实例管理 [管理实例 →] │ │
|
||||
│ │ (跳转到服务商实例配置子页面) │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ 显示设置 ──────────────────────────────────────────┐ │
|
||||
│ │ 帮助图片 URL [___] │ │
|
||||
│ │ 帮助文字 [___] │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.3 从 `general` Tab 移除的内容
|
||||
|
||||
原 `general` tab 中的以下配置区块将移除:
|
||||
|
||||
- **"Recharge / Subscription Page"** 整个 card
|
||||
|
||||
### 3.4 旧版兼容:自定义页面迁移
|
||||
|
||||
对于已使用 `purchase_subscription_url` 配置外部支付页面的用户:
|
||||
|
||||
- 数据库迁移脚本检查 `purchase_subscription_url` 是否有值
|
||||
- 若有值,自动创建一个"自定义菜单页面" (custom_menu_item),保留原 URL
|
||||
- 确保旧版用户升级后,原来的外部支付页面仍可通过自定义菜单访问
|
||||
- `purchase_subscription_enabled` 和 `purchase_subscription_url` 设置项保留但标记 deprecated
|
||||
|
||||
---
|
||||
|
||||
## 四、路由变更
|
||||
|
||||
### 4.1 新增路由
|
||||
|
||||
| 路由 | 组件 | 权限 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `/purchase` | `PaymentView.vue` | requiresAuth | 替换原 iframe 页面 |
|
||||
| `/orders` | `UserOrdersView.vue` | requiresAuth | 用户订单列表 |
|
||||
| `/admin/orders` | `AdminOrdersView.vue` | requiresAdmin | 订单概览(默认 tab) |
|
||||
| `/admin/orders/list` | 同上组件内 tab | requiresAdmin | 订单列表 |
|
||||
| `/admin/orders/channels` | 同上组件内 tab | requiresAdmin | 渠道管理 |
|
||||
| `/admin/orders/plans` | 同上组件内 tab | requiresAdmin | 订阅套餐管理 |
|
||||
| `/admin/orders/providers` | `AdminProvidersView.vue` | requiresAdmin | 服务商实例管理 |
|
||||
|
||||
### 4.2 路由 meta
|
||||
|
||||
所有支付相关路由需要 meta 字段:
|
||||
|
||||
```typescript
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
requiresPayment: true, // 新增: 需要 payment_enabled
|
||||
}
|
||||
```
|
||||
|
||||
路由守卫检查:若 `requiresPayment && !payment_enabled`,重定向到 dashboard。
|
||||
|
||||
---
|
||||
|
||||
## 五、新增 Vue 组件清单
|
||||
|
||||
### 5.1 用户侧页面
|
||||
|
||||
#### 5.1.1 `PaymentView.vue` — 充值/订阅主页面
|
||||
|
||||
**替换**: `PurchaseSubscriptionView.vue`(iframe)
|
||||
|
||||
**来源**: sub2apipay `PaymentForm.tsx` + `PurchaseFlow.tsx` + `TopUpModal.tsx`
|
||||
|
||||
**功能**:
|
||||
- 金额输入(自定义 + 快捷按钮)
|
||||
- 支付方式选择(动态展示)
|
||||
- 手续费实时计算
|
||||
- 余额支付开关
|
||||
- 订阅套餐选购(卡片 + 确认弹窗)
|
||||
- 创建订单后跳转支付流程
|
||||
|
||||
**子组件**: `PaymentMethodSelector.vue`, `AmountInput.vue`, `FeeDisplay.vue`, `SubscriptionPlanCard.vue`, `SubscriptionConfirmModal.vue`
|
||||
|
||||
**API**: `GET /api/v1/payment/config`, `GET /api/v1/payment/plans`, `POST /api/v1/payment/orders`
|
||||
|
||||
#### 5.1.2 `PaymentQRCodeView.vue` — 二维码支付页
|
||||
|
||||
**来源**: sub2apipay `PaymentQRCode.tsx`
|
||||
|
||||
**功能**: 二维码显示、倒计时、轮询状态(3s)、支付成功自动跳转
|
||||
|
||||
**子组件**: `QRCodeDisplay.vue`, `CountdownTimer.vue`
|
||||
|
||||
**API**: `GET /api/v1/payment/orders/:id`
|
||||
|
||||
#### 5.1.3 `StripePaymentView.vue` — Stripe 支付页
|
||||
|
||||
**来源**: sub2apipay `stripe-popup/page.tsx`
|
||||
|
||||
**功能**: Stripe Payment Element 集成,使用 `clientSecret` 完成支付
|
||||
|
||||
**依赖**: `@stripe/stripe-js`
|
||||
|
||||
#### 5.1.4 `PaymentResultView.vue` — 支付结果页
|
||||
|
||||
**功能**: 成功/失败状态展示、订单摘要、跳转按钮
|
||||
|
||||
#### 5.1.5 `UserOrdersView.vue` — 我的订单
|
||||
|
||||
**来源**: sub2apipay `OrderTable.tsx` + `MobileOrderList.tsx` + `OrderFilterBar.tsx`
|
||||
|
||||
**功能**: 订单列表(分页、状态筛选、日期范围)、取消/退款操作
|
||||
|
||||
**子组件**: `OrderStatusBadge.vue`, `OrderFilterBar.vue`
|
||||
|
||||
**API**: `GET /api/v1/payment/orders/my`, `POST .../cancel`, `POST .../refund-request`
|
||||
|
||||
### 5.2 管理员侧页面
|
||||
|
||||
#### 5.2.1 `AdminOrdersView.vue` — 订单管理(tab 容器)
|
||||
|
||||
页面内 tab 导航:订单概览 | 订单列表 | 渠道管理 | 订阅套餐
|
||||
|
||||
**订单概览 tab**:
|
||||
- 统计卡片(今日/总收入、订单数、均价)
|
||||
- 每日收入趋势图(Chart.js)
|
||||
- 支付方式分布饼图
|
||||
- 充值排行榜
|
||||
|
||||
**子组件**: `OrderStatsCards.vue`, `DailyRevenueChart.vue`, `PaymentMethodChart.vue`, `TopUsersLeaderboard.vue`
|
||||
|
||||
**API**: `GET /api/v1/admin/payment/dashboard`
|
||||
|
||||
#### 5.2.2 订单列表 tab
|
||||
|
||||
**来源**: sub2apipay `admin/orders/page.tsx` + `admin/OrderTable.tsx` + `admin/OrderDetail.tsx` + `admin/RefundDialog.tsx`
|
||||
|
||||
**功能**: 全量订单搜索/筛选、详情面板、管理操作(取消/重试/退款)
|
||||
|
||||
**子组件**: `AdminOrderTable.vue`, `AdminOrderDetail.vue`, `AdminRefundDialog.vue`, `AdminOrderSearchBar.vue`
|
||||
|
||||
**API**: `GET/POST .../admin/payment/orders`, `.../cancel`, `.../retry`, `.../refund`
|
||||
|
||||
#### 5.2.3 渠道管理 tab
|
||||
|
||||
**来源**: sub2apipay `admin/channels/page.tsx` + `ChannelCard.tsx`
|
||||
|
||||
**功能**: 渠道 CRUD(名称、关联 Group、费率、描述、启/禁用)
|
||||
|
||||
**API**: `GET/POST/PUT/DELETE /api/v1/admin/payment/channels`
|
||||
|
||||
#### 5.2.4 订阅套餐 tab
|
||||
|
||||
**来源**: sub2apipay `admin/subscriptions/page.tsx`
|
||||
|
||||
**功能**: 套餐 CRUD(名称、价格、有效期、分组绑定、上架状态)
|
||||
|
||||
**API**: `GET/POST/PUT/DELETE /api/v1/admin/payment/plans`
|
||||
|
||||
#### 5.2.5 `AdminProvidersView.vue` — 服务商实例管理
|
||||
|
||||
**来源**: sub2apipay `admin/payment-config/page.tsx`(1479 行,最大单组件)
|
||||
|
||||
**功能**: 服务商实例 CRUD,动态配置表单(EasyPay/Alipay/Wxpay/Stripe),限额配置,退款开关
|
||||
|
||||
**路由**: `/admin/orders/providers`(从系统设置 payment tab "管理实例"按钮跳转)
|
||||
|
||||
**子组件**: `ProviderInstanceForm.vue`, `ProviderInstanceCard.vue`
|
||||
|
||||
**API**: `GET/POST/PUT/DELETE /api/v1/admin/payment/providers`
|
||||
|
||||
### 5.3 共享组件
|
||||
|
||||
| 组件 | 用途 |
|
||||
|------|------|
|
||||
| `PaymentMethodSelector.vue` | 支付方式选择 |
|
||||
| `AmountInput.vue` | 金额输入(含快捷按钮) |
|
||||
| `FeeDisplay.vue` | 手续费展示 |
|
||||
| `QRCodeDisplay.vue` | 二维码渲染 |
|
||||
| `CountdownTimer.vue` | 倒计时 |
|
||||
| `OrderStatusBadge.vue` | 订单状态标签 |
|
||||
| `OrderFilterBar.vue` | 订单筛选栏 |
|
||||
| `SubscriptionPlanCard.vue` | 套餐卡片 |
|
||||
| `SubscriptionConfirmModal.vue` | 套餐确认弹窗 |
|
||||
|
||||
---
|
||||
|
||||
## 六、Store 变更
|
||||
|
||||
### 6.1 `appStore` 变更
|
||||
|
||||
**publicSettings 字段变更**:
|
||||
```typescript
|
||||
// deprecated:
|
||||
purchase_subscription_enabled: boolean
|
||||
purchase_subscription_url: string
|
||||
|
||||
// 新增:
|
||||
payment_enabled: boolean // 充值/订阅功能总开关
|
||||
```
|
||||
|
||||
### 6.2 新增 `paymentStore`
|
||||
|
||||
```typescript
|
||||
// src/stores/payment.ts
|
||||
defineStore('payment', () => {
|
||||
const config = ref<PaymentConfig | null>(null)
|
||||
const currentOrder = ref<Order | null>(null)
|
||||
const plans = ref<SubscriptionPlan[]>([])
|
||||
|
||||
async function fetchConfig(): Promise<PaymentConfig>
|
||||
async function fetchPlans(): Promise<SubscriptionPlan[]>
|
||||
async function createOrder(params): Promise<Order>
|
||||
async function pollOrderStatus(orderId: string): Promise<OrderStatus>
|
||||
})
|
||||
```
|
||||
|
||||
### 6.3 `adminSettingsStore` 变更
|
||||
|
||||
新增: `paymentEnabled` — 控制管理侧"订单管理"菜单可见性。
|
||||
|
||||
---
|
||||
|
||||
## 七、API 模块新增
|
||||
|
||||
### 7.1 用户 API (`src/api/payment.ts`)
|
||||
|
||||
```typescript
|
||||
export const paymentAPI = {
|
||||
getConfig(): Promise<PaymentConfig>
|
||||
getPlans(): Promise<SubscriptionPlan[]>
|
||||
createOrder(params): Promise<CreateOrderResult>
|
||||
getOrder(orderId): Promise<Order>
|
||||
getMyOrders(params): Promise<PaginatedResult<Order>>
|
||||
cancelOrder(orderId): Promise<void>
|
||||
requestRefund(orderId, reason): Promise<void>
|
||||
getLimits(): Promise<MethodLimits>
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 管理 API (`src/api/admin/payment.ts`)
|
||||
|
||||
```typescript
|
||||
export const adminPaymentAPI = {
|
||||
// 仪表盘
|
||||
getDashboard(days?): Promise<DashboardStats>
|
||||
// 订单
|
||||
getOrders(params): Promise<PaginatedResult<Order>>
|
||||
getOrder(orderId): Promise<OrderDetail>
|
||||
cancelOrder(orderId): Promise<void>
|
||||
retryRecharge(orderId): Promise<void>
|
||||
refundOrder(orderId, params): Promise<RefundResult>
|
||||
// 渠道
|
||||
getChannels(): Promise<Channel[]>
|
||||
createChannel(data): Promise<Channel>
|
||||
updateChannel(id, data): Promise<Channel>
|
||||
deleteChannel(id): Promise<void>
|
||||
// 订阅套餐
|
||||
getPlans(): Promise<SubscriptionPlan[]>
|
||||
createPlan(data): Promise<SubscriptionPlan>
|
||||
updatePlan(id, data): Promise<SubscriptionPlan>
|
||||
deletePlan(id): Promise<void>
|
||||
// 服务商实例
|
||||
getProviders(): Promise<ProviderInstance[]>
|
||||
createProvider(data): Promise<ProviderInstance>
|
||||
updateProvider(id, data): Promise<ProviderInstance>
|
||||
deleteProvider(id): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、i18n 变更
|
||||
|
||||
### 8.1 新增 `payment` 命名空间
|
||||
|
||||
```typescript
|
||||
payment: {
|
||||
// 充值页面
|
||||
title: '充值/订阅', // 'Recharge / Subscription'
|
||||
amountLabel: '充值金额',
|
||||
quickAmounts: '快捷金额',
|
||||
customAmount: '自定义金额',
|
||||
paymentMethod: '支付方式',
|
||||
fee: '手续费',
|
||||
actualPay: '实付金额',
|
||||
createOrder: '确认支付',
|
||||
|
||||
methods: {
|
||||
alipay: '支付宝',
|
||||
wxpay: '微信支付',
|
||||
stripe: 'Stripe',
|
||||
alipay_direct: '支付宝(直连)',
|
||||
wxpay_direct: '微信支付(直连)',
|
||||
},
|
||||
|
||||
status: {
|
||||
pending: '待支付',
|
||||
paid: '已支付',
|
||||
recharging: '充值中',
|
||||
completed: '已完成',
|
||||
expired: '已过期',
|
||||
cancelled: '已取消',
|
||||
failed: '失败',
|
||||
refund_requested: '退款申请中',
|
||||
refunding: '退款中',
|
||||
refunded: '已退款',
|
||||
partially_refunded: '部分退款',
|
||||
refund_failed: '退款失败',
|
||||
},
|
||||
|
||||
qr: {
|
||||
scanToPay: '请扫码支付',
|
||||
expiresIn: '剩余支付时间',
|
||||
expired: '订单已过期',
|
||||
},
|
||||
|
||||
orders: {
|
||||
title: '我的订单',
|
||||
empty: '暂无订单',
|
||||
orderId: '订单号',
|
||||
amount: '金额',
|
||||
payAmount: '实付',
|
||||
status: '状态',
|
||||
paymentMethod: '支付方式',
|
||||
createdAt: '创建时间',
|
||||
cancel: '取消订单',
|
||||
requestRefund: '申请退款',
|
||||
},
|
||||
|
||||
result: {
|
||||
success: '支付成功',
|
||||
failed: '支付失败',
|
||||
backToRecharge: '返回充值',
|
||||
viewOrders: '查看订单',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 修改的 i18n 键
|
||||
|
||||
```typescript
|
||||
nav: {
|
||||
myOrders: '我的订单', // 'My Orders'
|
||||
orderManagement: '订单管理', // 'Order Management'
|
||||
}
|
||||
|
||||
admin.settings.tabs: {
|
||||
payment: '充值/订阅', // 'Recharge / Subscription'
|
||||
}
|
||||
|
||||
admin.settings.payment: {
|
||||
title: '充值/订阅功能',
|
||||
description: '配置在线支付充值和订阅购买功能',
|
||||
enabled: '启用充值/订阅',
|
||||
enabledHint: '开启后用户可通过在线支付充值余额或购买订阅',
|
||||
minAmount: '最低充值金额',
|
||||
maxAmount: '最高充值金额',
|
||||
dailyLimit: '每日充值限额',
|
||||
maxPendingOrders: '最大待支付订单数',
|
||||
orderTimeout: '订单超时时间(分钟)',
|
||||
balancePaymentDisabled: '禁用余额支付',
|
||||
enabledPaymentTypes: '启用的支付方式',
|
||||
manageProviders: '管理服务商实例',
|
||||
helpImageUrl: '帮助图片 URL',
|
||||
helpText: '帮助文字',
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 Deprecated i18n 键
|
||||
|
||||
保留但不再使用:`admin.settings.purchase.*`, `purchase.*`
|
||||
|
||||
---
|
||||
|
||||
## 九、文件变更清单
|
||||
|
||||
### 9.1 修改的现有文件
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `src/components/layout/AppSidebar.vue` | 新增菜单项,条件改为 `payment_enabled` |
|
||||
| `src/router/index.ts` | 新增路由,修改 `/purchase` 组件 |
|
||||
| `src/views/admin/SettingsView.vue` | 新增 `payment` tab,移除旧 purchase 配置 |
|
||||
| `src/stores/app.ts` | publicSettings 新增 `payment_enabled` |
|
||||
| `src/stores/adminSettings.ts` | 新增 `paymentEnabled` |
|
||||
| `src/stores/index.ts` | 导出新 store |
|
||||
| `src/i18n/locales/en.ts` | 新增 payment 命名空间 |
|
||||
| `src/i18n/locales/zh.ts` | 新增 payment 命名空间 |
|
||||
| `src/api/index.ts` | 导出新 API 模块 |
|
||||
| `src/types/index.ts` | 新增 payment 类型 |
|
||||
|
||||
### 9.2 新增文件
|
||||
|
||||
**视图 (10 个)**:
|
||||
- `src/views/user/PaymentView.vue`
|
||||
- `src/views/user/PaymentQRCodeView.vue`
|
||||
- `src/views/user/StripePaymentView.vue`
|
||||
- `src/views/user/PaymentResultView.vue`
|
||||
- `src/views/user/UserOrdersView.vue`
|
||||
- `src/views/admin/orders/AdminOrdersView.vue`
|
||||
- `src/views/admin/orders/AdminOrderListView.vue`
|
||||
- `src/views/admin/orders/AdminOrderChannelsView.vue`
|
||||
- `src/views/admin/orders/AdminOrderPlansView.vue`
|
||||
- `src/views/admin/orders/AdminProvidersView.vue`
|
||||
|
||||
**组件 (19 个)**:
|
||||
- `src/components/payment/PaymentMethodSelector.vue`
|
||||
- `src/components/payment/AmountInput.vue`
|
||||
- `src/components/payment/FeeDisplay.vue`
|
||||
- `src/components/payment/QRCodeDisplay.vue`
|
||||
- `src/components/payment/CountdownTimer.vue`
|
||||
- `src/components/payment/OrderStatusBadge.vue`
|
||||
- `src/components/payment/OrderFilterBar.vue`
|
||||
- `src/components/payment/SubscriptionPlanCard.vue`
|
||||
- `src/components/payment/SubscriptionConfirmModal.vue`
|
||||
- `src/components/admin/payment/OrderStatsCards.vue`
|
||||
- `src/components/admin/payment/DailyRevenueChart.vue`
|
||||
- `src/components/admin/payment/PaymentMethodChart.vue`
|
||||
- `src/components/admin/payment/TopUsersLeaderboard.vue`
|
||||
- `src/components/admin/payment/AdminOrderTable.vue`
|
||||
- `src/components/admin/payment/AdminOrderDetail.vue`
|
||||
- `src/components/admin/payment/AdminRefundDialog.vue`
|
||||
- `src/components/admin/payment/AdminOrderSearchBar.vue`
|
||||
- `src/components/admin/payment/ProviderInstanceForm.vue`
|
||||
- `src/components/admin/payment/ProviderInstanceCard.vue`
|
||||
|
||||
**API / Store / Types (4 个)**:
|
||||
- `src/api/payment.ts`
|
||||
- `src/api/admin/payment.ts`
|
||||
- `src/stores/payment.ts`
|
||||
- `src/types/payment.ts`
|
||||
|
||||
### 9.3 删除的文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `src/views/user/PurchaseSubscriptionView.vue` | 替换为 `PaymentView.vue` |
|
||||
| `src/utils/embedded-url.ts` | 不再需要 iframe URL 构建 |
|
||||
|
||||
### 9.4 新增依赖
|
||||
|
||||
| 包 | 用途 |
|
||||
|----|------|
|
||||
| `@stripe/stripe-js` | Stripe Payment Element |
|
||||
| `qrcode` | 二维码渲染(已有此依赖) |
|
||||
|
||||
---
|
||||
|
||||
## 十、后端 Setting 表新增键(前端消费)
|
||||
|
||||
| Key | 类型 | 默认值 | 说明 |
|
||||
|-----|------|--------|------|
|
||||
| `payment_enabled` | bool | `false` | 总开关 |
|
||||
| `payment_min_amount` | number | `1` | 最低充值额 |
|
||||
| `payment_max_amount` | number | `10000` | 最高充值额 |
|
||||
| `payment_daily_limit` | number | `50000` | 日限额 |
|
||||
| `payment_max_pending_orders` | number | `3` | 最大待支付数 |
|
||||
| `payment_order_timeout_minutes` | number | `30` | 订单超时 |
|
||||
| `payment_balance_disabled` | bool | `false` | 禁用余额支付 |
|
||||
| `payment_enabled_types` | string | `""` | 支付方式(逗号分隔) |
|
||||
| `payment_help_image_url` | string | `""` | 帮助图片 |
|
||||
| `payment_help_text` | string | `""` | 帮助文字 |
|
||||
|
||||
---
|
||||
|
||||
## 十一、实施顺序
|
||||
|
||||
### Phase 1: 基础设施
|
||||
1. TypeScript 类型定义 (`types/payment.ts`)
|
||||
2. API 模块 (`api/payment.ts`, `api/admin/payment.ts`)
|
||||
3. Store (`stores/payment.ts`)
|
||||
4. 修改 `stores/app.ts` + `stores/adminSettings.ts`
|
||||
5. 修改 `router/index.ts` — 新增路由
|
||||
6. 修改 `AppSidebar.vue` — 新增菜单项
|
||||
7. 新增 i18n 文本
|
||||
|
||||
### Phase 2: 用户侧页面
|
||||
1. `PaymentView.vue` + 子组件
|
||||
2. `PaymentQRCodeView.vue` + QR 组件
|
||||
3. `StripePaymentView.vue`
|
||||
4. `PaymentResultView.vue`
|
||||
5. `UserOrdersView.vue` + 订单组件
|
||||
|
||||
### Phase 3: 管理侧页面
|
||||
1. `AdminOrdersView.vue`(tab 容器 + 订单概览)
|
||||
2. 订单列表 tab + 表格/详情/退款
|
||||
3. 渠道管理 tab
|
||||
4. 订阅套餐 tab
|
||||
5. `AdminProvidersView.vue`(最复杂)
|
||||
|
||||
### Phase 4: 系统设置集成
|
||||
1. `SettingsView.vue` — 新增 `payment` tab
|
||||
2. 移除 `general` tab 旧 purchase 配置
|
||||
3. 旧版兼容迁移逻辑
|
||||
|
||||
---
|
||||
|
||||
## 附录 A: sub2apipay → sub2api 组件映射
|
||||
|
||||
| sub2apipay (React) | 行数 | sub2api (Vue3) | 说明 |
|
||||
|---------------------|------|----------------|------|
|
||||
| `PaymentForm.tsx` | ~400 | `PaymentView.vue` + 子组件 | 拆分为细粒度组件 |
|
||||
| `PaymentQRCode.tsx` | ~300 | `PaymentQRCodeView.vue` | |
|
||||
| `PurchaseFlow.tsx` | ~350 | 融入 `PaymentView.vue` | |
|
||||
| `SubscriptionConfirm.tsx` | ~200 | `SubscriptionConfirmModal.vue` | |
|
||||
| `SubscriptionPlanCard.tsx` | ~150 | `SubscriptionPlanCard.vue` | |
|
||||
| `TopUpModal.tsx` | ~300 | 融入 `PaymentView.vue` | |
|
||||
| `OrderTable.tsx` | ~250 | 复用 sub2api DataTable | |
|
||||
| `MobileOrderList.tsx` | ~200 | 响应式设计融入 View | |
|
||||
| `OrderFilterBar.tsx` | ~150 | `OrderFilterBar.vue` | |
|
||||
| `OrderStatus.tsx` | ~100 | `OrderStatusBadge.vue` | |
|
||||
| `admin/DashboardStats.tsx` | ~150 | `OrderStatsCards.vue` | |
|
||||
| `admin/DailyChart.tsx` | ~200 | `DailyRevenueChart.vue` | |
|
||||
| `admin/PaymentMethodChart.tsx` | ~150 | `PaymentMethodChart.vue` | |
|
||||
| `admin/Leaderboard.tsx` | ~150 | `TopUsersLeaderboard.vue` | |
|
||||
| `admin/OrderTable.tsx` | ~300 | `AdminOrderTable.vue` | |
|
||||
| `admin/OrderDetail.tsx` | ~250 | `AdminOrderDetail.vue` | |
|
||||
| `admin/RefundDialog.tsx` | ~200 | `AdminRefundDialog.vue` | |
|
||||
| `admin/payment-config (page.tsx)` | ~1479 | 拆分为 View + Form + Card | |
|
||||
|
||||
## 附录 B: 关键设计决策
|
||||
|
||||
### B.1 为什么不保留 iframe
|
||||
|
||||
| 维度 | iframe | 原生集成 |
|
||||
|------|--------|---------|
|
||||
| 用户体验 | 两套 UI,主题同步延迟 | 统一 UI |
|
||||
| 认证 | URL 传 token,泄露风险 | JWT 自动携带 |
|
||||
| 部署 | 需独立部署 + 域名 | 单一部署 |
|
||||
| 维护 | 两个项目两套技术栈 | 一个项目 |
|
||||
| 性能 | iframe 加载开销 | 无额外开销 |
|
||||
| CSP | X-Frame-Options 兼容问题 | 无此问题 |
|
||||
|
||||
### B.2 "订单管理"作为一级菜单
|
||||
|
||||
- 订单是高频管理操作,需快速访问
|
||||
- 包含 4 个子功能,信息密度高
|
||||
- 遵循 sub2api 现有模式:业务操作独立菜单
|
||||
|
||||
### B.3 `payment_enabled` 总开关
|
||||
|
||||
- 所有支付菜单和路由受此开关控制
|
||||
- 关闭时:侧边栏不显示、路由守卫重定向、后端 API 同步校验
|
||||
- 零配置时不影响不使用支付功能的用户
|
||||
@@ -0,0 +1,276 @@
|
||||
# 支付系统实施路线图
|
||||
|
||||
> 基于前端计划 + 后端计划的完整实施路线图
|
||||
>
|
||||
> 分支: `feature/payment` @ `touwaeriol/sub2api`
|
||||
|
||||
---
|
||||
|
||||
## Phase 概览
|
||||
|
||||
```
|
||||
Phase 1: 数据库 & Schema ← 无依赖,最先开始
|
||||
Phase 2: Go 后端核心 ← 依赖 Phase 1
|
||||
Phase 3: Go 后端 API ← 依赖 Phase 2
|
||||
Phase 4: 前端基础设施 ← 可与 Phase 2 并行
|
||||
Phase 5: 前端用户页面 ← 依赖 Phase 3 + 4
|
||||
Phase 6: 前端管理页面 ← 依赖 Phase 3 + 4
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: 数据库 & Schema
|
||||
|
||||
### 任务列表
|
||||
|
||||
| # | 任务 | 文件 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 1.1 | PaymentOrder schema | ent/schema/payment_order.go | 订单表,12种状态 |
|
||||
| 1.2 | PaymentAuditLog schema | ent/schema/payment_audit_log.go | 审计日志 |
|
||||
| 1.3 | PaymentChannel schema | ent/schema/payment_channel.go | 展示渠道 |
|
||||
| 1.4 | SubscriptionPlan schema | ent/schema/subscription_plan.go | 订阅套餐 |
|
||||
| 1.5 | PaymentProviderInstance schema | ent/schema/payment_provider_instance.go | 服务商实例 |
|
||||
| 1.6 | SQL migration: orders | migrations/090_payment_orders.sql | |
|
||||
| 1.7 | SQL migration: audit_logs | migrations/091_payment_audit_logs.sql | |
|
||||
| 1.8 | SQL migration: channels | migrations/092_payment_channels.sql | |
|
||||
| 1.9 | SQL migration: plans | migrations/093_subscription_plans.sql | |
|
||||
| 1.10 | SQL migration: instances | migrations/094_payment_provider_instances.sql | |
|
||||
| 1.11 | Ent generate | `go generate ./ent` | 生成 CRUD 代码 |
|
||||
|
||||
**验收**: `go build ./...` 通过,Ent 生成代码无报错
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Go 后端核心
|
||||
|
||||
### 2A: 支付基础设施(可并行)
|
||||
|
||||
| # | 任务 | 文件 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 2.1 | 类型 & 接口定义 | internal/payment/types.go | Provider 接口, 请求/响应类型 |
|
||||
| 2.2 | Provider 注册表 | internal/payment/registry.go | 动态注册/查找 |
|
||||
| 2.3 | 手续费计算 | internal/payment/fee.go | shopspring/decimal, ROUND_UP |
|
||||
| 2.4 | AES 加解密 | internal/payment/crypto.go | 实例配置加密 |
|
||||
| 2.5 | 负载均衡 | internal/payment/load_balancer.go | round-robin / least-amount |
|
||||
| 2.6 | Provider 工厂 | internal/payment/provider_factory.go | 根据实例配置创建 Provider |
|
||||
|
||||
### 2B: Provider 实现(可并行)
|
||||
|
||||
| # | 任务 | 文件 | SDK |
|
||||
|---|------|------|-----|
|
||||
| 2.7 | EasyPay | internal/payment/provider/easypay.go | net/http + crypto/md5 |
|
||||
| 2.8 | Alipay | internal/payment/provider/alipay.go | smartwalle/alipay/v3 |
|
||||
| 2.9 | Wxpay | internal/payment/provider/wxpay.go | wechatpay-apiv3/wechatpay-go |
|
||||
| 2.10 | Stripe | internal/payment/provider/stripe.go | stripe/stripe-go/v82 |
|
||||
|
||||
### 2C: Service 层(依赖 2A + 2B)
|
||||
|
||||
| # | 任务 | 文件 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 2.11 | 配置服务 | internal/service/payment_config_service.go | 系统配置+实例+渠道+套餐 CRUD |
|
||||
| 2.12 | 订单服务-创建 | internal/service/payment_service.go | 创建订单、手续费、限额校验 |
|
||||
| 2.13 | 订单服务-支付确认 | 同上 | Webhook 处理、状态流转 |
|
||||
| 2.14 | 订单服务-履约 | 同上 | 余额充值(RedeemService)、订阅激活 |
|
||||
| 2.15 | 订单服务-退款 | 同上 | prepare/execute/rollback 三阶段 |
|
||||
| 2.16 | 订单服务-超时 | 同上 | 定时过期 + 关单 |
|
||||
| 2.17 | 订单服务-统计 | 同上 | Dashboard 聚合查询 |
|
||||
| 2.18 | Wire DI | internal/payment/wire.go | Provider Set |
|
||||
|
||||
**验收**: 单元测试通过,`go build ./...` 通过
|
||||
|
||||
### 新增 Go 依赖
|
||||
|
||||
```bash
|
||||
go get github.com/stripe/stripe-go/v82
|
||||
go get github.com/smartwalle/alipay/v3
|
||||
go get github.com/wechatpay-apiv3/wechatpay-go
|
||||
go get github.com/shopspring/decimal
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Go 后端 API
|
||||
|
||||
### 3A: Handler 层
|
||||
|
||||
| # | 任务 | 文件 | 端点数 |
|
||||
|---|------|------|--------|
|
||||
| 3.1 | 用户 Handler | internal/handler/payment_handler.go | 9 |
|
||||
| 3.2 | Webhook Handler | internal/handler/payment_webhook_handler.go | 4 |
|
||||
| 3.3 | 管理 Handler | internal/handler/admin/payment_handler.go | 18 |
|
||||
|
||||
### 3B: 路由 & 集成
|
||||
|
||||
| # | 任务 | 文件 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 3.4 | 路由注册 | internal/server/routes/payment.go | 新路由文件 |
|
||||
| 3.5 | Router 集成 | internal/server/router.go | registerRoutes 中调用 |
|
||||
| 3.6 | Handlers 结构体 | internal/handler/handlers.go | 添加 Payment 字段 |
|
||||
| 3.7 | Wire 更新 | cmd/server/wire.go | 注入支付依赖 |
|
||||
| 3.8 | Settings API 扩展 | internal/handler/admin/setting_handler.go | payment_enabled 等配置 |
|
||||
|
||||
**验收**: API 可调通(curl/Postman),Webhook 端点可接收请求
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: 前端基础设施
|
||||
|
||||
可与 Phase 2 并行开始。
|
||||
|
||||
| # | 任务 | 文件 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 4.1 | TypeScript 类型 | frontend/src/types/payment.ts | Order, Plan, Channel 等类型 |
|
||||
| 4.2 | 用户 API 模块 | frontend/src/api/payment.ts | 9 个 API 方法 |
|
||||
| 4.3 | 管理 API 模块 | frontend/src/api/admin/payment.ts | 18 个 API 方法 |
|
||||
| 4.4 | API 导出 | frontend/src/api/index.ts | 导出新模块 |
|
||||
| 4.5 | Payment Store | frontend/src/stores/payment.ts | 配置/订单/套餐状态 |
|
||||
| 4.6 | App Store 修改 | frontend/src/stores/app.ts | 新增 payment_enabled |
|
||||
| 4.7 | Admin Store 修改 | frontend/src/stores/adminSettings.ts | 新增 paymentEnabled |
|
||||
| 4.8 | Router 新增路由 | frontend/src/router/index.ts | 7 个新路由 + meta |
|
||||
| 4.9 | 路由守卫 | frontend/src/router/index.ts | requiresPayment 检查 |
|
||||
| 4.10 | Sidebar 修改 | frontend/src/components/layout/AppSidebar.vue | 新增菜单项 |
|
||||
| 4.11 | i18n 英文 | frontend/src/i18n/locales/en.ts | payment 命名空间 |
|
||||
| 4.12 | i18n 中文 | frontend/src/i18n/locales/zh.ts | payment 命名空间 |
|
||||
|
||||
**新增前端依赖**:
|
||||
```bash
|
||||
cd frontend && pnpm add @stripe/stripe-js
|
||||
```
|
||||
|
||||
**验收**: `pnpm typecheck` 通过,菜单可见性正确
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: 前端用户页面
|
||||
|
||||
依赖 Phase 3 (API) + Phase 4 (基础设施)。
|
||||
|
||||
| # | 任务 | 文件 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 5.1 | 支付方式选择器 | components/payment/PaymentMethodSelector.vue | 共享组件 |
|
||||
| 5.2 | 金额输入 | components/payment/AmountInput.vue | 快捷按钮+自定义 |
|
||||
| 5.3 | 手续费展示 | components/payment/FeeDisplay.vue | 实时计算 |
|
||||
| 5.4 | 套餐卡片 | components/payment/SubscriptionPlanCard.vue | |
|
||||
| 5.5 | 套餐确认弹窗 | components/payment/SubscriptionConfirmModal.vue | |
|
||||
| 5.6 | **充值/订阅主页** | views/user/PaymentView.vue | 替换 iframe,核心页面 |
|
||||
| 5.7 | QR码展示 | components/payment/QRCodeDisplay.vue | qrcode 库 |
|
||||
| 5.8 | 倒计时 | components/payment/CountdownTimer.vue | |
|
||||
| 5.9 | **二维码支付页** | views/user/PaymentQRCodeView.vue | 轮询+倒计时 |
|
||||
| 5.10 | **Stripe 支付页** | views/user/StripePaymentView.vue | Payment Element |
|
||||
| 5.11 | **支付结果页** | views/user/PaymentResultView.vue | 成功/失败展示 |
|
||||
| 5.12 | 订单状态标签 | components/payment/OrderStatusBadge.vue | 彩色标签 |
|
||||
| 5.13 | 订单筛选栏 | components/payment/OrderFilterBar.vue | |
|
||||
| 5.14 | **我的订单页** | views/user/UserOrdersView.vue | 列表+筛选+操作 |
|
||||
| 5.15 | 删除旧文件 | PurchaseSubscriptionView.vue, embedded-url.ts | |
|
||||
|
||||
**验收**: 用户可完成充值流程(创建订单→扫码/Stripe→支付成功→余额增加)
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: 前端管理页面
|
||||
|
||||
可与 Phase 5 并行。
|
||||
|
||||
| # | 任务 | 文件 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 6.1 | 统计卡片 | components/admin/payment/OrderStatsCards.vue | |
|
||||
| 6.2 | 日收入图表 | components/admin/payment/DailyRevenueChart.vue | Chart.js |
|
||||
| 6.3 | 支付分布图 | components/admin/payment/PaymentMethodChart.vue | |
|
||||
| 6.4 | 排行榜 | components/admin/payment/TopUsersLeaderboard.vue | |
|
||||
| 6.5 | **订单管理页(tab容器)** | views/admin/orders/AdminOrdersView.vue | 4个tab |
|
||||
| 6.6 | 管理订单表格 | components/admin/payment/AdminOrderTable.vue | DataTable |
|
||||
| 6.7 | 订单详情 | components/admin/payment/AdminOrderDetail.vue | |
|
||||
| 6.8 | 退款对话框 | components/admin/payment/AdminRefundDialog.vue | |
|
||||
| 6.9 | 订单搜索栏 | components/admin/payment/AdminOrderSearchBar.vue | |
|
||||
| 6.10 | **订单列表tab** | 融入 AdminOrdersView | |
|
||||
| 6.11 | **渠道管理tab** | views/admin/orders/AdminOrderChannelsView.vue | |
|
||||
| 6.12 | **订阅套餐tab** | views/admin/orders/AdminOrderPlansView.vue | |
|
||||
| 6.13 | 服务商实例表单 | components/admin/payment/ProviderInstanceForm.vue | |
|
||||
| 6.14 | 服务商实例卡片 | components/admin/payment/ProviderInstanceCard.vue | |
|
||||
| 6.15 | **服务商管理页** | views/admin/orders/AdminProvidersView.vue | |
|
||||
| 6.16 | **Settings payment tab** | 修改 SettingsView.vue | 新增tab+移除旧配置 |
|
||||
| 6.17 | 旧版兼容迁移 | Go migration code | purchase_url→自定义菜单 |
|
||||
|
||||
**验收**: 管理员可完成全流程(配置支付→管理订单→处理退款)
|
||||
|
||||
---
|
||||
|
||||
## 依赖关系图
|
||||
|
||||
```
|
||||
Phase 1 (DB)
|
||||
│
|
||||
▼
|
||||
Phase 2 (Go Core) ──────┐
|
||||
│ │
|
||||
▼ │
|
||||
Phase 3 (Go API) ◄──────┤
|
||||
│ │
|
||||
▼ ▼
|
||||
Phase 5 (User UI) ◄── Phase 4 (FE Infra)
|
||||
│
|
||||
Phase 6 (Admin UI) ◄────┘
|
||||
|
||||
可并行:
|
||||
- Phase 2A + 2B (基础设施 + Provider 实现)
|
||||
- Phase 4 可与 Phase 2 同时开始
|
||||
- Phase 5 + Phase 6 可并行
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 后端单元测试
|
||||
|
||||
| 测试文件 | 覆盖 |
|
||||
|---------|------|
|
||||
| internal/payment/fee_test.go | 手续费计算精度 |
|
||||
| internal/payment/registry_test.go | 注册/查找 |
|
||||
| internal/payment/load_balancer_test.go | 实例选择策略 |
|
||||
| internal/payment/crypto_test.go | 加解密正确性 |
|
||||
| internal/payment/provider/easypay_test.go | 签名验证 |
|
||||
| internal/service/payment_service_test.go | 订单状态流转 |
|
||||
| internal/service/payment_config_service_test.go | 配置 CRUD |
|
||||
| internal/handler/payment_handler_test.go | API 请求/响应 |
|
||||
|
||||
### 后端集成测试
|
||||
|
||||
| 测试 | 覆盖 |
|
||||
|------|------|
|
||||
| 订单创建→支付→履约 | 完整流程 |
|
||||
| 退款三阶段 | prepare→execute→rollback |
|
||||
| Webhook 验签 | 各 Provider 签名验证 |
|
||||
|
||||
### 前端组件测试
|
||||
|
||||
| 测试 | 覆盖 |
|
||||
|------|------|
|
||||
| PaymentMethodSelector | 选择/禁用/限额展示 |
|
||||
| AmountInput | 金额验证/精度 |
|
||||
| OrderStatusBadge | 状态→颜色映射 |
|
||||
| PaymentView | 创建订单流程 |
|
||||
|
||||
---
|
||||
|
||||
## 迁移兼容
|
||||
|
||||
### 滚动部署 3 阶段
|
||||
|
||||
1. **部署后端** — 新 API 端点上线,但 `payment_enabled=false`,不影响现有功能
|
||||
2. **部署前端** — 新页面/组件上线,但菜单隐藏(因为 `payment_enabled=false`)
|
||||
3. **管理员开启** — 在设置中启用 `payment_enabled`,配置支付服务商,功能生效
|
||||
|
||||
### purchase_subscription_url 兼容
|
||||
|
||||
Go 迁移代码在启动时检查:
|
||||
```go
|
||||
if url := settingService.Get("purchase_subscription_url"); url != "" {
|
||||
// 自动创建 custom_menu_item 保留旧 URL
|
||||
// 标记 purchase_subscription_url 为 deprecated
|
||||
}
|
||||
```
|
||||
|
||||
### 数据库迁移顺序
|
||||
|
||||
迁移 090-094 仅创建新表,不修改现有表,零风险。
|
||||
@@ -26,6 +26,7 @@ import scheduledTestsAPI from './scheduledTests'
|
||||
import backupAPI from './backup'
|
||||
import tlsFingerprintProfileAPI from './tlsFingerprintProfile'
|
||||
import channelsAPI from './channels'
|
||||
import adminPaymentAPI from './payment'
|
||||
|
||||
/**
|
||||
* Unified admin API object for convenient access
|
||||
@@ -53,7 +54,8 @@ export const adminAPI = {
|
||||
scheduledTests: scheduledTestsAPI,
|
||||
backup: backupAPI,
|
||||
tlsFingerprintProfiles: tlsFingerprintProfileAPI,
|
||||
channels: channelsAPI
|
||||
channels: channelsAPI,
|
||||
payment: adminPaymentAPI
|
||||
}
|
||||
|
||||
export {
|
||||
@@ -79,7 +81,8 @@ export {
|
||||
scheduledTestsAPI,
|
||||
backupAPI,
|
||||
tlsFingerprintProfileAPI,
|
||||
channelsAPI
|
||||
channelsAPI,
|
||||
adminPaymentAPI
|
||||
}
|
||||
|
||||
export default adminAPI
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Admin Payment API endpoints
|
||||
* Handles payment management operations for administrators
|
||||
*/
|
||||
|
||||
import { apiClient } from '../client'
|
||||
import type {
|
||||
DashboardStats,
|
||||
PaymentOrder,
|
||||
PaymentChannel,
|
||||
SubscriptionPlan,
|
||||
ProviderInstance
|
||||
} from '@/types/payment'
|
||||
import type { BasePaginationResponse } from '@/types'
|
||||
|
||||
export const adminPaymentAPI = {
|
||||
// ==================== Dashboard ====================
|
||||
|
||||
/** Get payment dashboard statistics */
|
||||
getDashboard(days?: number) {
|
||||
return apiClient.get<DashboardStats>('/admin/payment/dashboard', {
|
||||
params: days ? { days } : undefined
|
||||
})
|
||||
},
|
||||
|
||||
// ==================== Orders ====================
|
||||
|
||||
/** Get all orders (paginated, with filters) */
|
||||
getOrders(params?: {
|
||||
page?: number
|
||||
page_size?: number
|
||||
status?: string
|
||||
payment_type?: string
|
||||
user_id?: number
|
||||
keyword?: string
|
||||
start_date?: string
|
||||
end_date?: string
|
||||
order_type?: string
|
||||
}) {
|
||||
return apiClient.get<BasePaginationResponse<PaymentOrder>>('/admin/payment/orders', { params })
|
||||
},
|
||||
|
||||
/** Get a specific order by ID */
|
||||
getOrder(id: number) {
|
||||
return apiClient.get<PaymentOrder>(`/admin/payment/orders/${id}`)
|
||||
},
|
||||
|
||||
/** Cancel an order (admin) */
|
||||
cancelOrder(id: number) {
|
||||
return apiClient.post(`/admin/payment/orders/${id}/cancel`)
|
||||
},
|
||||
|
||||
/** Retry recharge for a failed order */
|
||||
retryRecharge(id: number) {
|
||||
return apiClient.post(`/admin/payment/orders/${id}/retry`)
|
||||
},
|
||||
|
||||
/** Process a refund */
|
||||
refundOrder(id: number, data: { amount: number; reason: string; deduct_balance?: boolean }) {
|
||||
return apiClient.post(`/admin/payment/orders/${id}/refund`, data)
|
||||
},
|
||||
|
||||
// ==================== Channels ====================
|
||||
|
||||
/** Get all payment channels */
|
||||
getChannels() {
|
||||
return apiClient.get<PaymentChannel[]>('/admin/payment/channels')
|
||||
},
|
||||
|
||||
/** Create a payment channel */
|
||||
createChannel(data: Partial<PaymentChannel>) {
|
||||
return apiClient.post<PaymentChannel>('/admin/payment/channels', data)
|
||||
},
|
||||
|
||||
/** Update a payment channel */
|
||||
updateChannel(id: number, data: Partial<PaymentChannel>) {
|
||||
return apiClient.put<PaymentChannel>(`/admin/payment/channels/${id}`, data)
|
||||
},
|
||||
|
||||
/** Delete a payment channel */
|
||||
deleteChannel(id: number) {
|
||||
return apiClient.delete(`/admin/payment/channels/${id}`)
|
||||
},
|
||||
|
||||
// ==================== Subscription Plans ====================
|
||||
|
||||
/** Get all subscription plans */
|
||||
getPlans() {
|
||||
return apiClient.get<SubscriptionPlan[]>('/admin/payment/plans')
|
||||
},
|
||||
|
||||
/** Create a subscription plan */
|
||||
createPlan(data: Partial<SubscriptionPlan>) {
|
||||
return apiClient.post<SubscriptionPlan>('/admin/payment/plans', data)
|
||||
},
|
||||
|
||||
/** Update a subscription plan */
|
||||
updatePlan(id: number, data: Partial<SubscriptionPlan>) {
|
||||
return apiClient.put<SubscriptionPlan>(`/admin/payment/plans/${id}`, data)
|
||||
},
|
||||
|
||||
/** Delete a subscription plan */
|
||||
deletePlan(id: number) {
|
||||
return apiClient.delete(`/admin/payment/plans/${id}`)
|
||||
},
|
||||
|
||||
// ==================== Provider Instances ====================
|
||||
|
||||
/** Get all provider instances */
|
||||
getProviders() {
|
||||
return apiClient.get<ProviderInstance[]>('/admin/payment/providers')
|
||||
},
|
||||
|
||||
/** Create a provider instance */
|
||||
createProvider(data: Partial<ProviderInstance>) {
|
||||
return apiClient.post<ProviderInstance>('/admin/payment/providers', data)
|
||||
},
|
||||
|
||||
/** Update a provider instance */
|
||||
updateProvider(id: number, data: Partial<ProviderInstance>) {
|
||||
return apiClient.put<ProviderInstance>(`/admin/payment/providers/${id}`, data)
|
||||
},
|
||||
|
||||
/** Delete a provider instance */
|
||||
deleteProvider(id: number) {
|
||||
return apiClient.delete(`/admin/payment/providers/${id}`)
|
||||
}
|
||||
}
|
||||
|
||||
export default adminPaymentAPI
|
||||
@@ -40,6 +40,8 @@ export interface SystemSettings {
|
||||
hide_ccs_import_button: boolean
|
||||
purchase_subscription_enabled: boolean
|
||||
purchase_subscription_url: string
|
||||
payment_enabled: boolean
|
||||
sora_client_enabled: boolean
|
||||
backend_mode_enabled: boolean
|
||||
custom_menu_items: CustomMenuItem[]
|
||||
custom_endpoints: CustomEndpoint[]
|
||||
|
||||
@@ -14,6 +14,7 @@ export { keysAPI } from './keys'
|
||||
export { usageAPI } from './usage'
|
||||
export { userAPI } from './user'
|
||||
export { redeemAPI, type RedeemHistoryItem } from './redeem'
|
||||
export { paymentAPI } from './payment'
|
||||
export { userGroupsAPI } from './groups'
|
||||
export { totpAPI } from './totp'
|
||||
export { default as announcementsAPI } from './announcements'
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* User Payment API endpoints
|
||||
* Handles payment operations for regular users
|
||||
*/
|
||||
|
||||
import { apiClient } from './client'
|
||||
import type {
|
||||
PaymentConfig,
|
||||
SubscriptionPlan,
|
||||
PaymentChannel,
|
||||
MethodLimit,
|
||||
CreateOrderRequest,
|
||||
CreateOrderResult,
|
||||
PaymentOrder
|
||||
} from '@/types/payment'
|
||||
import type { BasePaginationResponse } from '@/types'
|
||||
|
||||
export const paymentAPI = {
|
||||
/** Get payment configuration (enabled types, limits, etc.) */
|
||||
getConfig() {
|
||||
return apiClient.get<PaymentConfig>('/payment/config')
|
||||
},
|
||||
|
||||
/** Get available subscription plans */
|
||||
getPlans() {
|
||||
return apiClient.get<SubscriptionPlan[]>('/payment/plans')
|
||||
},
|
||||
|
||||
/** Get available payment channels */
|
||||
getChannels() {
|
||||
return apiClient.get<PaymentChannel[]>('/payment/channels')
|
||||
},
|
||||
|
||||
/** Get payment method limits and fee rates */
|
||||
getLimits() {
|
||||
return apiClient.get<Record<string, MethodLimit>>('/payment/limits')
|
||||
},
|
||||
|
||||
/** Create a new payment order */
|
||||
createOrder(data: CreateOrderRequest) {
|
||||
return apiClient.post<CreateOrderResult>('/payment/orders', data)
|
||||
},
|
||||
|
||||
/** Get current user's orders */
|
||||
getMyOrders(params?: { page?: number; page_size?: number; status?: string }) {
|
||||
return apiClient.get<BasePaginationResponse<PaymentOrder>>('/payment/orders/my', { params })
|
||||
},
|
||||
|
||||
/** Get a specific order by ID */
|
||||
getOrder(id: number) {
|
||||
return apiClient.get<PaymentOrder>(`/payment/orders/${id}`)
|
||||
},
|
||||
|
||||
/** Cancel a pending order */
|
||||
cancelOrder(id: number) {
|
||||
return apiClient.post(`/payment/orders/${id}/cancel`)
|
||||
},
|
||||
|
||||
/** Request a refund for a completed order */
|
||||
requestRefund(id: number, data: { reason: string }) {
|
||||
return apiClient.post(`/payment/orders/${id}/refund-request`, data)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<BaseDialog
|
||||
:show="show"
|
||||
:title="t('payment.admin.orderDetail')"
|
||||
width="wide"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<div v-if="order" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.orders.orderId') }}</p>
|
||||
<p class="font-mono text-sm font-medium text-gray-900 dark:text-white">#{{ order.id }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.orders.status') }}</p>
|
||||
<span :class="['badge', statusBadgeClass(order.status)]">
|
||||
{{ t('payment.status.' + order.status.toLowerCase(), order.status) }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.orders.amount') }}</p>
|
||||
<p class="text-sm font-medium text-gray-900 dark:text-white">${{ order.amount.toFixed(2) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.orders.payAmount') }}</p>
|
||||
<p class="text-sm font-medium text-gray-900 dark:text-white">${{ order.pay_amount.toFixed(2) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.orders.paymentMethod') }}</p>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">
|
||||
{{ t('payment.methods.' + order.payment_type, order.payment_type) }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.admin.feeRate') }}</p>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">{{ (order.fee_rate * 100).toFixed(1) }}%</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.admin.orderType') }}</p>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">
|
||||
{{ t('payment.admin.' + order.order_type + 'Order', order.order_type) }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.orders.userId') }}</p>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">#{{ order.user_id }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.orders.createdAt') }}</p>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">{{ formatDateTime(order.created_at) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.admin.expiresAt') }}</p>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">{{ formatDateTime(order.expires_at) }}</p>
|
||||
</div>
|
||||
<div v-if="order.paid_at">
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.admin.paidAt') }}</p>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">{{ formatDateTime(order.paid_at) }}</p>
|
||||
</div>
|
||||
<div v-if="order.completed_at">
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ t('payment.admin.completedAt') }}</p>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">{{ formatDateTime(order.completed_at) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="order.refund_amount"
|
||||
class="rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-800 dark:bg-red-900/20"
|
||||
>
|
||||
<h4 class="mb-2 text-sm font-semibold text-red-700 dark:text-red-400">
|
||||
{{ t('payment.admin.refundInfo') }}
|
||||
</h4>
|
||||
<div class="grid grid-cols-2 gap-2 text-sm">
|
||||
<div>
|
||||
<span class="text-red-600 dark:text-red-400">{{ t('payment.admin.refundAmount') }}:</span>
|
||||
<span class="ml-1 font-medium text-red-700 dark:text-red-300">${{ order.refund_amount.toFixed(2) }}</span>
|
||||
</div>
|
||||
<div v-if="order.refund_reason" class="col-span-2">
|
||||
<span class="text-red-600 dark:text-red-400">{{ t('payment.admin.refundReason') }}:</span>
|
||||
<span class="ml-1 text-red-700 dark:text-red-300">{{ order.refund_reason }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-2 border-t border-gray-200 pt-4 dark:border-dark-700">
|
||||
<button
|
||||
v-if="order.status === 'PENDING'"
|
||||
@click="emit('cancel', order)"
|
||||
class="btn btn-sm rounded-md bg-yellow-50 px-3 py-1.5 text-sm text-yellow-600 hover:bg-yellow-100 dark:bg-yellow-900/20 dark:text-yellow-400 dark:hover:bg-yellow-900/30"
|
||||
>
|
||||
{{ t('payment.orders.cancel') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="order.status === 'FAILED'"
|
||||
@click="emit('retry', order)"
|
||||
class="btn btn-sm btn-secondary"
|
||||
>
|
||||
{{ t('payment.admin.retry') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="canRefund(order)"
|
||||
@click="emit('refund', order)"
|
||||
class="btn btn-sm rounded-md bg-red-50 px-3 py-1.5 text-sm text-red-600 hover:bg-red-100 dark:bg-red-900/20 dark:text-red-400 dark:hover:bg-red-900/30"
|
||||
>
|
||||
{{ t('payment.admin.refund') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</BaseDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import BaseDialog from '@/components/common/BaseDialog.vue'
|
||||
import type { PaymentOrder } from '@/types/payment'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
defineProps<{
|
||||
show: boolean
|
||||
order: PaymentOrder | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'close'): void
|
||||
(e: 'cancel', order: PaymentOrder): void
|
||||
(e: 'retry', order: PaymentOrder): void
|
||||
(e: 'refund', order: PaymentOrder): void
|
||||
}>()
|
||||
|
||||
function statusBadgeClass(status: string): string {
|
||||
const m: Record<string, string> = {
|
||||
PENDING: 'badge-warning', PAID: 'badge-info', RECHARGING: 'badge-info',
|
||||
COMPLETED: 'badge-success', EXPIRED: 'badge-secondary', CANCELLED: 'badge-secondary',
|
||||
FAILED: 'badge-danger', REFUND_REQUESTED: 'badge-warning', REFUNDING: 'badge-warning',
|
||||
PARTIALLY_REFUNDED: 'badge-warning', REFUNDED: 'badge-info', REFUND_FAILED: 'badge-danger',
|
||||
}
|
||||
return m[status] || 'badge-secondary'
|
||||
}
|
||||
|
||||
function canRefund(order: PaymentOrder): boolean {
|
||||
return ['COMPLETED', 'PARTIALLY_REFUNDED'].includes(order.status)
|
||||
}
|
||||
|
||||
function formatDateTime(dateStr: string): string {
|
||||
if (!dateStr) return '-'
|
||||
return new Date(dateStr).toLocaleString()
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,235 @@
|
||||
<template>
|
||||
<div class="space-y-4">
|
||||
<div class="card p-4">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<div class="flex-1 sm:max-w-64">
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
:placeholder="t('payment.admin.searchOrders')"
|
||||
class="input"
|
||||
@input="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
<Select
|
||||
v-model="filters.status"
|
||||
:options="statusFilterOptions"
|
||||
class="w-36"
|
||||
@change="emitFiltersChanged"
|
||||
/>
|
||||
<Select
|
||||
v-model="filters.payment_type"
|
||||
:options="paymentTypeFilterOptions"
|
||||
class="w-40"
|
||||
@change="emitFiltersChanged"
|
||||
/>
|
||||
<Select
|
||||
v-model="filters.order_type"
|
||||
:options="orderTypeFilterOptions"
|
||||
class="w-36"
|
||||
@change="emitFiltersChanged"
|
||||
/>
|
||||
<div class="flex flex-1 flex-wrap items-center justify-end gap-2">
|
||||
<button
|
||||
@click="emit('refresh')"
|
||||
:disabled="loading"
|
||||
class="btn btn-secondary"
|
||||
:title="t('common.refresh')"
|
||||
>
|
||||
<Icon name="refresh" size="md" :class="loading ? 'animate-spin' : ''" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DataTable :columns="columns" :data="orders" :loading="loading">
|
||||
<template #cell-id="{ value }">
|
||||
<span class="font-mono text-sm">#{{ value }}</span>
|
||||
</template>
|
||||
|
||||
<template #cell-user_id="{ value }">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">#{{ value }}</span>
|
||||
</template>
|
||||
|
||||
<template #cell-amount="{ value, row }">
|
||||
<div class="text-sm">
|
||||
<span class="font-medium text-gray-900 dark:text-white">${{ value.toFixed(2) }}</span>
|
||||
<span v-if="row.pay_amount !== value" class="ml-1 text-xs text-gray-500">
|
||||
({{ t('payment.orders.payAmount') }}: ${{ row.pay_amount.toFixed(2) }})
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell-payment_type="{ value }">
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">
|
||||
{{ t('payment.methods.' + value, value) }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #cell-status="{ value }">
|
||||
<span :class="['badge', statusBadgeClass(value)]">
|
||||
{{ t('payment.status.' + value.toLowerCase(), value) }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #cell-order_type="{ value }">
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">
|
||||
{{ t('payment.admin.' + value + 'Order', value) }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template #cell-created_at="{ value }">
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{ formatDateTime(value) }}</span>
|
||||
</template>
|
||||
|
||||
<template #cell-actions="{ row }">
|
||||
<div class="flex items-center gap-1">
|
||||
<button
|
||||
@click="emit('detail', row)"
|
||||
class="btn-icon text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
:title="t('common.view')"
|
||||
>
|
||||
<Icon name="eye" size="sm" />
|
||||
</button>
|
||||
<button
|
||||
v-if="row.status === 'PENDING'"
|
||||
@click="emit('cancel', row)"
|
||||
class="btn-icon text-yellow-500 hover:text-yellow-700"
|
||||
:title="t('payment.orders.cancel')"
|
||||
>
|
||||
<Icon name="x" size="sm" />
|
||||
</button>
|
||||
<button
|
||||
v-if="row.status === 'FAILED'"
|
||||
@click="emit('retry', row)"
|
||||
class="btn-icon text-blue-500 hover:text-blue-700"
|
||||
:title="t('payment.admin.retry')"
|
||||
>
|
||||
<Icon name="refresh" size="sm" />
|
||||
</button>
|
||||
<button
|
||||
v-if="canRefund(row)"
|
||||
@click="emit('refund', row)"
|
||||
class="btn-icon text-red-500 hover:text-red-700"
|
||||
:title="t('payment.admin.refund')"
|
||||
>
|
||||
<Icon name="dollar" size="sm" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</DataTable>
|
||||
|
||||
<Pagination
|
||||
v-if="total > 0"
|
||||
:page="page"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
@update:page="emit('update:page', $event)"
|
||||
@update:pageSize="emit('update:pageSize', $event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { PaymentOrder } from '@/types/payment'
|
||||
import type { Column } from '@/components/common/types'
|
||||
import DataTable from '@/components/common/DataTable.vue'
|
||||
import Pagination from '@/components/common/Pagination.vue'
|
||||
import Select from '@/components/common/Select.vue'
|
||||
import Icon from '@/components/icons/Icon.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
defineProps<{
|
||||
orders: PaymentOrder[]
|
||||
loading: boolean
|
||||
page: number
|
||||
pageSize: number
|
||||
total: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'detail', order: PaymentOrder): void
|
||||
(e: 'cancel', order: PaymentOrder): void
|
||||
(e: 'retry', order: PaymentOrder): void
|
||||
(e: 'refund', order: PaymentOrder): void
|
||||
(e: 'refresh'): void
|
||||
(e: 'update:page', page: number): void
|
||||
(e: 'update:pageSize', size: number): void
|
||||
(e: 'filter', filters: { keyword?: string; status?: string; payment_type?: string; order_type?: string }): void
|
||||
}>()
|
||||
|
||||
const searchQuery = ref('')
|
||||
const filters = reactive({ status: '', payment_type: '', order_type: '' })
|
||||
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||
function handleSearch() {
|
||||
if (debounceTimer) clearTimeout(debounceTimer)
|
||||
debounceTimer = setTimeout(() => emitFiltersChanged(), 300)
|
||||
}
|
||||
|
||||
function emitFiltersChanged() {
|
||||
emit('filter', {
|
||||
keyword: searchQuery.value || undefined,
|
||||
status: filters.status || undefined,
|
||||
payment_type: filters.payment_type || undefined,
|
||||
order_type: filters.order_type || undefined,
|
||||
})
|
||||
}
|
||||
|
||||
const columns: Column[] = [
|
||||
{ key: 'id', label: 'ID' },
|
||||
{ key: 'user_id', label: 'User' },
|
||||
{ key: 'amount', label: 'Amount' },
|
||||
{ key: 'payment_type', label: 'Method' },
|
||||
{ key: 'status', label: 'Status' },
|
||||
{ key: 'order_type', label: 'Type' },
|
||||
{ key: 'created_at', label: 'Created' },
|
||||
{ key: 'actions', label: 'Actions' },
|
||||
]
|
||||
|
||||
const statusFilterOptions = computed(() => [
|
||||
{ value: '', label: t('payment.admin.allStatuses') },
|
||||
{ value: 'PENDING', label: t('payment.status.pending') },
|
||||
{ value: 'PAID', label: t('payment.status.paid') },
|
||||
{ value: 'COMPLETED', label: t('payment.status.completed') },
|
||||
{ value: 'EXPIRED', label: t('payment.status.expired') },
|
||||
{ value: 'CANCELLED', label: t('payment.status.cancelled') },
|
||||
{ value: 'FAILED', label: t('payment.status.failed') },
|
||||
{ value: 'REFUNDED', label: t('payment.status.refunded') },
|
||||
])
|
||||
|
||||
const paymentTypeFilterOptions = computed(() => [
|
||||
{ value: '', label: t('payment.admin.allPaymentTypes') },
|
||||
{ value: 'alipay', label: t('payment.methods.alipay') },
|
||||
{ value: 'wxpay', label: t('payment.methods.wxpay') },
|
||||
{ value: 'stripe', label: t('payment.methods.stripe') },
|
||||
])
|
||||
|
||||
const orderTypeFilterOptions = computed(() => [
|
||||
{ value: '', label: t('payment.admin.allOrderTypes') },
|
||||
{ value: 'balance', label: t('payment.admin.balanceOrder') },
|
||||
{ value: 'subscription', label: t('payment.admin.subscriptionOrder') },
|
||||
])
|
||||
|
||||
function statusBadgeClass(status: string): string {
|
||||
const m: Record<string, string> = {
|
||||
PENDING: 'badge-warning', PAID: 'badge-info', RECHARGING: 'badge-info',
|
||||
COMPLETED: 'badge-success', EXPIRED: 'badge-secondary', CANCELLED: 'badge-secondary',
|
||||
FAILED: 'badge-danger', REFUND_REQUESTED: 'badge-warning', REFUNDING: 'badge-warning',
|
||||
PARTIALLY_REFUNDED: 'badge-warning', REFUNDED: 'badge-info', REFUND_FAILED: 'badge-danger',
|
||||
}
|
||||
return m[status] || 'badge-secondary'
|
||||
}
|
||||
|
||||
function canRefund(order: PaymentOrder): boolean {
|
||||
return ['COMPLETED', 'PARTIALLY_REFUNDED'].includes(order.status)
|
||||
}
|
||||
|
||||
function formatDateTime(dateStr: string): string {
|
||||
if (!dateStr) return '-'
|
||||
return new Date(dateStr).toLocaleString()
|
||||
}
|
||||
</script>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user