diff --git a/.github/audit-exceptions.yml b/.github/audit-exceptions.yml index b71422a7..4e05aae6 100644 --- a/.github/audit-exceptions.yml +++ b/.github/audit-exceptions.yml @@ -28,3 +28,10 @@ exceptions: mitigation: "No user-controlled template strings; plan to migrate to native JS alternatives" expires_on: "2026-07-02" owner: "security@your-domain" + - package: axios + advisory: "GHSA-3p68-rc4w-qgx5" + severity: critical + reason: "NO_PROXY bypass not exploitable; all API calls go to known endpoints via server-side proxy" + mitigation: "Proxy configuration not user-controlled; upgrade when axios releases fix" + expires_on: "2026-07-10" + owner: "security@your-domain" diff --git a/backend/cmd/server/wire.go b/backend/cmd/server/wire.go index 7fc648ac..0c3fe094 100644 --- a/backend/cmd/server/wire.go +++ b/backend/cmd/server/wire.go @@ -13,6 +13,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent" "github.com/Wei-Shaw/sub2api/internal/config" "github.com/Wei-Shaw/sub2api/internal/handler" + "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" @@ -41,6 +42,13 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { // Server layer ProviderSet server.ProviderSet, + // Payment providers + payment.ProvideRegistry, + payment.ProvideEncryptionKey, + payment.ProvideDefaultLoadBalancer, + service.ProvidePaymentConfigService, + service.ProvidePaymentOrderExpiryService, + // Privacy client factory for OpenAI training opt-out providePrivacyClientFactory, @@ -95,6 +103,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 +246,12 @@ func provideCleanup( } return nil }}, + {"PaymentOrderExpiryService", func() error { + if paymentOrderExpiry != nil { + paymentOrderExpiry.Stop() + } + return nil + }}, } infraSteps := []cleanupStep{ diff --git a/backend/cmd/server/wire_gen.go b/backend/cmd/server/wire_gen.go index aff9a0ff..c288a289 100644 --- a/backend/cmd/server/wire_gen.go +++ b/backend/cmd/server/wire_gen.go @@ -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" @@ -72,6 +73,15 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { userService := service.NewUserService(userRepository, apiKeyAuthCacheInvalidator, billingCache) redeemCache := repository.NewRedeemCache(redisClient) redeemService := service.NewRedeemService(redeemCodeRepository, userRepository, subscriptionService, redeemCache, billingCacheService, client, apiKeyAuthCacheInvalidator) + registry := payment.ProvideRegistry() + encryptionKey, err := payment.ProvideEncryptionKey(configConfig) + if err != nil { + return nil, err + } + 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) secretEncryptor, err := repository.NewAESEncryptor(configConfig) if err != nil { return nil, err @@ -183,7 +193,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { geminiMessagesCompatService := service.NewGeminiMessagesCompatService(accountRepository, groupRepository, gatewayCache, schedulerSnapshotService, geminiTokenProvider, rateLimitService, httpUpstream, antigravityGatewayService, configConfig) opsSystemLogSink := service.ProvideOpsSystemLogSink(opsRepository) opsService := service.NewOpsService(opsRepository, settingRepository, configConfig, accountRepository, userRepository, concurrencyService, gatewayService, openAIGatewayService, geminiMessagesCompatService, antigravityGatewayService, opsSystemLogSink) - settingHandler := admin.NewSettingHandler(settingService, emailService, turnstileService, opsService) + settingHandler := admin.NewSettingHandler(settingService, emailService, turnstileService, opsService, paymentConfigService, paymentService) opsHandler := admin.NewOpsHandler(opsService) updateCache := repository.NewUpdateCache(redisClient) gitHubReleaseClient := repository.ProvideGitHubReleaseClient(configConfig) @@ -211,7 +221,8 @@ 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) + adminPaymentHandler := 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, adminPaymentHandler) usageRecordWorkerPool := service.NewUsageRecordWorkerPool(configConfig) userMsgQueueCache := repository.NewUserMsgQueueCache(redisClient) userMessageQueueService := service.ProvideUserMessageQueueService(userMsgQueueCache, rpmCache, configConfig) @@ -219,9 +230,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) @@ -236,7 +249,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { 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 +302,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 +438,12 @@ func provideCleanup( } return nil }}, + {"PaymentOrderExpiryService", func() error { + if paymentOrderExpiry != nil { + paymentOrderExpiry.Stop() + } + return nil + }}, } infraSteps := []cleanupStep{ diff --git a/backend/cmd/server/wire_gen_test.go b/backend/cmd/server/wire_gen_test.go index 6e4561c9..a6e0551a 100644 --- a/backend/cmd/server/wire_gen_test.go +++ b/backend/cmd/server/wire_gen_test.go @@ -75,6 +75,7 @@ func TestProvideCleanup_WithMinimalDependencies_NoPanic(t *testing.T) { nil, // openAIGateway nil, // scheduledTestRunner nil, // backupSvc + nil, // paymentOrderExpiry ) require.NotPanics(t, func() { diff --git a/backend/ent/client.go b/backend/ent/client.go index 4129d6c5..e52e015a 100644 --- a/backend/ent/client.go +++ b/backend/ent/client.go @@ -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,8 +332,9 @@ 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.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting, + 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.SubscriptionPlan, c.TLSFingerprintProfile, c.UsageCleanupTask, c.UsageLog, c.User, c.UserAllowedGroup, c.UserAttributeDefinition, c.UserAttributeValue, c.UserSubscription, @@ -323,8 +348,9 @@ 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.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting, + 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.SubscriptionPlan, c.TLSFingerprintProfile, c.UsageCleanupTask, c.UsageLog, c.User, c.UserAllowedGroup, c.UserAttributeDefinition, c.UserAttributeValue, c.UserSubscription, @@ -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,15 +4629,17 @@ 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, + 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, + ErrorPassthroughRule, Group, IdempotencyRecord, PaymentAuditLog, PaymentOrder, + PaymentProviderInstance, PromoCode, PromoCodeUsage, Proxy, RedeemCode, + SecuritySecret, Setting, SubscriptionPlan, TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Interceptor } diff --git a/backend/ent/ent.go b/backend/ent/ent.go index bdeaed8a..96ed5e03 100644 --- a/backend/ent/ent.go +++ b/backend/ent/ent.go @@ -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, diff --git a/backend/ent/hook/hook.go b/backend/ent/hook/hook.go index f6f7b4e9..199dacea 100644 --- a/backend/ent/hook/hook.go +++ b/backend/ent/hook/hook.go @@ -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) diff --git a/backend/ent/intercept/intercept.go b/backend/ent/intercept/intercept.go index 13169ca7..8d8320bb 100644 --- a/backend/ent/intercept/intercept.go +++ b/backend/ent/intercept/intercept.go @@ -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,87 @@ 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 +552,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 +814,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 +832,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: diff --git a/backend/ent/migrate/schema.go b/backend/ent/migrate/schema.go index a7ae4af0..e947b2e8 100644 --- a/backend/ent/migrate/schema.go +++ b/backend/ent/migrate/schema.go @@ -485,6 +485,158 @@ 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: "out_trade_no", Type: field.TypeString, Size: 64, Default: ""}, + {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[37]}, + RefColumns: []*schema.Column{UsersColumns[0]}, + OnDelete: schema.NoAction, + }, + }, + Indexes: []*schema.Index{ + { + Name: "paymentorder_out_trade_no", + Unique: false, + Columns: []*schema.Column{PaymentOrdersColumns[8]}, + }, + { + Name: "paymentorder_user_id", + Unique: false, + Columns: []*schema.Column{PaymentOrdersColumns[37]}, + }, + { + Name: "paymentorder_status", + Unique: false, + Columns: []*schema.Column{PaymentOrdersColumns[19]}, + }, + { + Name: "paymentorder_expires_at", + Unique: false, + Columns: []*schema.Column{PaymentOrdersColumns[27]}, + }, + { + Name: "paymentorder_created_at", + Unique: false, + Columns: []*schema.Column{PaymentOrdersColumns[35]}, + }, + { + Name: "paymentorder_paid_at", + Unique: false, + Columns: []*schema.Column{PaymentOrdersColumns[28]}, + }, + { + Name: "paymentorder_payment_type_paid_at", + Unique: false, + Columns: []*schema.Column{PaymentOrdersColumns[9], PaymentOrdersColumns[28]}, + }, + { + Name: "paymentorder_order_type", + Unique: false, + Columns: []*schema.Column{PaymentOrdersColumns[14]}, + }, + }, + } + // 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: "payment_mode", Type: field.TypeString, Size: 20, Default: ""}, + {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}, @@ -671,6 +823,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}, @@ -1128,12 +1315,16 @@ var ( ErrorPassthroughRulesTable, GroupsTable, IdempotencyRecordsTable, + PaymentAuditLogsTable, + PaymentOrdersTable, + PaymentProviderInstancesTable, PromoCodesTable, PromoCodeUsagesTable, ProxiesTable, RedeemCodesTable, SecuritySecretsTable, SettingsTable, + SubscriptionPlansTable, TLSFingerprintProfilesTable, UsageCleanupTasksTable, UsageLogsTable, @@ -1177,6 +1368,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", } @@ -1199,6 +1400,9 @@ func init() { SettingsTable.Annotation = &entsql.Annotation{ Table: "settings", } + SubscriptionPlansTable.Annotation = &entsql.Annotation{ + Table: "subscription_plans", + } TLSFingerprintProfilesTable.Annotation = &entsql.Annotation{ Table: "tls_fingerprint_profiles", } diff --git a/backend/ent/mutation.go b/backend/ent/mutation.go index 594e5199..6b2fa838 100644 --- a/backend/ent/mutation.go +++ b/backend/ent/mutation.go @@ -20,6 +20,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" @@ -27,6 +30,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" @@ -55,12 +59,16 @@ const ( TypeErrorPassthroughRule = "ErrorPassthroughRule" TypeGroup = "Group" TypeIdempotencyRecord = "IdempotencyRecord" + TypePaymentAuditLog = "PaymentAuditLog" + TypePaymentOrder = "PaymentOrder" + TypePaymentProviderInstance = "PaymentProviderInstance" TypePromoCode = "PromoCode" TypePromoCodeUsage = "PromoCodeUsage" TypeProxy = "Proxy" TypeRedeemCode = "RedeemCode" TypeSecuritySecret = "SecuritySecret" TypeSetting = "Setting" + TypeSubscriptionPlan = "SubscriptionPlan" TypeTLSFingerprintProfile = "TLSFingerprintProfile" TypeUsageCleanupTask = "UsageCleanupTask" TypeUsageLog = "UsageLog" @@ -12183,6 +12191,4356 @@ func (m *IdempotencyRecordMutation) ResetEdge(name string) error { return fmt.Errorf("unknown IdempotencyRecord edge %s", name) } +// PaymentAuditLogMutation represents an operation that mutates the PaymentAuditLog nodes in the graph. +type PaymentAuditLogMutation struct { + config + op Op + typ string + id *int64 + order_id *string + action *string + detail *string + operator *string + created_at *time.Time + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*PaymentAuditLog, error) + predicates []predicate.PaymentAuditLog +} + +var _ ent.Mutation = (*PaymentAuditLogMutation)(nil) + +// paymentauditlogOption allows management of the mutation configuration using functional options. +type paymentauditlogOption func(*PaymentAuditLogMutation) + +// newPaymentAuditLogMutation creates new mutation for the PaymentAuditLog entity. +func newPaymentAuditLogMutation(c config, op Op, opts ...paymentauditlogOption) *PaymentAuditLogMutation { + m := &PaymentAuditLogMutation{ + config: c, + op: op, + typ: TypePaymentAuditLog, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withPaymentAuditLogID sets the ID field of the mutation. +func withPaymentAuditLogID(id int64) paymentauditlogOption { + return func(m *PaymentAuditLogMutation) { + var ( + err error + once sync.Once + value *PaymentAuditLog + ) + m.oldValue = func(ctx context.Context) (*PaymentAuditLog, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().PaymentAuditLog.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withPaymentAuditLog sets the old PaymentAuditLog of the mutation. +func withPaymentAuditLog(node *PaymentAuditLog) paymentauditlogOption { + return func(m *PaymentAuditLogMutation) { + m.oldValue = func(context.Context) (*PaymentAuditLog, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m PaymentAuditLogMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m PaymentAuditLogMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *PaymentAuditLogMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *PaymentAuditLogMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().PaymentAuditLog.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetOrderID sets the "order_id" field. +func (m *PaymentAuditLogMutation) SetOrderID(s string) { + m.order_id = &s +} + +// OrderID returns the value of the "order_id" field in the mutation. +func (m *PaymentAuditLogMutation) OrderID() (r string, exists bool) { + v := m.order_id + if v == nil { + return + } + return *v, true +} + +// OldOrderID returns the old "order_id" field's value of the PaymentAuditLog entity. +// If the PaymentAuditLog object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentAuditLogMutation) OldOrderID(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldOrderID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldOrderID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOrderID: %w", err) + } + return oldValue.OrderID, nil +} + +// ResetOrderID resets all changes to the "order_id" field. +func (m *PaymentAuditLogMutation) ResetOrderID() { + m.order_id = nil +} + +// SetAction sets the "action" field. +func (m *PaymentAuditLogMutation) SetAction(s string) { + m.action = &s +} + +// Action returns the value of the "action" field in the mutation. +func (m *PaymentAuditLogMutation) Action() (r string, exists bool) { + v := m.action + if v == nil { + return + } + return *v, true +} + +// OldAction returns the old "action" field's value of the PaymentAuditLog entity. +// If the PaymentAuditLog object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentAuditLogMutation) OldAction(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAction is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAction requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAction: %w", err) + } + return oldValue.Action, nil +} + +// ResetAction resets all changes to the "action" field. +func (m *PaymentAuditLogMutation) ResetAction() { + m.action = nil +} + +// SetDetail sets the "detail" field. +func (m *PaymentAuditLogMutation) SetDetail(s string) { + m.detail = &s +} + +// Detail returns the value of the "detail" field in the mutation. +func (m *PaymentAuditLogMutation) Detail() (r string, exists bool) { + v := m.detail + if v == nil { + return + } + return *v, true +} + +// OldDetail returns the old "detail" field's value of the PaymentAuditLog entity. +// If the PaymentAuditLog object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentAuditLogMutation) OldDetail(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDetail is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDetail requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDetail: %w", err) + } + return oldValue.Detail, nil +} + +// ResetDetail resets all changes to the "detail" field. +func (m *PaymentAuditLogMutation) ResetDetail() { + m.detail = nil +} + +// SetOperator sets the "operator" field. +func (m *PaymentAuditLogMutation) SetOperator(s string) { + m.operator = &s +} + +// Operator returns the value of the "operator" field in the mutation. +func (m *PaymentAuditLogMutation) Operator() (r string, exists bool) { + v := m.operator + if v == nil { + return + } + return *v, true +} + +// OldOperator returns the old "operator" field's value of the PaymentAuditLog entity. +// If the PaymentAuditLog object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentAuditLogMutation) OldOperator(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldOperator is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldOperator requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOperator: %w", err) + } + return oldValue.Operator, nil +} + +// ResetOperator resets all changes to the "operator" field. +func (m *PaymentAuditLogMutation) ResetOperator() { + m.operator = nil +} + +// SetCreatedAt sets the "created_at" field. +func (m *PaymentAuditLogMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *PaymentAuditLogMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the PaymentAuditLog entity. +// If the PaymentAuditLog object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentAuditLogMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *PaymentAuditLogMutation) ResetCreatedAt() { + m.created_at = nil +} + +// Where appends a list predicates to the PaymentAuditLogMutation builder. +func (m *PaymentAuditLogMutation) Where(ps ...predicate.PaymentAuditLog) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the PaymentAuditLogMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *PaymentAuditLogMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.PaymentAuditLog, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *PaymentAuditLogMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *PaymentAuditLogMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (PaymentAuditLog). +func (m *PaymentAuditLogMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *PaymentAuditLogMutation) Fields() []string { + fields := make([]string, 0, 5) + if m.order_id != nil { + fields = append(fields, paymentauditlog.FieldOrderID) + } + if m.action != nil { + fields = append(fields, paymentauditlog.FieldAction) + } + if m.detail != nil { + fields = append(fields, paymentauditlog.FieldDetail) + } + if m.operator != nil { + fields = append(fields, paymentauditlog.FieldOperator) + } + if m.created_at != nil { + fields = append(fields, paymentauditlog.FieldCreatedAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *PaymentAuditLogMutation) Field(name string) (ent.Value, bool) { + switch name { + case paymentauditlog.FieldOrderID: + return m.OrderID() + case paymentauditlog.FieldAction: + return m.Action() + case paymentauditlog.FieldDetail: + return m.Detail() + case paymentauditlog.FieldOperator: + return m.Operator() + case paymentauditlog.FieldCreatedAt: + return m.CreatedAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *PaymentAuditLogMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case paymentauditlog.FieldOrderID: + return m.OldOrderID(ctx) + case paymentauditlog.FieldAction: + return m.OldAction(ctx) + case paymentauditlog.FieldDetail: + return m.OldDetail(ctx) + case paymentauditlog.FieldOperator: + return m.OldOperator(ctx) + case paymentauditlog.FieldCreatedAt: + return m.OldCreatedAt(ctx) + } + return nil, fmt.Errorf("unknown PaymentAuditLog field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *PaymentAuditLogMutation) SetField(name string, value ent.Value) error { + switch name { + case paymentauditlog.FieldOrderID: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOrderID(v) + return nil + case paymentauditlog.FieldAction: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetAction(v) + return nil + case paymentauditlog.FieldDetail: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDetail(v) + return nil + case paymentauditlog.FieldOperator: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOperator(v) + return nil + case paymentauditlog.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + } + return fmt.Errorf("unknown PaymentAuditLog field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *PaymentAuditLogMutation) AddedFields() []string { + return nil +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *PaymentAuditLogMutation) AddedField(name string) (ent.Value, bool) { + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *PaymentAuditLogMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown PaymentAuditLog numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *PaymentAuditLogMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *PaymentAuditLogMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *PaymentAuditLogMutation) ClearField(name string) error { + return fmt.Errorf("unknown PaymentAuditLog nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *PaymentAuditLogMutation) ResetField(name string) error { + switch name { + case paymentauditlog.FieldOrderID: + m.ResetOrderID() + return nil + case paymentauditlog.FieldAction: + m.ResetAction() + return nil + case paymentauditlog.FieldDetail: + m.ResetDetail() + return nil + case paymentauditlog.FieldOperator: + m.ResetOperator() + return nil + case paymentauditlog.FieldCreatedAt: + m.ResetCreatedAt() + return nil + } + return fmt.Errorf("unknown PaymentAuditLog field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *PaymentAuditLogMutation) AddedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *PaymentAuditLogMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *PaymentAuditLogMutation) RemovedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *PaymentAuditLogMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *PaymentAuditLogMutation) ClearedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *PaymentAuditLogMutation) EdgeCleared(name string) bool { + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *PaymentAuditLogMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown PaymentAuditLog unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *PaymentAuditLogMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown PaymentAuditLog edge %s", name) +} + +// PaymentOrderMutation represents an operation that mutates the PaymentOrder nodes in the graph. +type PaymentOrderMutation struct { + config + op Op + typ string + id *int64 + user_email *string + user_name *string + user_notes *string + amount *float64 + addamount *float64 + pay_amount *float64 + addpay_amount *float64 + fee_rate *float64 + addfee_rate *float64 + recharge_code *string + out_trade_no *string + payment_type *string + payment_trade_no *string + pay_url *string + qr_code *string + qr_code_img *string + order_type *string + plan_id *int64 + addplan_id *int64 + subscription_group_id *int64 + addsubscription_group_id *int64 + subscription_days *int + addsubscription_days *int + provider_instance_id *string + status *string + refund_amount *float64 + addrefund_amount *float64 + refund_reason *string + refund_at *time.Time + force_refund *bool + refund_requested_at *time.Time + refund_request_reason *string + refund_requested_by *string + expires_at *time.Time + paid_at *time.Time + completed_at *time.Time + failed_at *time.Time + failed_reason *string + client_ip *string + src_host *string + src_url *string + created_at *time.Time + updated_at *time.Time + clearedFields map[string]struct{} + user *int64 + cleareduser bool + done bool + oldValue func(context.Context) (*PaymentOrder, error) + predicates []predicate.PaymentOrder +} + +var _ ent.Mutation = (*PaymentOrderMutation)(nil) + +// paymentorderOption allows management of the mutation configuration using functional options. +type paymentorderOption func(*PaymentOrderMutation) + +// newPaymentOrderMutation creates new mutation for the PaymentOrder entity. +func newPaymentOrderMutation(c config, op Op, opts ...paymentorderOption) *PaymentOrderMutation { + m := &PaymentOrderMutation{ + config: c, + op: op, + typ: TypePaymentOrder, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withPaymentOrderID sets the ID field of the mutation. +func withPaymentOrderID(id int64) paymentorderOption { + return func(m *PaymentOrderMutation) { + var ( + err error + once sync.Once + value *PaymentOrder + ) + m.oldValue = func(ctx context.Context) (*PaymentOrder, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().PaymentOrder.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withPaymentOrder sets the old PaymentOrder of the mutation. +func withPaymentOrder(node *PaymentOrder) paymentorderOption { + return func(m *PaymentOrderMutation) { + m.oldValue = func(context.Context) (*PaymentOrder, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m PaymentOrderMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m PaymentOrderMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *PaymentOrderMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *PaymentOrderMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().PaymentOrder.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetUserID sets the "user_id" field. +func (m *PaymentOrderMutation) SetUserID(i int64) { + m.user = &i +} + +// UserID returns the value of the "user_id" field in the mutation. +func (m *PaymentOrderMutation) UserID() (r int64, exists bool) { + v := m.user + if v == nil { + return + } + return *v, true +} + +// OldUserID returns the old "user_id" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldUserID(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUserID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUserID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUserID: %w", err) + } + return oldValue.UserID, nil +} + +// ResetUserID resets all changes to the "user_id" field. +func (m *PaymentOrderMutation) ResetUserID() { + m.user = nil +} + +// SetUserEmail sets the "user_email" field. +func (m *PaymentOrderMutation) SetUserEmail(s string) { + m.user_email = &s +} + +// UserEmail returns the value of the "user_email" field in the mutation. +func (m *PaymentOrderMutation) UserEmail() (r string, exists bool) { + v := m.user_email + if v == nil { + return + } + return *v, true +} + +// OldUserEmail returns the old "user_email" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldUserEmail(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUserEmail is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUserEmail requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUserEmail: %w", err) + } + return oldValue.UserEmail, nil +} + +// ResetUserEmail resets all changes to the "user_email" field. +func (m *PaymentOrderMutation) ResetUserEmail() { + m.user_email = nil +} + +// SetUserName sets the "user_name" field. +func (m *PaymentOrderMutation) SetUserName(s string) { + m.user_name = &s +} + +// UserName returns the value of the "user_name" field in the mutation. +func (m *PaymentOrderMutation) UserName() (r string, exists bool) { + v := m.user_name + if v == nil { + return + } + return *v, true +} + +// OldUserName returns the old "user_name" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldUserName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUserName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUserName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUserName: %w", err) + } + return oldValue.UserName, nil +} + +// ResetUserName resets all changes to the "user_name" field. +func (m *PaymentOrderMutation) ResetUserName() { + m.user_name = nil +} + +// SetUserNotes sets the "user_notes" field. +func (m *PaymentOrderMutation) SetUserNotes(s string) { + m.user_notes = &s +} + +// UserNotes returns the value of the "user_notes" field in the mutation. +func (m *PaymentOrderMutation) UserNotes() (r string, exists bool) { + v := m.user_notes + if v == nil { + return + } + return *v, true +} + +// OldUserNotes returns the old "user_notes" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldUserNotes(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUserNotes is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUserNotes requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUserNotes: %w", err) + } + return oldValue.UserNotes, nil +} + +// ClearUserNotes clears the value of the "user_notes" field. +func (m *PaymentOrderMutation) ClearUserNotes() { + m.user_notes = nil + m.clearedFields[paymentorder.FieldUserNotes] = struct{}{} +} + +// UserNotesCleared returns if the "user_notes" field was cleared in this mutation. +func (m *PaymentOrderMutation) UserNotesCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldUserNotes] + return ok +} + +// ResetUserNotes resets all changes to the "user_notes" field. +func (m *PaymentOrderMutation) ResetUserNotes() { + m.user_notes = nil + delete(m.clearedFields, paymentorder.FieldUserNotes) +} + +// SetAmount sets the "amount" field. +func (m *PaymentOrderMutation) SetAmount(f float64) { + m.amount = &f + m.addamount = nil +} + +// Amount returns the value of the "amount" field in the mutation. +func (m *PaymentOrderMutation) Amount() (r float64, exists bool) { + v := m.amount + if v == nil { + return + } + return *v, true +} + +// OldAmount returns the old "amount" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldAmount(ctx context.Context) (v float64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAmount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAmount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAmount: %w", err) + } + return oldValue.Amount, nil +} + +// AddAmount adds f to the "amount" field. +func (m *PaymentOrderMutation) AddAmount(f float64) { + if m.addamount != nil { + *m.addamount += f + } else { + m.addamount = &f + } +} + +// AddedAmount returns the value that was added to the "amount" field in this mutation. +func (m *PaymentOrderMutation) AddedAmount() (r float64, exists bool) { + v := m.addamount + if v == nil { + return + } + return *v, true +} + +// ResetAmount resets all changes to the "amount" field. +func (m *PaymentOrderMutation) ResetAmount() { + m.amount = nil + m.addamount = nil +} + +// SetPayAmount sets the "pay_amount" field. +func (m *PaymentOrderMutation) SetPayAmount(f float64) { + m.pay_amount = &f + m.addpay_amount = nil +} + +// PayAmount returns the value of the "pay_amount" field in the mutation. +func (m *PaymentOrderMutation) PayAmount() (r float64, exists bool) { + v := m.pay_amount + if v == nil { + return + } + return *v, true +} + +// OldPayAmount returns the old "pay_amount" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldPayAmount(ctx context.Context) (v float64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPayAmount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPayAmount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPayAmount: %w", err) + } + return oldValue.PayAmount, nil +} + +// AddPayAmount adds f to the "pay_amount" field. +func (m *PaymentOrderMutation) AddPayAmount(f float64) { + if m.addpay_amount != nil { + *m.addpay_amount += f + } else { + m.addpay_amount = &f + } +} + +// AddedPayAmount returns the value that was added to the "pay_amount" field in this mutation. +func (m *PaymentOrderMutation) AddedPayAmount() (r float64, exists bool) { + v := m.addpay_amount + if v == nil { + return + } + return *v, true +} + +// ResetPayAmount resets all changes to the "pay_amount" field. +func (m *PaymentOrderMutation) ResetPayAmount() { + m.pay_amount = nil + m.addpay_amount = nil +} + +// SetFeeRate sets the "fee_rate" field. +func (m *PaymentOrderMutation) SetFeeRate(f float64) { + m.fee_rate = &f + m.addfee_rate = nil +} + +// FeeRate returns the value of the "fee_rate" field in the mutation. +func (m *PaymentOrderMutation) FeeRate() (r float64, exists bool) { + v := m.fee_rate + if v == nil { + return + } + return *v, true +} + +// OldFeeRate returns the old "fee_rate" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldFeeRate(ctx context.Context) (v float64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldFeeRate is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldFeeRate requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFeeRate: %w", err) + } + return oldValue.FeeRate, nil +} + +// AddFeeRate adds f to the "fee_rate" field. +func (m *PaymentOrderMutation) AddFeeRate(f float64) { + if m.addfee_rate != nil { + *m.addfee_rate += f + } else { + m.addfee_rate = &f + } +} + +// AddedFeeRate returns the value that was added to the "fee_rate" field in this mutation. +func (m *PaymentOrderMutation) AddedFeeRate() (r float64, exists bool) { + v := m.addfee_rate + if v == nil { + return + } + return *v, true +} + +// ResetFeeRate resets all changes to the "fee_rate" field. +func (m *PaymentOrderMutation) ResetFeeRate() { + m.fee_rate = nil + m.addfee_rate = nil +} + +// SetRechargeCode sets the "recharge_code" field. +func (m *PaymentOrderMutation) SetRechargeCode(s string) { + m.recharge_code = &s +} + +// RechargeCode returns the value of the "recharge_code" field in the mutation. +func (m *PaymentOrderMutation) RechargeCode() (r string, exists bool) { + v := m.recharge_code + if v == nil { + return + } + return *v, true +} + +// OldRechargeCode returns the old "recharge_code" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldRechargeCode(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRechargeCode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRechargeCode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRechargeCode: %w", err) + } + return oldValue.RechargeCode, nil +} + +// ResetRechargeCode resets all changes to the "recharge_code" field. +func (m *PaymentOrderMutation) ResetRechargeCode() { + m.recharge_code = nil +} + +// SetOutTradeNo sets the "out_trade_no" field. +func (m *PaymentOrderMutation) SetOutTradeNo(s string) { + m.out_trade_no = &s +} + +// OutTradeNo returns the value of the "out_trade_no" field in the mutation. +func (m *PaymentOrderMutation) OutTradeNo() (r string, exists bool) { + v := m.out_trade_no + if v == nil { + return + } + return *v, true +} + +// OldOutTradeNo returns the old "out_trade_no" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldOutTradeNo(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldOutTradeNo is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldOutTradeNo requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOutTradeNo: %w", err) + } + return oldValue.OutTradeNo, nil +} + +// ResetOutTradeNo resets all changes to the "out_trade_no" field. +func (m *PaymentOrderMutation) ResetOutTradeNo() { + m.out_trade_no = nil +} + +// SetPaymentType sets the "payment_type" field. +func (m *PaymentOrderMutation) SetPaymentType(s string) { + m.payment_type = &s +} + +// PaymentType returns the value of the "payment_type" field in the mutation. +func (m *PaymentOrderMutation) PaymentType() (r string, exists bool) { + v := m.payment_type + if v == nil { + return + } + return *v, true +} + +// OldPaymentType returns the old "payment_type" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldPaymentType(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPaymentType is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPaymentType requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPaymentType: %w", err) + } + return oldValue.PaymentType, nil +} + +// ResetPaymentType resets all changes to the "payment_type" field. +func (m *PaymentOrderMutation) ResetPaymentType() { + m.payment_type = nil +} + +// SetPaymentTradeNo sets the "payment_trade_no" field. +func (m *PaymentOrderMutation) SetPaymentTradeNo(s string) { + m.payment_trade_no = &s +} + +// PaymentTradeNo returns the value of the "payment_trade_no" field in the mutation. +func (m *PaymentOrderMutation) PaymentTradeNo() (r string, exists bool) { + v := m.payment_trade_no + if v == nil { + return + } + return *v, true +} + +// OldPaymentTradeNo returns the old "payment_trade_no" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldPaymentTradeNo(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPaymentTradeNo is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPaymentTradeNo requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPaymentTradeNo: %w", err) + } + return oldValue.PaymentTradeNo, nil +} + +// ResetPaymentTradeNo resets all changes to the "payment_trade_no" field. +func (m *PaymentOrderMutation) ResetPaymentTradeNo() { + m.payment_trade_no = nil +} + +// SetPayURL sets the "pay_url" field. +func (m *PaymentOrderMutation) SetPayURL(s string) { + m.pay_url = &s +} + +// PayURL returns the value of the "pay_url" field in the mutation. +func (m *PaymentOrderMutation) PayURL() (r string, exists bool) { + v := m.pay_url + if v == nil { + return + } + return *v, true +} + +// OldPayURL returns the old "pay_url" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldPayURL(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPayURL is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPayURL requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPayURL: %w", err) + } + return oldValue.PayURL, nil +} + +// ClearPayURL clears the value of the "pay_url" field. +func (m *PaymentOrderMutation) ClearPayURL() { + m.pay_url = nil + m.clearedFields[paymentorder.FieldPayURL] = struct{}{} +} + +// PayURLCleared returns if the "pay_url" field was cleared in this mutation. +func (m *PaymentOrderMutation) PayURLCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldPayURL] + return ok +} + +// ResetPayURL resets all changes to the "pay_url" field. +func (m *PaymentOrderMutation) ResetPayURL() { + m.pay_url = nil + delete(m.clearedFields, paymentorder.FieldPayURL) +} + +// SetQrCode sets the "qr_code" field. +func (m *PaymentOrderMutation) SetQrCode(s string) { + m.qr_code = &s +} + +// QrCode returns the value of the "qr_code" field in the mutation. +func (m *PaymentOrderMutation) QrCode() (r string, exists bool) { + v := m.qr_code + if v == nil { + return + } + return *v, true +} + +// OldQrCode returns the old "qr_code" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldQrCode(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldQrCode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldQrCode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldQrCode: %w", err) + } + return oldValue.QrCode, nil +} + +// ClearQrCode clears the value of the "qr_code" field. +func (m *PaymentOrderMutation) ClearQrCode() { + m.qr_code = nil + m.clearedFields[paymentorder.FieldQrCode] = struct{}{} +} + +// QrCodeCleared returns if the "qr_code" field was cleared in this mutation. +func (m *PaymentOrderMutation) QrCodeCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldQrCode] + return ok +} + +// ResetQrCode resets all changes to the "qr_code" field. +func (m *PaymentOrderMutation) ResetQrCode() { + m.qr_code = nil + delete(m.clearedFields, paymentorder.FieldQrCode) +} + +// SetQrCodeImg sets the "qr_code_img" field. +func (m *PaymentOrderMutation) SetQrCodeImg(s string) { + m.qr_code_img = &s +} + +// QrCodeImg returns the value of the "qr_code_img" field in the mutation. +func (m *PaymentOrderMutation) QrCodeImg() (r string, exists bool) { + v := m.qr_code_img + if v == nil { + return + } + return *v, true +} + +// OldQrCodeImg returns the old "qr_code_img" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldQrCodeImg(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldQrCodeImg is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldQrCodeImg requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldQrCodeImg: %w", err) + } + return oldValue.QrCodeImg, nil +} + +// ClearQrCodeImg clears the value of the "qr_code_img" field. +func (m *PaymentOrderMutation) ClearQrCodeImg() { + m.qr_code_img = nil + m.clearedFields[paymentorder.FieldQrCodeImg] = struct{}{} +} + +// QrCodeImgCleared returns if the "qr_code_img" field was cleared in this mutation. +func (m *PaymentOrderMutation) QrCodeImgCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldQrCodeImg] + return ok +} + +// ResetQrCodeImg resets all changes to the "qr_code_img" field. +func (m *PaymentOrderMutation) ResetQrCodeImg() { + m.qr_code_img = nil + delete(m.clearedFields, paymentorder.FieldQrCodeImg) +} + +// SetOrderType sets the "order_type" field. +func (m *PaymentOrderMutation) SetOrderType(s string) { + m.order_type = &s +} + +// OrderType returns the value of the "order_type" field in the mutation. +func (m *PaymentOrderMutation) OrderType() (r string, exists bool) { + v := m.order_type + if v == nil { + return + } + return *v, true +} + +// OldOrderType returns the old "order_type" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldOrderType(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldOrderType is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldOrderType requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOrderType: %w", err) + } + return oldValue.OrderType, nil +} + +// ResetOrderType resets all changes to the "order_type" field. +func (m *PaymentOrderMutation) ResetOrderType() { + m.order_type = nil +} + +// SetPlanID sets the "plan_id" field. +func (m *PaymentOrderMutation) SetPlanID(i int64) { + m.plan_id = &i + m.addplan_id = nil +} + +// PlanID returns the value of the "plan_id" field in the mutation. +func (m *PaymentOrderMutation) PlanID() (r int64, exists bool) { + v := m.plan_id + if v == nil { + return + } + return *v, true +} + +// OldPlanID returns the old "plan_id" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldPlanID(ctx context.Context) (v *int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPlanID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPlanID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPlanID: %w", err) + } + return oldValue.PlanID, nil +} + +// AddPlanID adds i to the "plan_id" field. +func (m *PaymentOrderMutation) AddPlanID(i int64) { + if m.addplan_id != nil { + *m.addplan_id += i + } else { + m.addplan_id = &i + } +} + +// AddedPlanID returns the value that was added to the "plan_id" field in this mutation. +func (m *PaymentOrderMutation) AddedPlanID() (r int64, exists bool) { + v := m.addplan_id + if v == nil { + return + } + return *v, true +} + +// ClearPlanID clears the value of the "plan_id" field. +func (m *PaymentOrderMutation) ClearPlanID() { + m.plan_id = nil + m.addplan_id = nil + m.clearedFields[paymentorder.FieldPlanID] = struct{}{} +} + +// PlanIDCleared returns if the "plan_id" field was cleared in this mutation. +func (m *PaymentOrderMutation) PlanIDCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldPlanID] + return ok +} + +// ResetPlanID resets all changes to the "plan_id" field. +func (m *PaymentOrderMutation) ResetPlanID() { + m.plan_id = nil + m.addplan_id = nil + delete(m.clearedFields, paymentorder.FieldPlanID) +} + +// SetSubscriptionGroupID sets the "subscription_group_id" field. +func (m *PaymentOrderMutation) SetSubscriptionGroupID(i int64) { + m.subscription_group_id = &i + m.addsubscription_group_id = nil +} + +// SubscriptionGroupID returns the value of the "subscription_group_id" field in the mutation. +func (m *PaymentOrderMutation) SubscriptionGroupID() (r int64, exists bool) { + v := m.subscription_group_id + if v == nil { + return + } + return *v, true +} + +// OldSubscriptionGroupID returns the old "subscription_group_id" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldSubscriptionGroupID(ctx context.Context) (v *int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSubscriptionGroupID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSubscriptionGroupID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSubscriptionGroupID: %w", err) + } + return oldValue.SubscriptionGroupID, nil +} + +// AddSubscriptionGroupID adds i to the "subscription_group_id" field. +func (m *PaymentOrderMutation) AddSubscriptionGroupID(i int64) { + if m.addsubscription_group_id != nil { + *m.addsubscription_group_id += i + } else { + m.addsubscription_group_id = &i + } +} + +// AddedSubscriptionGroupID returns the value that was added to the "subscription_group_id" field in this mutation. +func (m *PaymentOrderMutation) AddedSubscriptionGroupID() (r int64, exists bool) { + v := m.addsubscription_group_id + if v == nil { + return + } + return *v, true +} + +// ClearSubscriptionGroupID clears the value of the "subscription_group_id" field. +func (m *PaymentOrderMutation) ClearSubscriptionGroupID() { + m.subscription_group_id = nil + m.addsubscription_group_id = nil + m.clearedFields[paymentorder.FieldSubscriptionGroupID] = struct{}{} +} + +// SubscriptionGroupIDCleared returns if the "subscription_group_id" field was cleared in this mutation. +func (m *PaymentOrderMutation) SubscriptionGroupIDCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldSubscriptionGroupID] + return ok +} + +// ResetSubscriptionGroupID resets all changes to the "subscription_group_id" field. +func (m *PaymentOrderMutation) ResetSubscriptionGroupID() { + m.subscription_group_id = nil + m.addsubscription_group_id = nil + delete(m.clearedFields, paymentorder.FieldSubscriptionGroupID) +} + +// SetSubscriptionDays sets the "subscription_days" field. +func (m *PaymentOrderMutation) SetSubscriptionDays(i int) { + m.subscription_days = &i + m.addsubscription_days = nil +} + +// SubscriptionDays returns the value of the "subscription_days" field in the mutation. +func (m *PaymentOrderMutation) SubscriptionDays() (r int, exists bool) { + v := m.subscription_days + if v == nil { + return + } + return *v, true +} + +// OldSubscriptionDays returns the old "subscription_days" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldSubscriptionDays(ctx context.Context) (v *int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSubscriptionDays is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSubscriptionDays requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSubscriptionDays: %w", err) + } + return oldValue.SubscriptionDays, nil +} + +// AddSubscriptionDays adds i to the "subscription_days" field. +func (m *PaymentOrderMutation) AddSubscriptionDays(i int) { + if m.addsubscription_days != nil { + *m.addsubscription_days += i + } else { + m.addsubscription_days = &i + } +} + +// AddedSubscriptionDays returns the value that was added to the "subscription_days" field in this mutation. +func (m *PaymentOrderMutation) AddedSubscriptionDays() (r int, exists bool) { + v := m.addsubscription_days + if v == nil { + return + } + return *v, true +} + +// ClearSubscriptionDays clears the value of the "subscription_days" field. +func (m *PaymentOrderMutation) ClearSubscriptionDays() { + m.subscription_days = nil + m.addsubscription_days = nil + m.clearedFields[paymentorder.FieldSubscriptionDays] = struct{}{} +} + +// SubscriptionDaysCleared returns if the "subscription_days" field was cleared in this mutation. +func (m *PaymentOrderMutation) SubscriptionDaysCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldSubscriptionDays] + return ok +} + +// ResetSubscriptionDays resets all changes to the "subscription_days" field. +func (m *PaymentOrderMutation) ResetSubscriptionDays() { + m.subscription_days = nil + m.addsubscription_days = nil + delete(m.clearedFields, paymentorder.FieldSubscriptionDays) +} + +// SetProviderInstanceID sets the "provider_instance_id" field. +func (m *PaymentOrderMutation) SetProviderInstanceID(s string) { + m.provider_instance_id = &s +} + +// ProviderInstanceID returns the value of the "provider_instance_id" field in the mutation. +func (m *PaymentOrderMutation) ProviderInstanceID() (r string, exists bool) { + v := m.provider_instance_id + if v == nil { + return + } + return *v, true +} + +// OldProviderInstanceID returns the old "provider_instance_id" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldProviderInstanceID(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProviderInstanceID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProviderInstanceID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProviderInstanceID: %w", err) + } + return oldValue.ProviderInstanceID, nil +} + +// ClearProviderInstanceID clears the value of the "provider_instance_id" field. +func (m *PaymentOrderMutation) ClearProviderInstanceID() { + m.provider_instance_id = nil + m.clearedFields[paymentorder.FieldProviderInstanceID] = struct{}{} +} + +// ProviderInstanceIDCleared returns if the "provider_instance_id" field was cleared in this mutation. +func (m *PaymentOrderMutation) ProviderInstanceIDCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldProviderInstanceID] + return ok +} + +// ResetProviderInstanceID resets all changes to the "provider_instance_id" field. +func (m *PaymentOrderMutation) ResetProviderInstanceID() { + m.provider_instance_id = nil + delete(m.clearedFields, paymentorder.FieldProviderInstanceID) +} + +// SetStatus sets the "status" field. +func (m *PaymentOrderMutation) SetStatus(s string) { + m.status = &s +} + +// Status returns the value of the "status" field in the mutation. +func (m *PaymentOrderMutation) Status() (r string, exists bool) { + v := m.status + if v == nil { + return + } + return *v, true +} + +// OldStatus returns the old "status" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldStatus(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldStatus is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldStatus requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldStatus: %w", err) + } + return oldValue.Status, nil +} + +// ResetStatus resets all changes to the "status" field. +func (m *PaymentOrderMutation) ResetStatus() { + m.status = nil +} + +// SetRefundAmount sets the "refund_amount" field. +func (m *PaymentOrderMutation) SetRefundAmount(f float64) { + m.refund_amount = &f + m.addrefund_amount = nil +} + +// RefundAmount returns the value of the "refund_amount" field in the mutation. +func (m *PaymentOrderMutation) RefundAmount() (r float64, exists bool) { + v := m.refund_amount + if v == nil { + return + } + return *v, true +} + +// OldRefundAmount returns the old "refund_amount" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldRefundAmount(ctx context.Context) (v float64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRefundAmount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRefundAmount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRefundAmount: %w", err) + } + return oldValue.RefundAmount, nil +} + +// AddRefundAmount adds f to the "refund_amount" field. +func (m *PaymentOrderMutation) AddRefundAmount(f float64) { + if m.addrefund_amount != nil { + *m.addrefund_amount += f + } else { + m.addrefund_amount = &f + } +} + +// AddedRefundAmount returns the value that was added to the "refund_amount" field in this mutation. +func (m *PaymentOrderMutation) AddedRefundAmount() (r float64, exists bool) { + v := m.addrefund_amount + if v == nil { + return + } + return *v, true +} + +// ResetRefundAmount resets all changes to the "refund_amount" field. +func (m *PaymentOrderMutation) ResetRefundAmount() { + m.refund_amount = nil + m.addrefund_amount = nil +} + +// SetRefundReason sets the "refund_reason" field. +func (m *PaymentOrderMutation) SetRefundReason(s string) { + m.refund_reason = &s +} + +// RefundReason returns the value of the "refund_reason" field in the mutation. +func (m *PaymentOrderMutation) RefundReason() (r string, exists bool) { + v := m.refund_reason + if v == nil { + return + } + return *v, true +} + +// OldRefundReason returns the old "refund_reason" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldRefundReason(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRefundReason is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRefundReason requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRefundReason: %w", err) + } + return oldValue.RefundReason, nil +} + +// ClearRefundReason clears the value of the "refund_reason" field. +func (m *PaymentOrderMutation) ClearRefundReason() { + m.refund_reason = nil + m.clearedFields[paymentorder.FieldRefundReason] = struct{}{} +} + +// RefundReasonCleared returns if the "refund_reason" field was cleared in this mutation. +func (m *PaymentOrderMutation) RefundReasonCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldRefundReason] + return ok +} + +// ResetRefundReason resets all changes to the "refund_reason" field. +func (m *PaymentOrderMutation) ResetRefundReason() { + m.refund_reason = nil + delete(m.clearedFields, paymentorder.FieldRefundReason) +} + +// SetRefundAt sets the "refund_at" field. +func (m *PaymentOrderMutation) SetRefundAt(t time.Time) { + m.refund_at = &t +} + +// RefundAt returns the value of the "refund_at" field in the mutation. +func (m *PaymentOrderMutation) RefundAt() (r time.Time, exists bool) { + v := m.refund_at + if v == nil { + return + } + return *v, true +} + +// OldRefundAt returns the old "refund_at" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldRefundAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRefundAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRefundAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRefundAt: %w", err) + } + return oldValue.RefundAt, nil +} + +// ClearRefundAt clears the value of the "refund_at" field. +func (m *PaymentOrderMutation) ClearRefundAt() { + m.refund_at = nil + m.clearedFields[paymentorder.FieldRefundAt] = struct{}{} +} + +// RefundAtCleared returns if the "refund_at" field was cleared in this mutation. +func (m *PaymentOrderMutation) RefundAtCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldRefundAt] + return ok +} + +// ResetRefundAt resets all changes to the "refund_at" field. +func (m *PaymentOrderMutation) ResetRefundAt() { + m.refund_at = nil + delete(m.clearedFields, paymentorder.FieldRefundAt) +} + +// SetForceRefund sets the "force_refund" field. +func (m *PaymentOrderMutation) SetForceRefund(b bool) { + m.force_refund = &b +} + +// ForceRefund returns the value of the "force_refund" field in the mutation. +func (m *PaymentOrderMutation) ForceRefund() (r bool, exists bool) { + v := m.force_refund + if v == nil { + return + } + return *v, true +} + +// OldForceRefund returns the old "force_refund" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldForceRefund(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldForceRefund is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldForceRefund requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldForceRefund: %w", err) + } + return oldValue.ForceRefund, nil +} + +// ResetForceRefund resets all changes to the "force_refund" field. +func (m *PaymentOrderMutation) ResetForceRefund() { + m.force_refund = nil +} + +// SetRefundRequestedAt sets the "refund_requested_at" field. +func (m *PaymentOrderMutation) SetRefundRequestedAt(t time.Time) { + m.refund_requested_at = &t +} + +// RefundRequestedAt returns the value of the "refund_requested_at" field in the mutation. +func (m *PaymentOrderMutation) RefundRequestedAt() (r time.Time, exists bool) { + v := m.refund_requested_at + if v == nil { + return + } + return *v, true +} + +// OldRefundRequestedAt returns the old "refund_requested_at" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldRefundRequestedAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRefundRequestedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRefundRequestedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRefundRequestedAt: %w", err) + } + return oldValue.RefundRequestedAt, nil +} + +// ClearRefundRequestedAt clears the value of the "refund_requested_at" field. +func (m *PaymentOrderMutation) ClearRefundRequestedAt() { + m.refund_requested_at = nil + m.clearedFields[paymentorder.FieldRefundRequestedAt] = struct{}{} +} + +// RefundRequestedAtCleared returns if the "refund_requested_at" field was cleared in this mutation. +func (m *PaymentOrderMutation) RefundRequestedAtCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldRefundRequestedAt] + return ok +} + +// ResetRefundRequestedAt resets all changes to the "refund_requested_at" field. +func (m *PaymentOrderMutation) ResetRefundRequestedAt() { + m.refund_requested_at = nil + delete(m.clearedFields, paymentorder.FieldRefundRequestedAt) +} + +// SetRefundRequestReason sets the "refund_request_reason" field. +func (m *PaymentOrderMutation) SetRefundRequestReason(s string) { + m.refund_request_reason = &s +} + +// RefundRequestReason returns the value of the "refund_request_reason" field in the mutation. +func (m *PaymentOrderMutation) RefundRequestReason() (r string, exists bool) { + v := m.refund_request_reason + if v == nil { + return + } + return *v, true +} + +// OldRefundRequestReason returns the old "refund_request_reason" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldRefundRequestReason(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRefundRequestReason is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRefundRequestReason requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRefundRequestReason: %w", err) + } + return oldValue.RefundRequestReason, nil +} + +// ClearRefundRequestReason clears the value of the "refund_request_reason" field. +func (m *PaymentOrderMutation) ClearRefundRequestReason() { + m.refund_request_reason = nil + m.clearedFields[paymentorder.FieldRefundRequestReason] = struct{}{} +} + +// RefundRequestReasonCleared returns if the "refund_request_reason" field was cleared in this mutation. +func (m *PaymentOrderMutation) RefundRequestReasonCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldRefundRequestReason] + return ok +} + +// ResetRefundRequestReason resets all changes to the "refund_request_reason" field. +func (m *PaymentOrderMutation) ResetRefundRequestReason() { + m.refund_request_reason = nil + delete(m.clearedFields, paymentorder.FieldRefundRequestReason) +} + +// SetRefundRequestedBy sets the "refund_requested_by" field. +func (m *PaymentOrderMutation) SetRefundRequestedBy(s string) { + m.refund_requested_by = &s +} + +// RefundRequestedBy returns the value of the "refund_requested_by" field in the mutation. +func (m *PaymentOrderMutation) RefundRequestedBy() (r string, exists bool) { + v := m.refund_requested_by + if v == nil { + return + } + return *v, true +} + +// OldRefundRequestedBy returns the old "refund_requested_by" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldRefundRequestedBy(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRefundRequestedBy is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRefundRequestedBy requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRefundRequestedBy: %w", err) + } + return oldValue.RefundRequestedBy, nil +} + +// ClearRefundRequestedBy clears the value of the "refund_requested_by" field. +func (m *PaymentOrderMutation) ClearRefundRequestedBy() { + m.refund_requested_by = nil + m.clearedFields[paymentorder.FieldRefundRequestedBy] = struct{}{} +} + +// RefundRequestedByCleared returns if the "refund_requested_by" field was cleared in this mutation. +func (m *PaymentOrderMutation) RefundRequestedByCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldRefundRequestedBy] + return ok +} + +// ResetRefundRequestedBy resets all changes to the "refund_requested_by" field. +func (m *PaymentOrderMutation) ResetRefundRequestedBy() { + m.refund_requested_by = nil + delete(m.clearedFields, paymentorder.FieldRefundRequestedBy) +} + +// SetExpiresAt sets the "expires_at" field. +func (m *PaymentOrderMutation) SetExpiresAt(t time.Time) { + m.expires_at = &t +} + +// ExpiresAt returns the value of the "expires_at" field in the mutation. +func (m *PaymentOrderMutation) ExpiresAt() (r time.Time, exists bool) { + v := m.expires_at + if v == nil { + return + } + return *v, true +} + +// OldExpiresAt returns the old "expires_at" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldExpiresAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldExpiresAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldExpiresAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldExpiresAt: %w", err) + } + return oldValue.ExpiresAt, nil +} + +// ResetExpiresAt resets all changes to the "expires_at" field. +func (m *PaymentOrderMutation) ResetExpiresAt() { + m.expires_at = nil +} + +// SetPaidAt sets the "paid_at" field. +func (m *PaymentOrderMutation) SetPaidAt(t time.Time) { + m.paid_at = &t +} + +// PaidAt returns the value of the "paid_at" field in the mutation. +func (m *PaymentOrderMutation) PaidAt() (r time.Time, exists bool) { + v := m.paid_at + if v == nil { + return + } + return *v, true +} + +// OldPaidAt returns the old "paid_at" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldPaidAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPaidAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPaidAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPaidAt: %w", err) + } + return oldValue.PaidAt, nil +} + +// ClearPaidAt clears the value of the "paid_at" field. +func (m *PaymentOrderMutation) ClearPaidAt() { + m.paid_at = nil + m.clearedFields[paymentorder.FieldPaidAt] = struct{}{} +} + +// PaidAtCleared returns if the "paid_at" field was cleared in this mutation. +func (m *PaymentOrderMutation) PaidAtCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldPaidAt] + return ok +} + +// ResetPaidAt resets all changes to the "paid_at" field. +func (m *PaymentOrderMutation) ResetPaidAt() { + m.paid_at = nil + delete(m.clearedFields, paymentorder.FieldPaidAt) +} + +// SetCompletedAt sets the "completed_at" field. +func (m *PaymentOrderMutation) SetCompletedAt(t time.Time) { + m.completed_at = &t +} + +// CompletedAt returns the value of the "completed_at" field in the mutation. +func (m *PaymentOrderMutation) CompletedAt() (r time.Time, exists bool) { + v := m.completed_at + if v == nil { + return + } + return *v, true +} + +// OldCompletedAt returns the old "completed_at" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldCompletedAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCompletedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCompletedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCompletedAt: %w", err) + } + return oldValue.CompletedAt, nil +} + +// ClearCompletedAt clears the value of the "completed_at" field. +func (m *PaymentOrderMutation) ClearCompletedAt() { + m.completed_at = nil + m.clearedFields[paymentorder.FieldCompletedAt] = struct{}{} +} + +// CompletedAtCleared returns if the "completed_at" field was cleared in this mutation. +func (m *PaymentOrderMutation) CompletedAtCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldCompletedAt] + return ok +} + +// ResetCompletedAt resets all changes to the "completed_at" field. +func (m *PaymentOrderMutation) ResetCompletedAt() { + m.completed_at = nil + delete(m.clearedFields, paymentorder.FieldCompletedAt) +} + +// SetFailedAt sets the "failed_at" field. +func (m *PaymentOrderMutation) SetFailedAt(t time.Time) { + m.failed_at = &t +} + +// FailedAt returns the value of the "failed_at" field in the mutation. +func (m *PaymentOrderMutation) FailedAt() (r time.Time, exists bool) { + v := m.failed_at + if v == nil { + return + } + return *v, true +} + +// OldFailedAt returns the old "failed_at" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldFailedAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldFailedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldFailedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFailedAt: %w", err) + } + return oldValue.FailedAt, nil +} + +// ClearFailedAt clears the value of the "failed_at" field. +func (m *PaymentOrderMutation) ClearFailedAt() { + m.failed_at = nil + m.clearedFields[paymentorder.FieldFailedAt] = struct{}{} +} + +// FailedAtCleared returns if the "failed_at" field was cleared in this mutation. +func (m *PaymentOrderMutation) FailedAtCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldFailedAt] + return ok +} + +// ResetFailedAt resets all changes to the "failed_at" field. +func (m *PaymentOrderMutation) ResetFailedAt() { + m.failed_at = nil + delete(m.clearedFields, paymentorder.FieldFailedAt) +} + +// SetFailedReason sets the "failed_reason" field. +func (m *PaymentOrderMutation) SetFailedReason(s string) { + m.failed_reason = &s +} + +// FailedReason returns the value of the "failed_reason" field in the mutation. +func (m *PaymentOrderMutation) FailedReason() (r string, exists bool) { + v := m.failed_reason + if v == nil { + return + } + return *v, true +} + +// OldFailedReason returns the old "failed_reason" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldFailedReason(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldFailedReason is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldFailedReason requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFailedReason: %w", err) + } + return oldValue.FailedReason, nil +} + +// ClearFailedReason clears the value of the "failed_reason" field. +func (m *PaymentOrderMutation) ClearFailedReason() { + m.failed_reason = nil + m.clearedFields[paymentorder.FieldFailedReason] = struct{}{} +} + +// FailedReasonCleared returns if the "failed_reason" field was cleared in this mutation. +func (m *PaymentOrderMutation) FailedReasonCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldFailedReason] + return ok +} + +// ResetFailedReason resets all changes to the "failed_reason" field. +func (m *PaymentOrderMutation) ResetFailedReason() { + m.failed_reason = nil + delete(m.clearedFields, paymentorder.FieldFailedReason) +} + +// SetClientIP sets the "client_ip" field. +func (m *PaymentOrderMutation) SetClientIP(s string) { + m.client_ip = &s +} + +// ClientIP returns the value of the "client_ip" field in the mutation. +func (m *PaymentOrderMutation) ClientIP() (r string, exists bool) { + v := m.client_ip + if v == nil { + return + } + return *v, true +} + +// OldClientIP returns the old "client_ip" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldClientIP(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldClientIP is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldClientIP requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldClientIP: %w", err) + } + return oldValue.ClientIP, nil +} + +// ResetClientIP resets all changes to the "client_ip" field. +func (m *PaymentOrderMutation) ResetClientIP() { + m.client_ip = nil +} + +// SetSrcHost sets the "src_host" field. +func (m *PaymentOrderMutation) SetSrcHost(s string) { + m.src_host = &s +} + +// SrcHost returns the value of the "src_host" field in the mutation. +func (m *PaymentOrderMutation) SrcHost() (r string, exists bool) { + v := m.src_host + if v == nil { + return + } + return *v, true +} + +// OldSrcHost returns the old "src_host" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldSrcHost(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSrcHost is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSrcHost requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSrcHost: %w", err) + } + return oldValue.SrcHost, nil +} + +// ResetSrcHost resets all changes to the "src_host" field. +func (m *PaymentOrderMutation) ResetSrcHost() { + m.src_host = nil +} + +// SetSrcURL sets the "src_url" field. +func (m *PaymentOrderMutation) SetSrcURL(s string) { + m.src_url = &s +} + +// SrcURL returns the value of the "src_url" field in the mutation. +func (m *PaymentOrderMutation) SrcURL() (r string, exists bool) { + v := m.src_url + if v == nil { + return + } + return *v, true +} + +// OldSrcURL returns the old "src_url" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldSrcURL(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSrcURL is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSrcURL requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSrcURL: %w", err) + } + return oldValue.SrcURL, nil +} + +// ClearSrcURL clears the value of the "src_url" field. +func (m *PaymentOrderMutation) ClearSrcURL() { + m.src_url = nil + m.clearedFields[paymentorder.FieldSrcURL] = struct{}{} +} + +// SrcURLCleared returns if the "src_url" field was cleared in this mutation. +func (m *PaymentOrderMutation) SrcURLCleared() bool { + _, ok := m.clearedFields[paymentorder.FieldSrcURL] + return ok +} + +// ResetSrcURL resets all changes to the "src_url" field. +func (m *PaymentOrderMutation) ResetSrcURL() { + m.src_url = nil + delete(m.clearedFields, paymentorder.FieldSrcURL) +} + +// SetCreatedAt sets the "created_at" field. +func (m *PaymentOrderMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *PaymentOrderMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *PaymentOrderMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *PaymentOrderMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *PaymentOrderMutation) UpdatedAt() (r time.Time, exists bool) { + v := m.updated_at + if v == nil { + return + } + return *v, true +} + +// OldUpdatedAt returns the old "updated_at" field's value of the PaymentOrder entity. +// If the PaymentOrder object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentOrderMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err) + } + return oldValue.UpdatedAt, nil +} + +// ResetUpdatedAt resets all changes to the "updated_at" field. +func (m *PaymentOrderMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// ClearUser clears the "user" edge to the User entity. +func (m *PaymentOrderMutation) ClearUser() { + m.cleareduser = true + m.clearedFields[paymentorder.FieldUserID] = struct{}{} +} + +// UserCleared reports if the "user" edge to the User entity was cleared. +func (m *PaymentOrderMutation) UserCleared() bool { + return m.cleareduser +} + +// UserIDs returns the "user" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// UserID instead. It exists only for internal usage by the builders. +func (m *PaymentOrderMutation) UserIDs() (ids []int64) { + if id := m.user; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetUser resets all changes to the "user" edge. +func (m *PaymentOrderMutation) ResetUser() { + m.user = nil + m.cleareduser = false +} + +// Where appends a list predicates to the PaymentOrderMutation builder. +func (m *PaymentOrderMutation) Where(ps ...predicate.PaymentOrder) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the PaymentOrderMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *PaymentOrderMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.PaymentOrder, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *PaymentOrderMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *PaymentOrderMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (PaymentOrder). +func (m *PaymentOrderMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *PaymentOrderMutation) Fields() []string { + fields := make([]string, 0, 37) + if m.user != nil { + fields = append(fields, paymentorder.FieldUserID) + } + if m.user_email != nil { + fields = append(fields, paymentorder.FieldUserEmail) + } + if m.user_name != nil { + fields = append(fields, paymentorder.FieldUserName) + } + if m.user_notes != nil { + fields = append(fields, paymentorder.FieldUserNotes) + } + if m.amount != nil { + fields = append(fields, paymentorder.FieldAmount) + } + if m.pay_amount != nil { + fields = append(fields, paymentorder.FieldPayAmount) + } + if m.fee_rate != nil { + fields = append(fields, paymentorder.FieldFeeRate) + } + if m.recharge_code != nil { + fields = append(fields, paymentorder.FieldRechargeCode) + } + if m.out_trade_no != nil { + fields = append(fields, paymentorder.FieldOutTradeNo) + } + if m.payment_type != nil { + fields = append(fields, paymentorder.FieldPaymentType) + } + if m.payment_trade_no != nil { + fields = append(fields, paymentorder.FieldPaymentTradeNo) + } + if m.pay_url != nil { + fields = append(fields, paymentorder.FieldPayURL) + } + if m.qr_code != nil { + fields = append(fields, paymentorder.FieldQrCode) + } + if m.qr_code_img != nil { + fields = append(fields, paymentorder.FieldQrCodeImg) + } + if m.order_type != nil { + fields = append(fields, paymentorder.FieldOrderType) + } + if m.plan_id != nil { + fields = append(fields, paymentorder.FieldPlanID) + } + if m.subscription_group_id != nil { + fields = append(fields, paymentorder.FieldSubscriptionGroupID) + } + if m.subscription_days != nil { + fields = append(fields, paymentorder.FieldSubscriptionDays) + } + if m.provider_instance_id != nil { + fields = append(fields, paymentorder.FieldProviderInstanceID) + } + if m.status != nil { + fields = append(fields, paymentorder.FieldStatus) + } + if m.refund_amount != nil { + fields = append(fields, paymentorder.FieldRefundAmount) + } + if m.refund_reason != nil { + fields = append(fields, paymentorder.FieldRefundReason) + } + if m.refund_at != nil { + fields = append(fields, paymentorder.FieldRefundAt) + } + if m.force_refund != nil { + fields = append(fields, paymentorder.FieldForceRefund) + } + if m.refund_requested_at != nil { + fields = append(fields, paymentorder.FieldRefundRequestedAt) + } + if m.refund_request_reason != nil { + fields = append(fields, paymentorder.FieldRefundRequestReason) + } + if m.refund_requested_by != nil { + fields = append(fields, paymentorder.FieldRefundRequestedBy) + } + if m.expires_at != nil { + fields = append(fields, paymentorder.FieldExpiresAt) + } + if m.paid_at != nil { + fields = append(fields, paymentorder.FieldPaidAt) + } + if m.completed_at != nil { + fields = append(fields, paymentorder.FieldCompletedAt) + } + if m.failed_at != nil { + fields = append(fields, paymentorder.FieldFailedAt) + } + if m.failed_reason != nil { + fields = append(fields, paymentorder.FieldFailedReason) + } + if m.client_ip != nil { + fields = append(fields, paymentorder.FieldClientIP) + } + if m.src_host != nil { + fields = append(fields, paymentorder.FieldSrcHost) + } + if m.src_url != nil { + fields = append(fields, paymentorder.FieldSrcURL) + } + if m.created_at != nil { + fields = append(fields, paymentorder.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, paymentorder.FieldUpdatedAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *PaymentOrderMutation) Field(name string) (ent.Value, bool) { + switch name { + case paymentorder.FieldUserID: + return m.UserID() + case paymentorder.FieldUserEmail: + return m.UserEmail() + case paymentorder.FieldUserName: + return m.UserName() + case paymentorder.FieldUserNotes: + return m.UserNotes() + case paymentorder.FieldAmount: + return m.Amount() + case paymentorder.FieldPayAmount: + return m.PayAmount() + case paymentorder.FieldFeeRate: + return m.FeeRate() + case paymentorder.FieldRechargeCode: + return m.RechargeCode() + case paymentorder.FieldOutTradeNo: + return m.OutTradeNo() + case paymentorder.FieldPaymentType: + return m.PaymentType() + case paymentorder.FieldPaymentTradeNo: + return m.PaymentTradeNo() + case paymentorder.FieldPayURL: + return m.PayURL() + case paymentorder.FieldQrCode: + return m.QrCode() + case paymentorder.FieldQrCodeImg: + return m.QrCodeImg() + case paymentorder.FieldOrderType: + return m.OrderType() + case paymentorder.FieldPlanID: + return m.PlanID() + case paymentorder.FieldSubscriptionGroupID: + return m.SubscriptionGroupID() + case paymentorder.FieldSubscriptionDays: + return m.SubscriptionDays() + case paymentorder.FieldProviderInstanceID: + return m.ProviderInstanceID() + case paymentorder.FieldStatus: + return m.Status() + case paymentorder.FieldRefundAmount: + return m.RefundAmount() + case paymentorder.FieldRefundReason: + return m.RefundReason() + case paymentorder.FieldRefundAt: + return m.RefundAt() + case paymentorder.FieldForceRefund: + return m.ForceRefund() + case paymentorder.FieldRefundRequestedAt: + return m.RefundRequestedAt() + case paymentorder.FieldRefundRequestReason: + return m.RefundRequestReason() + case paymentorder.FieldRefundRequestedBy: + return m.RefundRequestedBy() + case paymentorder.FieldExpiresAt: + return m.ExpiresAt() + case paymentorder.FieldPaidAt: + return m.PaidAt() + case paymentorder.FieldCompletedAt: + return m.CompletedAt() + case paymentorder.FieldFailedAt: + return m.FailedAt() + case paymentorder.FieldFailedReason: + return m.FailedReason() + case paymentorder.FieldClientIP: + return m.ClientIP() + case paymentorder.FieldSrcHost: + return m.SrcHost() + case paymentorder.FieldSrcURL: + return m.SrcURL() + case paymentorder.FieldCreatedAt: + return m.CreatedAt() + case paymentorder.FieldUpdatedAt: + return m.UpdatedAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *PaymentOrderMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case paymentorder.FieldUserID: + return m.OldUserID(ctx) + case paymentorder.FieldUserEmail: + return m.OldUserEmail(ctx) + case paymentorder.FieldUserName: + return m.OldUserName(ctx) + case paymentorder.FieldUserNotes: + return m.OldUserNotes(ctx) + case paymentorder.FieldAmount: + return m.OldAmount(ctx) + case paymentorder.FieldPayAmount: + return m.OldPayAmount(ctx) + case paymentorder.FieldFeeRate: + return m.OldFeeRate(ctx) + case paymentorder.FieldRechargeCode: + return m.OldRechargeCode(ctx) + case paymentorder.FieldOutTradeNo: + return m.OldOutTradeNo(ctx) + case paymentorder.FieldPaymentType: + return m.OldPaymentType(ctx) + case paymentorder.FieldPaymentTradeNo: + return m.OldPaymentTradeNo(ctx) + case paymentorder.FieldPayURL: + return m.OldPayURL(ctx) + case paymentorder.FieldQrCode: + return m.OldQrCode(ctx) + case paymentorder.FieldQrCodeImg: + return m.OldQrCodeImg(ctx) + case paymentorder.FieldOrderType: + return m.OldOrderType(ctx) + case paymentorder.FieldPlanID: + return m.OldPlanID(ctx) + case paymentorder.FieldSubscriptionGroupID: + return m.OldSubscriptionGroupID(ctx) + case paymentorder.FieldSubscriptionDays: + return m.OldSubscriptionDays(ctx) + case paymentorder.FieldProviderInstanceID: + return m.OldProviderInstanceID(ctx) + case paymentorder.FieldStatus: + return m.OldStatus(ctx) + case paymentorder.FieldRefundAmount: + return m.OldRefundAmount(ctx) + case paymentorder.FieldRefundReason: + return m.OldRefundReason(ctx) + case paymentorder.FieldRefundAt: + return m.OldRefundAt(ctx) + case paymentorder.FieldForceRefund: + return m.OldForceRefund(ctx) + case paymentorder.FieldRefundRequestedAt: + return m.OldRefundRequestedAt(ctx) + case paymentorder.FieldRefundRequestReason: + return m.OldRefundRequestReason(ctx) + case paymentorder.FieldRefundRequestedBy: + return m.OldRefundRequestedBy(ctx) + case paymentorder.FieldExpiresAt: + return m.OldExpiresAt(ctx) + case paymentorder.FieldPaidAt: + return m.OldPaidAt(ctx) + case paymentorder.FieldCompletedAt: + return m.OldCompletedAt(ctx) + case paymentorder.FieldFailedAt: + return m.OldFailedAt(ctx) + case paymentorder.FieldFailedReason: + return m.OldFailedReason(ctx) + case paymentorder.FieldClientIP: + return m.OldClientIP(ctx) + case paymentorder.FieldSrcHost: + return m.OldSrcHost(ctx) + case paymentorder.FieldSrcURL: + return m.OldSrcURL(ctx) + case paymentorder.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case paymentorder.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + } + return nil, fmt.Errorf("unknown PaymentOrder field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *PaymentOrderMutation) SetField(name string, value ent.Value) error { + switch name { + case paymentorder.FieldUserID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUserID(v) + return nil + case paymentorder.FieldUserEmail: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUserEmail(v) + return nil + case paymentorder.FieldUserName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUserName(v) + return nil + case paymentorder.FieldUserNotes: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUserNotes(v) + return nil + case paymentorder.FieldAmount: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetAmount(v) + return nil + case paymentorder.FieldPayAmount: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPayAmount(v) + return nil + case paymentorder.FieldFeeRate: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFeeRate(v) + return nil + case paymentorder.FieldRechargeCode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRechargeCode(v) + return nil + case paymentorder.FieldOutTradeNo: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOutTradeNo(v) + return nil + case paymentorder.FieldPaymentType: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPaymentType(v) + return nil + case paymentorder.FieldPaymentTradeNo: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPaymentTradeNo(v) + return nil + case paymentorder.FieldPayURL: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPayURL(v) + return nil + case paymentorder.FieldQrCode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetQrCode(v) + return nil + case paymentorder.FieldQrCodeImg: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetQrCodeImg(v) + return nil + case paymentorder.FieldOrderType: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOrderType(v) + return nil + case paymentorder.FieldPlanID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPlanID(v) + return nil + case paymentorder.FieldSubscriptionGroupID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSubscriptionGroupID(v) + return nil + case paymentorder.FieldSubscriptionDays: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSubscriptionDays(v) + return nil + case paymentorder.FieldProviderInstanceID: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProviderInstanceID(v) + return nil + case paymentorder.FieldStatus: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetStatus(v) + return nil + case paymentorder.FieldRefundAmount: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRefundAmount(v) + return nil + case paymentorder.FieldRefundReason: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRefundReason(v) + return nil + case paymentorder.FieldRefundAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRefundAt(v) + return nil + case paymentorder.FieldForceRefund: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetForceRefund(v) + return nil + case paymentorder.FieldRefundRequestedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRefundRequestedAt(v) + return nil + case paymentorder.FieldRefundRequestReason: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRefundRequestReason(v) + return nil + case paymentorder.FieldRefundRequestedBy: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRefundRequestedBy(v) + return nil + case paymentorder.FieldExpiresAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetExpiresAt(v) + return nil + case paymentorder.FieldPaidAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPaidAt(v) + return nil + case paymentorder.FieldCompletedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCompletedAt(v) + return nil + case paymentorder.FieldFailedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFailedAt(v) + return nil + case paymentorder.FieldFailedReason: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFailedReason(v) + return nil + case paymentorder.FieldClientIP: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetClientIP(v) + return nil + case paymentorder.FieldSrcHost: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSrcHost(v) + return nil + case paymentorder.FieldSrcURL: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSrcURL(v) + return nil + case paymentorder.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case paymentorder.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + } + return fmt.Errorf("unknown PaymentOrder field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *PaymentOrderMutation) AddedFields() []string { + var fields []string + if m.addamount != nil { + fields = append(fields, paymentorder.FieldAmount) + } + if m.addpay_amount != nil { + fields = append(fields, paymentorder.FieldPayAmount) + } + if m.addfee_rate != nil { + fields = append(fields, paymentorder.FieldFeeRate) + } + if m.addplan_id != nil { + fields = append(fields, paymentorder.FieldPlanID) + } + if m.addsubscription_group_id != nil { + fields = append(fields, paymentorder.FieldSubscriptionGroupID) + } + if m.addsubscription_days != nil { + fields = append(fields, paymentorder.FieldSubscriptionDays) + } + if m.addrefund_amount != nil { + fields = append(fields, paymentorder.FieldRefundAmount) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *PaymentOrderMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case paymentorder.FieldAmount: + return m.AddedAmount() + case paymentorder.FieldPayAmount: + return m.AddedPayAmount() + case paymentorder.FieldFeeRate: + return m.AddedFeeRate() + case paymentorder.FieldPlanID: + return m.AddedPlanID() + case paymentorder.FieldSubscriptionGroupID: + return m.AddedSubscriptionGroupID() + case paymentorder.FieldSubscriptionDays: + return m.AddedSubscriptionDays() + case paymentorder.FieldRefundAmount: + return m.AddedRefundAmount() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *PaymentOrderMutation) AddField(name string, value ent.Value) error { + switch name { + case paymentorder.FieldAmount: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddAmount(v) + return nil + case paymentorder.FieldPayAmount: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddPayAmount(v) + return nil + case paymentorder.FieldFeeRate: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddFeeRate(v) + return nil + case paymentorder.FieldPlanID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddPlanID(v) + return nil + case paymentorder.FieldSubscriptionGroupID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddSubscriptionGroupID(v) + return nil + case paymentorder.FieldSubscriptionDays: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddSubscriptionDays(v) + return nil + case paymentorder.FieldRefundAmount: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddRefundAmount(v) + return nil + } + return fmt.Errorf("unknown PaymentOrder numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *PaymentOrderMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(paymentorder.FieldUserNotes) { + fields = append(fields, paymentorder.FieldUserNotes) + } + if m.FieldCleared(paymentorder.FieldPayURL) { + fields = append(fields, paymentorder.FieldPayURL) + } + if m.FieldCleared(paymentorder.FieldQrCode) { + fields = append(fields, paymentorder.FieldQrCode) + } + if m.FieldCleared(paymentorder.FieldQrCodeImg) { + fields = append(fields, paymentorder.FieldQrCodeImg) + } + if m.FieldCleared(paymentorder.FieldPlanID) { + fields = append(fields, paymentorder.FieldPlanID) + } + if m.FieldCleared(paymentorder.FieldSubscriptionGroupID) { + fields = append(fields, paymentorder.FieldSubscriptionGroupID) + } + if m.FieldCleared(paymentorder.FieldSubscriptionDays) { + fields = append(fields, paymentorder.FieldSubscriptionDays) + } + if m.FieldCleared(paymentorder.FieldProviderInstanceID) { + fields = append(fields, paymentorder.FieldProviderInstanceID) + } + if m.FieldCleared(paymentorder.FieldRefundReason) { + fields = append(fields, paymentorder.FieldRefundReason) + } + if m.FieldCleared(paymentorder.FieldRefundAt) { + fields = append(fields, paymentorder.FieldRefundAt) + } + if m.FieldCleared(paymentorder.FieldRefundRequestedAt) { + fields = append(fields, paymentorder.FieldRefundRequestedAt) + } + if m.FieldCleared(paymentorder.FieldRefundRequestReason) { + fields = append(fields, paymentorder.FieldRefundRequestReason) + } + if m.FieldCleared(paymentorder.FieldRefundRequestedBy) { + fields = append(fields, paymentorder.FieldRefundRequestedBy) + } + if m.FieldCleared(paymentorder.FieldPaidAt) { + fields = append(fields, paymentorder.FieldPaidAt) + } + if m.FieldCleared(paymentorder.FieldCompletedAt) { + fields = append(fields, paymentorder.FieldCompletedAt) + } + if m.FieldCleared(paymentorder.FieldFailedAt) { + fields = append(fields, paymentorder.FieldFailedAt) + } + if m.FieldCleared(paymentorder.FieldFailedReason) { + fields = append(fields, paymentorder.FieldFailedReason) + } + if m.FieldCleared(paymentorder.FieldSrcURL) { + fields = append(fields, paymentorder.FieldSrcURL) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *PaymentOrderMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *PaymentOrderMutation) ClearField(name string) error { + switch name { + case paymentorder.FieldUserNotes: + m.ClearUserNotes() + return nil + case paymentorder.FieldPayURL: + m.ClearPayURL() + return nil + case paymentorder.FieldQrCode: + m.ClearQrCode() + return nil + case paymentorder.FieldQrCodeImg: + m.ClearQrCodeImg() + return nil + case paymentorder.FieldPlanID: + m.ClearPlanID() + return nil + case paymentorder.FieldSubscriptionGroupID: + m.ClearSubscriptionGroupID() + return nil + case paymentorder.FieldSubscriptionDays: + m.ClearSubscriptionDays() + return nil + case paymentorder.FieldProviderInstanceID: + m.ClearProviderInstanceID() + return nil + case paymentorder.FieldRefundReason: + m.ClearRefundReason() + return nil + case paymentorder.FieldRefundAt: + m.ClearRefundAt() + return nil + case paymentorder.FieldRefundRequestedAt: + m.ClearRefundRequestedAt() + return nil + case paymentorder.FieldRefundRequestReason: + m.ClearRefundRequestReason() + return nil + case paymentorder.FieldRefundRequestedBy: + m.ClearRefundRequestedBy() + return nil + case paymentorder.FieldPaidAt: + m.ClearPaidAt() + return nil + case paymentorder.FieldCompletedAt: + m.ClearCompletedAt() + return nil + case paymentorder.FieldFailedAt: + m.ClearFailedAt() + return nil + case paymentorder.FieldFailedReason: + m.ClearFailedReason() + return nil + case paymentorder.FieldSrcURL: + m.ClearSrcURL() + return nil + } + return fmt.Errorf("unknown PaymentOrder nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *PaymentOrderMutation) ResetField(name string) error { + switch name { + case paymentorder.FieldUserID: + m.ResetUserID() + return nil + case paymentorder.FieldUserEmail: + m.ResetUserEmail() + return nil + case paymentorder.FieldUserName: + m.ResetUserName() + return nil + case paymentorder.FieldUserNotes: + m.ResetUserNotes() + return nil + case paymentorder.FieldAmount: + m.ResetAmount() + return nil + case paymentorder.FieldPayAmount: + m.ResetPayAmount() + return nil + case paymentorder.FieldFeeRate: + m.ResetFeeRate() + return nil + case paymentorder.FieldRechargeCode: + m.ResetRechargeCode() + return nil + case paymentorder.FieldOutTradeNo: + m.ResetOutTradeNo() + return nil + case paymentorder.FieldPaymentType: + m.ResetPaymentType() + return nil + case paymentorder.FieldPaymentTradeNo: + m.ResetPaymentTradeNo() + return nil + case paymentorder.FieldPayURL: + m.ResetPayURL() + return nil + case paymentorder.FieldQrCode: + m.ResetQrCode() + return nil + case paymentorder.FieldQrCodeImg: + m.ResetQrCodeImg() + return nil + case paymentorder.FieldOrderType: + m.ResetOrderType() + return nil + case paymentorder.FieldPlanID: + m.ResetPlanID() + return nil + case paymentorder.FieldSubscriptionGroupID: + m.ResetSubscriptionGroupID() + return nil + case paymentorder.FieldSubscriptionDays: + m.ResetSubscriptionDays() + return nil + case paymentorder.FieldProviderInstanceID: + m.ResetProviderInstanceID() + return nil + case paymentorder.FieldStatus: + m.ResetStatus() + return nil + case paymentorder.FieldRefundAmount: + m.ResetRefundAmount() + return nil + case paymentorder.FieldRefundReason: + m.ResetRefundReason() + return nil + case paymentorder.FieldRefundAt: + m.ResetRefundAt() + return nil + case paymentorder.FieldForceRefund: + m.ResetForceRefund() + return nil + case paymentorder.FieldRefundRequestedAt: + m.ResetRefundRequestedAt() + return nil + case paymentorder.FieldRefundRequestReason: + m.ResetRefundRequestReason() + return nil + case paymentorder.FieldRefundRequestedBy: + m.ResetRefundRequestedBy() + return nil + case paymentorder.FieldExpiresAt: + m.ResetExpiresAt() + return nil + case paymentorder.FieldPaidAt: + m.ResetPaidAt() + return nil + case paymentorder.FieldCompletedAt: + m.ResetCompletedAt() + return nil + case paymentorder.FieldFailedAt: + m.ResetFailedAt() + return nil + case paymentorder.FieldFailedReason: + m.ResetFailedReason() + return nil + case paymentorder.FieldClientIP: + m.ResetClientIP() + return nil + case paymentorder.FieldSrcHost: + m.ResetSrcHost() + return nil + case paymentorder.FieldSrcURL: + m.ResetSrcURL() + return nil + case paymentorder.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case paymentorder.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + } + return fmt.Errorf("unknown PaymentOrder field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *PaymentOrderMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.user != nil { + edges = append(edges, paymentorder.EdgeUser) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *PaymentOrderMutation) AddedIDs(name string) []ent.Value { + switch name { + case paymentorder.EdgeUser: + if id := m.user; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *PaymentOrderMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *PaymentOrderMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *PaymentOrderMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.cleareduser { + edges = append(edges, paymentorder.EdgeUser) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *PaymentOrderMutation) EdgeCleared(name string) bool { + switch name { + case paymentorder.EdgeUser: + return m.cleareduser + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *PaymentOrderMutation) ClearEdge(name string) error { + switch name { + case paymentorder.EdgeUser: + m.ClearUser() + return nil + } + return fmt.Errorf("unknown PaymentOrder unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *PaymentOrderMutation) ResetEdge(name string) error { + switch name { + case paymentorder.EdgeUser: + m.ResetUser() + return nil + } + return fmt.Errorf("unknown PaymentOrder edge %s", name) +} + +// PaymentProviderInstanceMutation represents an operation that mutates the PaymentProviderInstance nodes in the graph. +type PaymentProviderInstanceMutation struct { + config + op Op + typ string + id *int64 + provider_key *string + name *string + _config *string + supported_types *string + enabled *bool + payment_mode *string + sort_order *int + addsort_order *int + limits *string + refund_enabled *bool + created_at *time.Time + updated_at *time.Time + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*PaymentProviderInstance, error) + predicates []predicate.PaymentProviderInstance +} + +var _ ent.Mutation = (*PaymentProviderInstanceMutation)(nil) + +// paymentproviderinstanceOption allows management of the mutation configuration using functional options. +type paymentproviderinstanceOption func(*PaymentProviderInstanceMutation) + +// newPaymentProviderInstanceMutation creates new mutation for the PaymentProviderInstance entity. +func newPaymentProviderInstanceMutation(c config, op Op, opts ...paymentproviderinstanceOption) *PaymentProviderInstanceMutation { + m := &PaymentProviderInstanceMutation{ + config: c, + op: op, + typ: TypePaymentProviderInstance, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withPaymentProviderInstanceID sets the ID field of the mutation. +func withPaymentProviderInstanceID(id int64) paymentproviderinstanceOption { + return func(m *PaymentProviderInstanceMutation) { + var ( + err error + once sync.Once + value *PaymentProviderInstance + ) + m.oldValue = func(ctx context.Context) (*PaymentProviderInstance, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().PaymentProviderInstance.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withPaymentProviderInstance sets the old PaymentProviderInstance of the mutation. +func withPaymentProviderInstance(node *PaymentProviderInstance) paymentproviderinstanceOption { + return func(m *PaymentProviderInstanceMutation) { + m.oldValue = func(context.Context) (*PaymentProviderInstance, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m PaymentProviderInstanceMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m PaymentProviderInstanceMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *PaymentProviderInstanceMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *PaymentProviderInstanceMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().PaymentProviderInstance.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetProviderKey sets the "provider_key" field. +func (m *PaymentProviderInstanceMutation) SetProviderKey(s string) { + m.provider_key = &s +} + +// ProviderKey returns the value of the "provider_key" field in the mutation. +func (m *PaymentProviderInstanceMutation) ProviderKey() (r string, exists bool) { + v := m.provider_key + if v == nil { + return + } + return *v, true +} + +// OldProviderKey returns the old "provider_key" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldProviderKey(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProviderKey is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProviderKey requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProviderKey: %w", err) + } + return oldValue.ProviderKey, nil +} + +// ResetProviderKey resets all changes to the "provider_key" field. +func (m *PaymentProviderInstanceMutation) ResetProviderKey() { + m.provider_key = nil +} + +// SetName sets the "name" field. +func (m *PaymentProviderInstanceMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *PaymentProviderInstanceMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *PaymentProviderInstanceMutation) ResetName() { + m.name = nil +} + +// SetConfig sets the "config" field. +func (m *PaymentProviderInstanceMutation) SetConfig(s string) { + m._config = &s +} + +// Config returns the value of the "config" field in the mutation. +func (m *PaymentProviderInstanceMutation) Config() (r string, exists bool) { + v := m._config + if v == nil { + return + } + return *v, true +} + +// OldConfig returns the old "config" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldConfig(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldConfig is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldConfig requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldConfig: %w", err) + } + return oldValue.Config, nil +} + +// ResetConfig resets all changes to the "config" field. +func (m *PaymentProviderInstanceMutation) ResetConfig() { + m._config = nil +} + +// SetSupportedTypes sets the "supported_types" field. +func (m *PaymentProviderInstanceMutation) SetSupportedTypes(s string) { + m.supported_types = &s +} + +// SupportedTypes returns the value of the "supported_types" field in the mutation. +func (m *PaymentProviderInstanceMutation) SupportedTypes() (r string, exists bool) { + v := m.supported_types + if v == nil { + return + } + return *v, true +} + +// OldSupportedTypes returns the old "supported_types" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldSupportedTypes(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSupportedTypes is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSupportedTypes requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSupportedTypes: %w", err) + } + return oldValue.SupportedTypes, nil +} + +// ResetSupportedTypes resets all changes to the "supported_types" field. +func (m *PaymentProviderInstanceMutation) ResetSupportedTypes() { + m.supported_types = nil +} + +// SetEnabled sets the "enabled" field. +func (m *PaymentProviderInstanceMutation) SetEnabled(b bool) { + m.enabled = &b +} + +// Enabled returns the value of the "enabled" field in the mutation. +func (m *PaymentProviderInstanceMutation) Enabled() (r bool, exists bool) { + v := m.enabled + if v == nil { + return + } + return *v, true +} + +// OldEnabled returns the old "enabled" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldEnabled(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldEnabled is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldEnabled requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldEnabled: %w", err) + } + return oldValue.Enabled, nil +} + +// ResetEnabled resets all changes to the "enabled" field. +func (m *PaymentProviderInstanceMutation) ResetEnabled() { + m.enabled = nil +} + +// SetPaymentMode sets the "payment_mode" field. +func (m *PaymentProviderInstanceMutation) SetPaymentMode(s string) { + m.payment_mode = &s +} + +// PaymentMode returns the value of the "payment_mode" field in the mutation. +func (m *PaymentProviderInstanceMutation) PaymentMode() (r string, exists bool) { + v := m.payment_mode + if v == nil { + return + } + return *v, true +} + +// OldPaymentMode returns the old "payment_mode" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldPaymentMode(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPaymentMode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPaymentMode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPaymentMode: %w", err) + } + return oldValue.PaymentMode, nil +} + +// ResetPaymentMode resets all changes to the "payment_mode" field. +func (m *PaymentProviderInstanceMutation) ResetPaymentMode() { + m.payment_mode = nil +} + +// SetSortOrder sets the "sort_order" field. +func (m *PaymentProviderInstanceMutation) SetSortOrder(i int) { + m.sort_order = &i + m.addsort_order = nil +} + +// SortOrder returns the value of the "sort_order" field in the mutation. +func (m *PaymentProviderInstanceMutation) SortOrder() (r int, exists bool) { + v := m.sort_order + if v == nil { + return + } + return *v, true +} + +// OldSortOrder returns the old "sort_order" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldSortOrder(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSortOrder is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSortOrder requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSortOrder: %w", err) + } + return oldValue.SortOrder, nil +} + +// AddSortOrder adds i to the "sort_order" field. +func (m *PaymentProviderInstanceMutation) AddSortOrder(i int) { + if m.addsort_order != nil { + *m.addsort_order += i + } else { + m.addsort_order = &i + } +} + +// AddedSortOrder returns the value that was added to the "sort_order" field in this mutation. +func (m *PaymentProviderInstanceMutation) AddedSortOrder() (r int, exists bool) { + v := m.addsort_order + if v == nil { + return + } + return *v, true +} + +// ResetSortOrder resets all changes to the "sort_order" field. +func (m *PaymentProviderInstanceMutation) ResetSortOrder() { + m.sort_order = nil + m.addsort_order = nil +} + +// SetLimits sets the "limits" field. +func (m *PaymentProviderInstanceMutation) SetLimits(s string) { + m.limits = &s +} + +// Limits returns the value of the "limits" field in the mutation. +func (m *PaymentProviderInstanceMutation) Limits() (r string, exists bool) { + v := m.limits + if v == nil { + return + } + return *v, true +} + +// OldLimits returns the old "limits" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldLimits(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldLimits is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldLimits requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldLimits: %w", err) + } + return oldValue.Limits, nil +} + +// ResetLimits resets all changes to the "limits" field. +func (m *PaymentProviderInstanceMutation) ResetLimits() { + m.limits = nil +} + +// SetRefundEnabled sets the "refund_enabled" field. +func (m *PaymentProviderInstanceMutation) SetRefundEnabled(b bool) { + m.refund_enabled = &b +} + +// RefundEnabled returns the value of the "refund_enabled" field in the mutation. +func (m *PaymentProviderInstanceMutation) RefundEnabled() (r bool, exists bool) { + v := m.refund_enabled + if v == nil { + return + } + return *v, true +} + +// OldRefundEnabled returns the old "refund_enabled" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldRefundEnabled(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRefundEnabled is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRefundEnabled requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRefundEnabled: %w", err) + } + return oldValue.RefundEnabled, nil +} + +// ResetRefundEnabled resets all changes to the "refund_enabled" field. +func (m *PaymentProviderInstanceMutation) ResetRefundEnabled() { + m.refund_enabled = nil +} + +// SetCreatedAt sets the "created_at" field. +func (m *PaymentProviderInstanceMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *PaymentProviderInstanceMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *PaymentProviderInstanceMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *PaymentProviderInstanceMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *PaymentProviderInstanceMutation) UpdatedAt() (r time.Time, exists bool) { + v := m.updated_at + if v == nil { + return + } + return *v, true +} + +// OldUpdatedAt returns the old "updated_at" field's value of the PaymentProviderInstance entity. +// If the PaymentProviderInstance object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PaymentProviderInstanceMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err) + } + return oldValue.UpdatedAt, nil +} + +// ResetUpdatedAt resets all changes to the "updated_at" field. +func (m *PaymentProviderInstanceMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// Where appends a list predicates to the PaymentProviderInstanceMutation builder. +func (m *PaymentProviderInstanceMutation) Where(ps ...predicate.PaymentProviderInstance) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the PaymentProviderInstanceMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *PaymentProviderInstanceMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.PaymentProviderInstance, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *PaymentProviderInstanceMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *PaymentProviderInstanceMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (PaymentProviderInstance). +func (m *PaymentProviderInstanceMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *PaymentProviderInstanceMutation) Fields() []string { + fields := make([]string, 0, 11) + if m.provider_key != nil { + fields = append(fields, paymentproviderinstance.FieldProviderKey) + } + if m.name != nil { + fields = append(fields, paymentproviderinstance.FieldName) + } + if m._config != nil { + fields = append(fields, paymentproviderinstance.FieldConfig) + } + if m.supported_types != nil { + fields = append(fields, paymentproviderinstance.FieldSupportedTypes) + } + if m.enabled != nil { + fields = append(fields, paymentproviderinstance.FieldEnabled) + } + if m.payment_mode != nil { + fields = append(fields, paymentproviderinstance.FieldPaymentMode) + } + if m.sort_order != nil { + fields = append(fields, paymentproviderinstance.FieldSortOrder) + } + if m.limits != nil { + fields = append(fields, paymentproviderinstance.FieldLimits) + } + if m.refund_enabled != nil { + fields = append(fields, paymentproviderinstance.FieldRefundEnabled) + } + if m.created_at != nil { + fields = append(fields, paymentproviderinstance.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, paymentproviderinstance.FieldUpdatedAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *PaymentProviderInstanceMutation) Field(name string) (ent.Value, bool) { + switch name { + case paymentproviderinstance.FieldProviderKey: + return m.ProviderKey() + case paymentproviderinstance.FieldName: + return m.Name() + case paymentproviderinstance.FieldConfig: + return m.Config() + case paymentproviderinstance.FieldSupportedTypes: + return m.SupportedTypes() + case paymentproviderinstance.FieldEnabled: + return m.Enabled() + case paymentproviderinstance.FieldPaymentMode: + return m.PaymentMode() + case paymentproviderinstance.FieldSortOrder: + return m.SortOrder() + case paymentproviderinstance.FieldLimits: + return m.Limits() + case paymentproviderinstance.FieldRefundEnabled: + return m.RefundEnabled() + case paymentproviderinstance.FieldCreatedAt: + return m.CreatedAt() + case paymentproviderinstance.FieldUpdatedAt: + return m.UpdatedAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *PaymentProviderInstanceMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case paymentproviderinstance.FieldProviderKey: + return m.OldProviderKey(ctx) + case paymentproviderinstance.FieldName: + return m.OldName(ctx) + case paymentproviderinstance.FieldConfig: + return m.OldConfig(ctx) + case paymentproviderinstance.FieldSupportedTypes: + return m.OldSupportedTypes(ctx) + case paymentproviderinstance.FieldEnabled: + return m.OldEnabled(ctx) + case paymentproviderinstance.FieldPaymentMode: + return m.OldPaymentMode(ctx) + case paymentproviderinstance.FieldSortOrder: + return m.OldSortOrder(ctx) + case paymentproviderinstance.FieldLimits: + return m.OldLimits(ctx) + case paymentproviderinstance.FieldRefundEnabled: + return m.OldRefundEnabled(ctx) + case paymentproviderinstance.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case paymentproviderinstance.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + } + return nil, fmt.Errorf("unknown PaymentProviderInstance field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *PaymentProviderInstanceMutation) SetField(name string, value ent.Value) error { + switch name { + case paymentproviderinstance.FieldProviderKey: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProviderKey(v) + return nil + case paymentproviderinstance.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case paymentproviderinstance.FieldConfig: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetConfig(v) + return nil + case paymentproviderinstance.FieldSupportedTypes: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSupportedTypes(v) + return nil + case paymentproviderinstance.FieldEnabled: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetEnabled(v) + return nil + case paymentproviderinstance.FieldPaymentMode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPaymentMode(v) + return nil + case paymentproviderinstance.FieldSortOrder: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSortOrder(v) + return nil + case paymentproviderinstance.FieldLimits: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetLimits(v) + return nil + case paymentproviderinstance.FieldRefundEnabled: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRefundEnabled(v) + return nil + case paymentproviderinstance.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case paymentproviderinstance.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + } + return fmt.Errorf("unknown PaymentProviderInstance field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *PaymentProviderInstanceMutation) AddedFields() []string { + var fields []string + if m.addsort_order != nil { + fields = append(fields, paymentproviderinstance.FieldSortOrder) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *PaymentProviderInstanceMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case paymentproviderinstance.FieldSortOrder: + return m.AddedSortOrder() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *PaymentProviderInstanceMutation) AddField(name string, value ent.Value) error { + switch name { + case paymentproviderinstance.FieldSortOrder: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddSortOrder(v) + return nil + } + return fmt.Errorf("unknown PaymentProviderInstance numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *PaymentProviderInstanceMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *PaymentProviderInstanceMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *PaymentProviderInstanceMutation) ClearField(name string) error { + return fmt.Errorf("unknown PaymentProviderInstance nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *PaymentProviderInstanceMutation) ResetField(name string) error { + switch name { + case paymentproviderinstance.FieldProviderKey: + m.ResetProviderKey() + return nil + case paymentproviderinstance.FieldName: + m.ResetName() + return nil + case paymentproviderinstance.FieldConfig: + m.ResetConfig() + return nil + case paymentproviderinstance.FieldSupportedTypes: + m.ResetSupportedTypes() + return nil + case paymentproviderinstance.FieldEnabled: + m.ResetEnabled() + return nil + case paymentproviderinstance.FieldPaymentMode: + m.ResetPaymentMode() + return nil + case paymentproviderinstance.FieldSortOrder: + m.ResetSortOrder() + return nil + case paymentproviderinstance.FieldLimits: + m.ResetLimits() + return nil + case paymentproviderinstance.FieldRefundEnabled: + m.ResetRefundEnabled() + return nil + case paymentproviderinstance.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case paymentproviderinstance.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + } + return fmt.Errorf("unknown PaymentProviderInstance field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *PaymentProviderInstanceMutation) AddedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *PaymentProviderInstanceMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *PaymentProviderInstanceMutation) RemovedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *PaymentProviderInstanceMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *PaymentProviderInstanceMutation) ClearedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *PaymentProviderInstanceMutation) EdgeCleared(name string) bool { + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *PaymentProviderInstanceMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown PaymentProviderInstance unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *PaymentProviderInstanceMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown PaymentProviderInstance edge %s", name) +} + // PromoCodeMutation represents an operation that mutates the PromoCode nodes in the graph. type PromoCodeMutation struct { config @@ -16797,6 +21155,1171 @@ func (m *SettingMutation) ResetEdge(name string) error { return fmt.Errorf("unknown Setting edge %s", name) } +// SubscriptionPlanMutation represents an operation that mutates the SubscriptionPlan nodes in the graph. +type SubscriptionPlanMutation struct { + config + op Op + typ string + id *int64 + group_id *int64 + addgroup_id *int64 + name *string + description *string + price *float64 + addprice *float64 + original_price *float64 + addoriginal_price *float64 + validity_days *int + addvalidity_days *int + validity_unit *string + features *string + product_name *string + for_sale *bool + sort_order *int + addsort_order *int + created_at *time.Time + updated_at *time.Time + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*SubscriptionPlan, error) + predicates []predicate.SubscriptionPlan +} + +var _ ent.Mutation = (*SubscriptionPlanMutation)(nil) + +// subscriptionplanOption allows management of the mutation configuration using functional options. +type subscriptionplanOption func(*SubscriptionPlanMutation) + +// newSubscriptionPlanMutation creates new mutation for the SubscriptionPlan entity. +func newSubscriptionPlanMutation(c config, op Op, opts ...subscriptionplanOption) *SubscriptionPlanMutation { + m := &SubscriptionPlanMutation{ + config: c, + op: op, + typ: TypeSubscriptionPlan, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withSubscriptionPlanID sets the ID field of the mutation. +func withSubscriptionPlanID(id int64) subscriptionplanOption { + return func(m *SubscriptionPlanMutation) { + var ( + err error + once sync.Once + value *SubscriptionPlan + ) + m.oldValue = func(ctx context.Context) (*SubscriptionPlan, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().SubscriptionPlan.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withSubscriptionPlan sets the old SubscriptionPlan of the mutation. +func withSubscriptionPlan(node *SubscriptionPlan) subscriptionplanOption { + return func(m *SubscriptionPlanMutation) { + m.oldValue = func(context.Context) (*SubscriptionPlan, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m SubscriptionPlanMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m SubscriptionPlanMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *SubscriptionPlanMutation) ID() (id int64, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *SubscriptionPlanMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().SubscriptionPlan.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetGroupID sets the "group_id" field. +func (m *SubscriptionPlanMutation) SetGroupID(i int64) { + m.group_id = &i + m.addgroup_id = nil +} + +// GroupID returns the value of the "group_id" field in the mutation. +func (m *SubscriptionPlanMutation) GroupID() (r int64, exists bool) { + v := m.group_id + if v == nil { + return + } + return *v, true +} + +// OldGroupID returns the old "group_id" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldGroupID(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldGroupID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldGroupID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldGroupID: %w", err) + } + return oldValue.GroupID, nil +} + +// AddGroupID adds i to the "group_id" field. +func (m *SubscriptionPlanMutation) AddGroupID(i int64) { + if m.addgroup_id != nil { + *m.addgroup_id += i + } else { + m.addgroup_id = &i + } +} + +// AddedGroupID returns the value that was added to the "group_id" field in this mutation. +func (m *SubscriptionPlanMutation) AddedGroupID() (r int64, exists bool) { + v := m.addgroup_id + if v == nil { + return + } + return *v, true +} + +// ResetGroupID resets all changes to the "group_id" field. +func (m *SubscriptionPlanMutation) ResetGroupID() { + m.group_id = nil + m.addgroup_id = nil +} + +// SetName sets the "name" field. +func (m *SubscriptionPlanMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *SubscriptionPlanMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *SubscriptionPlanMutation) ResetName() { + m.name = nil +} + +// SetDescription sets the "description" field. +func (m *SubscriptionPlanMutation) SetDescription(s string) { + m.description = &s +} + +// Description returns the value of the "description" field in the mutation. +func (m *SubscriptionPlanMutation) Description() (r string, exists bool) { + v := m.description + if v == nil { + return + } + return *v, true +} + +// OldDescription returns the old "description" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldDescription(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDescription is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDescription requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDescription: %w", err) + } + return oldValue.Description, nil +} + +// ResetDescription resets all changes to the "description" field. +func (m *SubscriptionPlanMutation) ResetDescription() { + m.description = nil +} + +// SetPrice sets the "price" field. +func (m *SubscriptionPlanMutation) SetPrice(f float64) { + m.price = &f + m.addprice = nil +} + +// Price returns the value of the "price" field in the mutation. +func (m *SubscriptionPlanMutation) Price() (r float64, exists bool) { + v := m.price + if v == nil { + return + } + return *v, true +} + +// OldPrice returns the old "price" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldPrice(ctx context.Context) (v float64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPrice is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPrice requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPrice: %w", err) + } + return oldValue.Price, nil +} + +// AddPrice adds f to the "price" field. +func (m *SubscriptionPlanMutation) AddPrice(f float64) { + if m.addprice != nil { + *m.addprice += f + } else { + m.addprice = &f + } +} + +// AddedPrice returns the value that was added to the "price" field in this mutation. +func (m *SubscriptionPlanMutation) AddedPrice() (r float64, exists bool) { + v := m.addprice + if v == nil { + return + } + return *v, true +} + +// ResetPrice resets all changes to the "price" field. +func (m *SubscriptionPlanMutation) ResetPrice() { + m.price = nil + m.addprice = nil +} + +// SetOriginalPrice sets the "original_price" field. +func (m *SubscriptionPlanMutation) SetOriginalPrice(f float64) { + m.original_price = &f + m.addoriginal_price = nil +} + +// OriginalPrice returns the value of the "original_price" field in the mutation. +func (m *SubscriptionPlanMutation) OriginalPrice() (r float64, exists bool) { + v := m.original_price + if v == nil { + return + } + return *v, true +} + +// OldOriginalPrice returns the old "original_price" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldOriginalPrice(ctx context.Context) (v *float64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldOriginalPrice is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldOriginalPrice requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOriginalPrice: %w", err) + } + return oldValue.OriginalPrice, nil +} + +// AddOriginalPrice adds f to the "original_price" field. +func (m *SubscriptionPlanMutation) AddOriginalPrice(f float64) { + if m.addoriginal_price != nil { + *m.addoriginal_price += f + } else { + m.addoriginal_price = &f + } +} + +// AddedOriginalPrice returns the value that was added to the "original_price" field in this mutation. +func (m *SubscriptionPlanMutation) AddedOriginalPrice() (r float64, exists bool) { + v := m.addoriginal_price + if v == nil { + return + } + return *v, true +} + +// ClearOriginalPrice clears the value of the "original_price" field. +func (m *SubscriptionPlanMutation) ClearOriginalPrice() { + m.original_price = nil + m.addoriginal_price = nil + m.clearedFields[subscriptionplan.FieldOriginalPrice] = struct{}{} +} + +// OriginalPriceCleared returns if the "original_price" field was cleared in this mutation. +func (m *SubscriptionPlanMutation) OriginalPriceCleared() bool { + _, ok := m.clearedFields[subscriptionplan.FieldOriginalPrice] + return ok +} + +// ResetOriginalPrice resets all changes to the "original_price" field. +func (m *SubscriptionPlanMutation) ResetOriginalPrice() { + m.original_price = nil + m.addoriginal_price = nil + delete(m.clearedFields, subscriptionplan.FieldOriginalPrice) +} + +// SetValidityDays sets the "validity_days" field. +func (m *SubscriptionPlanMutation) SetValidityDays(i int) { + m.validity_days = &i + m.addvalidity_days = nil +} + +// ValidityDays returns the value of the "validity_days" field in the mutation. +func (m *SubscriptionPlanMutation) ValidityDays() (r int, exists bool) { + v := m.validity_days + if v == nil { + return + } + return *v, true +} + +// OldValidityDays returns the old "validity_days" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldValidityDays(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldValidityDays is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldValidityDays requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldValidityDays: %w", err) + } + return oldValue.ValidityDays, nil +} + +// AddValidityDays adds i to the "validity_days" field. +func (m *SubscriptionPlanMutation) AddValidityDays(i int) { + if m.addvalidity_days != nil { + *m.addvalidity_days += i + } else { + m.addvalidity_days = &i + } +} + +// AddedValidityDays returns the value that was added to the "validity_days" field in this mutation. +func (m *SubscriptionPlanMutation) AddedValidityDays() (r int, exists bool) { + v := m.addvalidity_days + if v == nil { + return + } + return *v, true +} + +// ResetValidityDays resets all changes to the "validity_days" field. +func (m *SubscriptionPlanMutation) ResetValidityDays() { + m.validity_days = nil + m.addvalidity_days = nil +} + +// SetValidityUnit sets the "validity_unit" field. +func (m *SubscriptionPlanMutation) SetValidityUnit(s string) { + m.validity_unit = &s +} + +// ValidityUnit returns the value of the "validity_unit" field in the mutation. +func (m *SubscriptionPlanMutation) ValidityUnit() (r string, exists bool) { + v := m.validity_unit + if v == nil { + return + } + return *v, true +} + +// OldValidityUnit returns the old "validity_unit" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldValidityUnit(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldValidityUnit is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldValidityUnit requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldValidityUnit: %w", err) + } + return oldValue.ValidityUnit, nil +} + +// ResetValidityUnit resets all changes to the "validity_unit" field. +func (m *SubscriptionPlanMutation) ResetValidityUnit() { + m.validity_unit = nil +} + +// SetFeatures sets the "features" field. +func (m *SubscriptionPlanMutation) SetFeatures(s string) { + m.features = &s +} + +// Features returns the value of the "features" field in the mutation. +func (m *SubscriptionPlanMutation) Features() (r string, exists bool) { + v := m.features + if v == nil { + return + } + return *v, true +} + +// OldFeatures returns the old "features" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldFeatures(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldFeatures is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldFeatures requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFeatures: %w", err) + } + return oldValue.Features, nil +} + +// ResetFeatures resets all changes to the "features" field. +func (m *SubscriptionPlanMutation) ResetFeatures() { + m.features = nil +} + +// SetProductName sets the "product_name" field. +func (m *SubscriptionPlanMutation) SetProductName(s string) { + m.product_name = &s +} + +// ProductName returns the value of the "product_name" field in the mutation. +func (m *SubscriptionPlanMutation) ProductName() (r string, exists bool) { + v := m.product_name + if v == nil { + return + } + return *v, true +} + +// OldProductName returns the old "product_name" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldProductName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProductName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProductName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProductName: %w", err) + } + return oldValue.ProductName, nil +} + +// ResetProductName resets all changes to the "product_name" field. +func (m *SubscriptionPlanMutation) ResetProductName() { + m.product_name = nil +} + +// SetForSale sets the "for_sale" field. +func (m *SubscriptionPlanMutation) SetForSale(b bool) { + m.for_sale = &b +} + +// ForSale returns the value of the "for_sale" field in the mutation. +func (m *SubscriptionPlanMutation) ForSale() (r bool, exists bool) { + v := m.for_sale + if v == nil { + return + } + return *v, true +} + +// OldForSale returns the old "for_sale" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldForSale(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldForSale is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldForSale requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldForSale: %w", err) + } + return oldValue.ForSale, nil +} + +// ResetForSale resets all changes to the "for_sale" field. +func (m *SubscriptionPlanMutation) ResetForSale() { + m.for_sale = nil +} + +// SetSortOrder sets the "sort_order" field. +func (m *SubscriptionPlanMutation) SetSortOrder(i int) { + m.sort_order = &i + m.addsort_order = nil +} + +// SortOrder returns the value of the "sort_order" field in the mutation. +func (m *SubscriptionPlanMutation) SortOrder() (r int, exists bool) { + v := m.sort_order + if v == nil { + return + } + return *v, true +} + +// OldSortOrder returns the old "sort_order" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldSortOrder(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSortOrder is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSortOrder requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSortOrder: %w", err) + } + return oldValue.SortOrder, nil +} + +// AddSortOrder adds i to the "sort_order" field. +func (m *SubscriptionPlanMutation) AddSortOrder(i int) { + if m.addsort_order != nil { + *m.addsort_order += i + } else { + m.addsort_order = &i + } +} + +// AddedSortOrder returns the value that was added to the "sort_order" field in this mutation. +func (m *SubscriptionPlanMutation) AddedSortOrder() (r int, exists bool) { + v := m.addsort_order + if v == nil { + return + } + return *v, true +} + +// ResetSortOrder resets all changes to the "sort_order" field. +func (m *SubscriptionPlanMutation) ResetSortOrder() { + m.sort_order = nil + m.addsort_order = nil +} + +// SetCreatedAt sets the "created_at" field. +func (m *SubscriptionPlanMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *SubscriptionPlanMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *SubscriptionPlanMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *SubscriptionPlanMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *SubscriptionPlanMutation) UpdatedAt() (r time.Time, exists bool) { + v := m.updated_at + if v == nil { + return + } + return *v, true +} + +// OldUpdatedAt returns the old "updated_at" field's value of the SubscriptionPlan entity. +// If the SubscriptionPlan object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SubscriptionPlanMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err) + } + return oldValue.UpdatedAt, nil +} + +// ResetUpdatedAt resets all changes to the "updated_at" field. +func (m *SubscriptionPlanMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// Where appends a list predicates to the SubscriptionPlanMutation builder. +func (m *SubscriptionPlanMutation) Where(ps ...predicate.SubscriptionPlan) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the SubscriptionPlanMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *SubscriptionPlanMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.SubscriptionPlan, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *SubscriptionPlanMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *SubscriptionPlanMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (SubscriptionPlan). +func (m *SubscriptionPlanMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *SubscriptionPlanMutation) Fields() []string { + fields := make([]string, 0, 13) + if m.group_id != nil { + fields = append(fields, subscriptionplan.FieldGroupID) + } + if m.name != nil { + fields = append(fields, subscriptionplan.FieldName) + } + if m.description != nil { + fields = append(fields, subscriptionplan.FieldDescription) + } + if m.price != nil { + fields = append(fields, subscriptionplan.FieldPrice) + } + if m.original_price != nil { + fields = append(fields, subscriptionplan.FieldOriginalPrice) + } + if m.validity_days != nil { + fields = append(fields, subscriptionplan.FieldValidityDays) + } + if m.validity_unit != nil { + fields = append(fields, subscriptionplan.FieldValidityUnit) + } + if m.features != nil { + fields = append(fields, subscriptionplan.FieldFeatures) + } + if m.product_name != nil { + fields = append(fields, subscriptionplan.FieldProductName) + } + if m.for_sale != nil { + fields = append(fields, subscriptionplan.FieldForSale) + } + if m.sort_order != nil { + fields = append(fields, subscriptionplan.FieldSortOrder) + } + if m.created_at != nil { + fields = append(fields, subscriptionplan.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, subscriptionplan.FieldUpdatedAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *SubscriptionPlanMutation) Field(name string) (ent.Value, bool) { + switch name { + case subscriptionplan.FieldGroupID: + return m.GroupID() + case subscriptionplan.FieldName: + return m.Name() + case subscriptionplan.FieldDescription: + return m.Description() + case subscriptionplan.FieldPrice: + return m.Price() + case subscriptionplan.FieldOriginalPrice: + return m.OriginalPrice() + case subscriptionplan.FieldValidityDays: + return m.ValidityDays() + case subscriptionplan.FieldValidityUnit: + return m.ValidityUnit() + case subscriptionplan.FieldFeatures: + return m.Features() + case subscriptionplan.FieldProductName: + return m.ProductName() + case subscriptionplan.FieldForSale: + return m.ForSale() + case subscriptionplan.FieldSortOrder: + return m.SortOrder() + case subscriptionplan.FieldCreatedAt: + return m.CreatedAt() + case subscriptionplan.FieldUpdatedAt: + return m.UpdatedAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *SubscriptionPlanMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case subscriptionplan.FieldGroupID: + return m.OldGroupID(ctx) + case subscriptionplan.FieldName: + return m.OldName(ctx) + case subscriptionplan.FieldDescription: + return m.OldDescription(ctx) + case subscriptionplan.FieldPrice: + return m.OldPrice(ctx) + case subscriptionplan.FieldOriginalPrice: + return m.OldOriginalPrice(ctx) + case subscriptionplan.FieldValidityDays: + return m.OldValidityDays(ctx) + case subscriptionplan.FieldValidityUnit: + return m.OldValidityUnit(ctx) + case subscriptionplan.FieldFeatures: + return m.OldFeatures(ctx) + case subscriptionplan.FieldProductName: + return m.OldProductName(ctx) + case subscriptionplan.FieldForSale: + return m.OldForSale(ctx) + case subscriptionplan.FieldSortOrder: + return m.OldSortOrder(ctx) + case subscriptionplan.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case subscriptionplan.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + } + return nil, fmt.Errorf("unknown SubscriptionPlan field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *SubscriptionPlanMutation) SetField(name string, value ent.Value) error { + switch name { + case subscriptionplan.FieldGroupID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetGroupID(v) + return nil + case subscriptionplan.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case subscriptionplan.FieldDescription: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDescription(v) + return nil + case subscriptionplan.FieldPrice: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPrice(v) + return nil + case subscriptionplan.FieldOriginalPrice: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOriginalPrice(v) + return nil + case subscriptionplan.FieldValidityDays: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetValidityDays(v) + return nil + case subscriptionplan.FieldValidityUnit: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetValidityUnit(v) + return nil + case subscriptionplan.FieldFeatures: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFeatures(v) + return nil + case subscriptionplan.FieldProductName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProductName(v) + return nil + case subscriptionplan.FieldForSale: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetForSale(v) + return nil + case subscriptionplan.FieldSortOrder: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSortOrder(v) + return nil + case subscriptionplan.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case subscriptionplan.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + } + return fmt.Errorf("unknown SubscriptionPlan field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *SubscriptionPlanMutation) AddedFields() []string { + var fields []string + if m.addgroup_id != nil { + fields = append(fields, subscriptionplan.FieldGroupID) + } + if m.addprice != nil { + fields = append(fields, subscriptionplan.FieldPrice) + } + if m.addoriginal_price != nil { + fields = append(fields, subscriptionplan.FieldOriginalPrice) + } + if m.addvalidity_days != nil { + fields = append(fields, subscriptionplan.FieldValidityDays) + } + if m.addsort_order != nil { + fields = append(fields, subscriptionplan.FieldSortOrder) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *SubscriptionPlanMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case subscriptionplan.FieldGroupID: + return m.AddedGroupID() + case subscriptionplan.FieldPrice: + return m.AddedPrice() + case subscriptionplan.FieldOriginalPrice: + return m.AddedOriginalPrice() + case subscriptionplan.FieldValidityDays: + return m.AddedValidityDays() + case subscriptionplan.FieldSortOrder: + return m.AddedSortOrder() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *SubscriptionPlanMutation) AddField(name string, value ent.Value) error { + switch name { + case subscriptionplan.FieldGroupID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddGroupID(v) + return nil + case subscriptionplan.FieldPrice: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddPrice(v) + return nil + case subscriptionplan.FieldOriginalPrice: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddOriginalPrice(v) + return nil + case subscriptionplan.FieldValidityDays: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddValidityDays(v) + return nil + case subscriptionplan.FieldSortOrder: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddSortOrder(v) + return nil + } + return fmt.Errorf("unknown SubscriptionPlan numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *SubscriptionPlanMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(subscriptionplan.FieldOriginalPrice) { + fields = append(fields, subscriptionplan.FieldOriginalPrice) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *SubscriptionPlanMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *SubscriptionPlanMutation) ClearField(name string) error { + switch name { + case subscriptionplan.FieldOriginalPrice: + m.ClearOriginalPrice() + return nil + } + return fmt.Errorf("unknown SubscriptionPlan nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *SubscriptionPlanMutation) ResetField(name string) error { + switch name { + case subscriptionplan.FieldGroupID: + m.ResetGroupID() + return nil + case subscriptionplan.FieldName: + m.ResetName() + return nil + case subscriptionplan.FieldDescription: + m.ResetDescription() + return nil + case subscriptionplan.FieldPrice: + m.ResetPrice() + return nil + case subscriptionplan.FieldOriginalPrice: + m.ResetOriginalPrice() + return nil + case subscriptionplan.FieldValidityDays: + m.ResetValidityDays() + return nil + case subscriptionplan.FieldValidityUnit: + m.ResetValidityUnit() + return nil + case subscriptionplan.FieldFeatures: + m.ResetFeatures() + return nil + case subscriptionplan.FieldProductName: + m.ResetProductName() + return nil + case subscriptionplan.FieldForSale: + m.ResetForSale() + return nil + case subscriptionplan.FieldSortOrder: + m.ResetSortOrder() + return nil + case subscriptionplan.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case subscriptionplan.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + } + return fmt.Errorf("unknown SubscriptionPlan field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *SubscriptionPlanMutation) AddedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *SubscriptionPlanMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *SubscriptionPlanMutation) RemovedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *SubscriptionPlanMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *SubscriptionPlanMutation) ClearedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *SubscriptionPlanMutation) EdgeCleared(name string) bool { + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *SubscriptionPlanMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown SubscriptionPlan unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *SubscriptionPlanMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown SubscriptionPlan edge %s", name) +} + // TLSFingerprintProfileMutation represents an operation that mutates the TLSFingerprintProfile nodes in the graph. type TLSFingerprintProfileMutation struct { config @@ -22715,6 +28238,9 @@ type UserMutation struct { promo_code_usages map[int64]struct{} removedpromo_code_usages map[int64]struct{} clearedpromo_code_usages bool + payment_orders map[int64]struct{} + removedpayment_orders map[int64]struct{} + clearedpayment_orders bool done bool oldValue func(context.Context) (*User, error) predicates []predicate.User @@ -23887,6 +29413,60 @@ func (m *UserMutation) ResetPromoCodeUsages() { m.removedpromo_code_usages = nil } +// AddPaymentOrderIDs adds the "payment_orders" edge to the PaymentOrder entity by ids. +func (m *UserMutation) AddPaymentOrderIDs(ids ...int64) { + if m.payment_orders == nil { + m.payment_orders = make(map[int64]struct{}) + } + for i := range ids { + m.payment_orders[ids[i]] = struct{}{} + } +} + +// ClearPaymentOrders clears the "payment_orders" edge to the PaymentOrder entity. +func (m *UserMutation) ClearPaymentOrders() { + m.clearedpayment_orders = true +} + +// PaymentOrdersCleared reports if the "payment_orders" edge to the PaymentOrder entity was cleared. +func (m *UserMutation) PaymentOrdersCleared() bool { + return m.clearedpayment_orders +} + +// RemovePaymentOrderIDs removes the "payment_orders" edge to the PaymentOrder entity by IDs. +func (m *UserMutation) RemovePaymentOrderIDs(ids ...int64) { + if m.removedpayment_orders == nil { + m.removedpayment_orders = make(map[int64]struct{}) + } + for i := range ids { + delete(m.payment_orders, ids[i]) + m.removedpayment_orders[ids[i]] = struct{}{} + } +} + +// RemovedPaymentOrders returns the removed IDs of the "payment_orders" edge to the PaymentOrder entity. +func (m *UserMutation) RemovedPaymentOrdersIDs() (ids []int64) { + for id := range m.removedpayment_orders { + ids = append(ids, id) + } + return +} + +// PaymentOrdersIDs returns the "payment_orders" edge IDs in the mutation. +func (m *UserMutation) PaymentOrdersIDs() (ids []int64) { + for id := range m.payment_orders { + ids = append(ids, id) + } + return +} + +// ResetPaymentOrders resets all changes to the "payment_orders" edge. +func (m *UserMutation) ResetPaymentOrders() { + m.payment_orders = nil + m.clearedpayment_orders = false + m.removedpayment_orders = nil +} + // Where appends a list predicates to the UserMutation builder. func (m *UserMutation) Where(ps ...predicate.User) { m.predicates = append(m.predicates, ps...) @@ -24289,7 +29869,7 @@ func (m *UserMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *UserMutation) AddedEdges() []string { - edges := make([]string, 0, 9) + edges := make([]string, 0, 10) if m.api_keys != nil { edges = append(edges, user.EdgeAPIKeys) } @@ -24317,6 +29897,9 @@ func (m *UserMutation) AddedEdges() []string { if m.promo_code_usages != nil { edges = append(edges, user.EdgePromoCodeUsages) } + if m.payment_orders != nil { + edges = append(edges, user.EdgePaymentOrders) + } return edges } @@ -24378,13 +29961,19 @@ func (m *UserMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case user.EdgePaymentOrders: + ids := make([]ent.Value, 0, len(m.payment_orders)) + for id := range m.payment_orders { + ids = append(ids, id) + } + return ids } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *UserMutation) RemovedEdges() []string { - edges := make([]string, 0, 9) + edges := make([]string, 0, 10) if m.removedapi_keys != nil { edges = append(edges, user.EdgeAPIKeys) } @@ -24412,6 +30001,9 @@ func (m *UserMutation) RemovedEdges() []string { if m.removedpromo_code_usages != nil { edges = append(edges, user.EdgePromoCodeUsages) } + if m.removedpayment_orders != nil { + edges = append(edges, user.EdgePaymentOrders) + } return edges } @@ -24473,13 +30065,19 @@ func (m *UserMutation) RemovedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case user.EdgePaymentOrders: + ids := make([]ent.Value, 0, len(m.removedpayment_orders)) + for id := range m.removedpayment_orders { + ids = append(ids, id) + } + return ids } return nil } // ClearedEdges returns all edge names that were cleared in this mutation. func (m *UserMutation) ClearedEdges() []string { - edges := make([]string, 0, 9) + edges := make([]string, 0, 10) if m.clearedapi_keys { edges = append(edges, user.EdgeAPIKeys) } @@ -24507,6 +30105,9 @@ func (m *UserMutation) ClearedEdges() []string { if m.clearedpromo_code_usages { edges = append(edges, user.EdgePromoCodeUsages) } + if m.clearedpayment_orders { + edges = append(edges, user.EdgePaymentOrders) + } return edges } @@ -24532,6 +30133,8 @@ func (m *UserMutation) EdgeCleared(name string) bool { return m.clearedattribute_values case user.EdgePromoCodeUsages: return m.clearedpromo_code_usages + case user.EdgePaymentOrders: + return m.clearedpayment_orders } return false } @@ -24575,6 +30178,9 @@ func (m *UserMutation) ResetEdge(name string) error { case user.EdgePromoCodeUsages: m.ResetPromoCodeUsages() return nil + case user.EdgePaymentOrders: + m.ResetPaymentOrders() + return nil } return fmt.Errorf("unknown User edge %s", name) } diff --git a/backend/ent/paymentauditlog.go b/backend/ent/paymentauditlog.go new file mode 100644 index 00000000..ffcdcfcd --- /dev/null +++ b/backend/ent/paymentauditlog.go @@ -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 diff --git a/backend/ent/paymentauditlog/paymentauditlog.go b/backend/ent/paymentauditlog/paymentauditlog.go new file mode 100644 index 00000000..9d480eef --- /dev/null +++ b/backend/ent/paymentauditlog/paymentauditlog.go @@ -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() +} diff --git a/backend/ent/paymentauditlog/where.go b/backend/ent/paymentauditlog/where.go new file mode 100644 index 00000000..2fd80a42 --- /dev/null +++ b/backend/ent/paymentauditlog/where.go @@ -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)) +} diff --git a/backend/ent/paymentauditlog_create.go b/backend/ent/paymentauditlog_create.go new file mode 100644 index 00000000..1906aba1 --- /dev/null +++ b/backend/ent/paymentauditlog_create.go @@ -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) + } +} diff --git a/backend/ent/paymentauditlog_delete.go b/backend/ent/paymentauditlog_delete.go new file mode 100644 index 00000000..ca22d8db --- /dev/null +++ b/backend/ent/paymentauditlog_delete.go @@ -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) + } +} diff --git a/backend/ent/paymentauditlog_query.go b/backend/ent/paymentauditlog_query.go new file mode 100644 index 00000000..7a4e9115 --- /dev/null +++ b/backend/ent/paymentauditlog_query.go @@ -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) +} diff --git a/backend/ent/paymentauditlog_update.go b/backend/ent/paymentauditlog_update.go new file mode 100644 index 00000000..52b4afe7 --- /dev/null +++ b/backend/ent/paymentauditlog_update.go @@ -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 +} diff --git a/backend/ent/paymentorder.go b/backend/ent/paymentorder.go new file mode 100644 index 00000000..6ea3e709 --- /dev/null +++ b/backend/ent/paymentorder.go @@ -0,0 +1,589 @@ +// 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"` + // OutTradeNo holds the value of the "out_trade_no" field. + OutTradeNo string `json:"out_trade_no,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.FieldOutTradeNo, 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.FieldOutTradeNo: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field out_trade_no", values[i]) + } else if value.Valid { + _m.OutTradeNo = 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("out_trade_no=") + builder.WriteString(_m.OutTradeNo) + 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 diff --git a/backend/ent/paymentorder/paymentorder.go b/backend/ent/paymentorder/paymentorder.go new file mode 100644 index 00000000..4467b2b6 --- /dev/null +++ b/backend/ent/paymentorder/paymentorder.go @@ -0,0 +1,406 @@ +// 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" + // FieldOutTradeNo holds the string denoting the out_trade_no field in the database. + FieldOutTradeNo = "out_trade_no" + // 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, + FieldOutTradeNo, + 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 + // DefaultOutTradeNo holds the default value on creation for the "out_trade_no" field. + DefaultOutTradeNo string + // OutTradeNoValidator is a validator for the "out_trade_no" field. It is called by the builders before save. + OutTradeNoValidator 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() +} + +// ByOutTradeNo orders the results by the out_trade_no field. +func ByOutTradeNo(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldOutTradeNo, 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), + ) +} diff --git a/backend/ent/paymentorder/where.go b/backend/ent/paymentorder/where.go new file mode 100644 index 00000000..78520fac --- /dev/null +++ b/backend/ent/paymentorder/where.go @@ -0,0 +1,2389 @@ +// Code generated by ent, DO NOT EDIT. + +package paymentorder + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldID, id)) +} + +// UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ. +func UserID(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUserID, v)) +} + +// UserEmail applies equality check predicate on the "user_email" field. It's identical to UserEmailEQ. +func UserEmail(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUserEmail, v)) +} + +// UserName applies equality check predicate on the "user_name" field. It's identical to UserNameEQ. +func UserName(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUserName, v)) +} + +// UserNotes applies equality check predicate on the "user_notes" field. It's identical to UserNotesEQ. +func UserNotes(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUserNotes, v)) +} + +// Amount applies equality check predicate on the "amount" field. It's identical to AmountEQ. +func Amount(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldAmount, v)) +} + +// PayAmount applies equality check predicate on the "pay_amount" field. It's identical to PayAmountEQ. +func PayAmount(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPayAmount, v)) +} + +// FeeRate applies equality check predicate on the "fee_rate" field. It's identical to FeeRateEQ. +func FeeRate(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldFeeRate, v)) +} + +// RechargeCode applies equality check predicate on the "recharge_code" field. It's identical to RechargeCodeEQ. +func RechargeCode(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRechargeCode, v)) +} + +// OutTradeNo applies equality check predicate on the "out_trade_no" field. It's identical to OutTradeNoEQ. +func OutTradeNo(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldOutTradeNo, v)) +} + +// PaymentType applies equality check predicate on the "payment_type" field. It's identical to PaymentTypeEQ. +func PaymentType(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPaymentType, v)) +} + +// PaymentTradeNo applies equality check predicate on the "payment_trade_no" field. It's identical to PaymentTradeNoEQ. +func PaymentTradeNo(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPaymentTradeNo, v)) +} + +// PayURL applies equality check predicate on the "pay_url" field. It's identical to PayURLEQ. +func PayURL(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPayURL, v)) +} + +// QrCode applies equality check predicate on the "qr_code" field. It's identical to QrCodeEQ. +func QrCode(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldQrCode, v)) +} + +// QrCodeImg applies equality check predicate on the "qr_code_img" field. It's identical to QrCodeImgEQ. +func QrCodeImg(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldQrCodeImg, v)) +} + +// OrderType applies equality check predicate on the "order_type" field. It's identical to OrderTypeEQ. +func OrderType(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldOrderType, v)) +} + +// PlanID applies equality check predicate on the "plan_id" field. It's identical to PlanIDEQ. +func PlanID(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPlanID, v)) +} + +// SubscriptionGroupID applies equality check predicate on the "subscription_group_id" field. It's identical to SubscriptionGroupIDEQ. +func SubscriptionGroupID(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldSubscriptionGroupID, v)) +} + +// SubscriptionDays applies equality check predicate on the "subscription_days" field. It's identical to SubscriptionDaysEQ. +func SubscriptionDays(v int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldSubscriptionDays, v)) +} + +// ProviderInstanceID applies equality check predicate on the "provider_instance_id" field. It's identical to ProviderInstanceIDEQ. +func ProviderInstanceID(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldProviderInstanceID, v)) +} + +// Status applies equality check predicate on the "status" field. It's identical to StatusEQ. +func Status(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldStatus, v)) +} + +// RefundAmount applies equality check predicate on the "refund_amount" field. It's identical to RefundAmountEQ. +func RefundAmount(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundAmount, v)) +} + +// RefundReason applies equality check predicate on the "refund_reason" field. It's identical to RefundReasonEQ. +func RefundReason(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundReason, v)) +} + +// RefundAt applies equality check predicate on the "refund_at" field. It's identical to RefundAtEQ. +func RefundAt(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundAt, v)) +} + +// ForceRefund applies equality check predicate on the "force_refund" field. It's identical to ForceRefundEQ. +func ForceRefund(v bool) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldForceRefund, v)) +} + +// RefundRequestedAt applies equality check predicate on the "refund_requested_at" field. It's identical to RefundRequestedAtEQ. +func RefundRequestedAt(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundRequestedAt, v)) +} + +// RefundRequestReason applies equality check predicate on the "refund_request_reason" field. It's identical to RefundRequestReasonEQ. +func RefundRequestReason(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundRequestReason, v)) +} + +// RefundRequestedBy applies equality check predicate on the "refund_requested_by" field. It's identical to RefundRequestedByEQ. +func RefundRequestedBy(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundRequestedBy, v)) +} + +// ExpiresAt applies equality check predicate on the "expires_at" field. It's identical to ExpiresAtEQ. +func ExpiresAt(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldExpiresAt, v)) +} + +// PaidAt applies equality check predicate on the "paid_at" field. It's identical to PaidAtEQ. +func PaidAt(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPaidAt, v)) +} + +// CompletedAt applies equality check predicate on the "completed_at" field. It's identical to CompletedAtEQ. +func CompletedAt(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldCompletedAt, v)) +} + +// FailedAt applies equality check predicate on the "failed_at" field. It's identical to FailedAtEQ. +func FailedAt(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldFailedAt, v)) +} + +// FailedReason applies equality check predicate on the "failed_reason" field. It's identical to FailedReasonEQ. +func FailedReason(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldFailedReason, v)) +} + +// ClientIP applies equality check predicate on the "client_ip" field. It's identical to ClientIPEQ. +func ClientIP(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldClientIP, v)) +} + +// SrcHost applies equality check predicate on the "src_host" field. It's identical to SrcHostEQ. +func SrcHost(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldSrcHost, v)) +} + +// SrcURL applies equality check predicate on the "src_url" field. It's identical to SrcURLEQ. +func SrcURL(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldSrcURL, v)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(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.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UserIDEQ applies the EQ predicate on the "user_id" field. +func UserIDEQ(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUserID, v)) +} + +// UserIDNEQ applies the NEQ predicate on the "user_id" field. +func UserIDNEQ(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldUserID, v)) +} + +// UserIDIn applies the In predicate on the "user_id" field. +func UserIDIn(vs ...int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldUserID, vs...)) +} + +// UserIDNotIn applies the NotIn predicate on the "user_id" field. +func UserIDNotIn(vs ...int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldUserID, vs...)) +} + +// UserEmailEQ applies the EQ predicate on the "user_email" field. +func UserEmailEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUserEmail, v)) +} + +// UserEmailNEQ applies the NEQ predicate on the "user_email" field. +func UserEmailNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldUserEmail, v)) +} + +// UserEmailIn applies the In predicate on the "user_email" field. +func UserEmailIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldUserEmail, vs...)) +} + +// UserEmailNotIn applies the NotIn predicate on the "user_email" field. +func UserEmailNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldUserEmail, vs...)) +} + +// UserEmailGT applies the GT predicate on the "user_email" field. +func UserEmailGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldUserEmail, v)) +} + +// UserEmailGTE applies the GTE predicate on the "user_email" field. +func UserEmailGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldUserEmail, v)) +} + +// UserEmailLT applies the LT predicate on the "user_email" field. +func UserEmailLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldUserEmail, v)) +} + +// UserEmailLTE applies the LTE predicate on the "user_email" field. +func UserEmailLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldUserEmail, v)) +} + +// UserEmailContains applies the Contains predicate on the "user_email" field. +func UserEmailContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldUserEmail, v)) +} + +// UserEmailHasPrefix applies the HasPrefix predicate on the "user_email" field. +func UserEmailHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldUserEmail, v)) +} + +// UserEmailHasSuffix applies the HasSuffix predicate on the "user_email" field. +func UserEmailHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldUserEmail, v)) +} + +// UserEmailEqualFold applies the EqualFold predicate on the "user_email" field. +func UserEmailEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldUserEmail, v)) +} + +// UserEmailContainsFold applies the ContainsFold predicate on the "user_email" field. +func UserEmailContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldUserEmail, v)) +} + +// UserNameEQ applies the EQ predicate on the "user_name" field. +func UserNameEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUserName, v)) +} + +// UserNameNEQ applies the NEQ predicate on the "user_name" field. +func UserNameNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldUserName, v)) +} + +// UserNameIn applies the In predicate on the "user_name" field. +func UserNameIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldUserName, vs...)) +} + +// UserNameNotIn applies the NotIn predicate on the "user_name" field. +func UserNameNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldUserName, vs...)) +} + +// UserNameGT applies the GT predicate on the "user_name" field. +func UserNameGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldUserName, v)) +} + +// UserNameGTE applies the GTE predicate on the "user_name" field. +func UserNameGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldUserName, v)) +} + +// UserNameLT applies the LT predicate on the "user_name" field. +func UserNameLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldUserName, v)) +} + +// UserNameLTE applies the LTE predicate on the "user_name" field. +func UserNameLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldUserName, v)) +} + +// UserNameContains applies the Contains predicate on the "user_name" field. +func UserNameContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldUserName, v)) +} + +// UserNameHasPrefix applies the HasPrefix predicate on the "user_name" field. +func UserNameHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldUserName, v)) +} + +// UserNameHasSuffix applies the HasSuffix predicate on the "user_name" field. +func UserNameHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldUserName, v)) +} + +// UserNameEqualFold applies the EqualFold predicate on the "user_name" field. +func UserNameEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldUserName, v)) +} + +// UserNameContainsFold applies the ContainsFold predicate on the "user_name" field. +func UserNameContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldUserName, v)) +} + +// UserNotesEQ applies the EQ predicate on the "user_notes" field. +func UserNotesEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUserNotes, v)) +} + +// UserNotesNEQ applies the NEQ predicate on the "user_notes" field. +func UserNotesNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldUserNotes, v)) +} + +// UserNotesIn applies the In predicate on the "user_notes" field. +func UserNotesIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldUserNotes, vs...)) +} + +// UserNotesNotIn applies the NotIn predicate on the "user_notes" field. +func UserNotesNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldUserNotes, vs...)) +} + +// UserNotesGT applies the GT predicate on the "user_notes" field. +func UserNotesGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldUserNotes, v)) +} + +// UserNotesGTE applies the GTE predicate on the "user_notes" field. +func UserNotesGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldUserNotes, v)) +} + +// UserNotesLT applies the LT predicate on the "user_notes" field. +func UserNotesLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldUserNotes, v)) +} + +// UserNotesLTE applies the LTE predicate on the "user_notes" field. +func UserNotesLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldUserNotes, v)) +} + +// UserNotesContains applies the Contains predicate on the "user_notes" field. +func UserNotesContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldUserNotes, v)) +} + +// UserNotesHasPrefix applies the HasPrefix predicate on the "user_notes" field. +func UserNotesHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldUserNotes, v)) +} + +// UserNotesHasSuffix applies the HasSuffix predicate on the "user_notes" field. +func UserNotesHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldUserNotes, v)) +} + +// UserNotesIsNil applies the IsNil predicate on the "user_notes" field. +func UserNotesIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldUserNotes)) +} + +// UserNotesNotNil applies the NotNil predicate on the "user_notes" field. +func UserNotesNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldUserNotes)) +} + +// UserNotesEqualFold applies the EqualFold predicate on the "user_notes" field. +func UserNotesEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldUserNotes, v)) +} + +// UserNotesContainsFold applies the ContainsFold predicate on the "user_notes" field. +func UserNotesContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldUserNotes, v)) +} + +// AmountEQ applies the EQ predicate on the "amount" field. +func AmountEQ(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldAmount, v)) +} + +// AmountNEQ applies the NEQ predicate on the "amount" field. +func AmountNEQ(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldAmount, v)) +} + +// AmountIn applies the In predicate on the "amount" field. +func AmountIn(vs ...float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldAmount, vs...)) +} + +// AmountNotIn applies the NotIn predicate on the "amount" field. +func AmountNotIn(vs ...float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldAmount, vs...)) +} + +// AmountGT applies the GT predicate on the "amount" field. +func AmountGT(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldAmount, v)) +} + +// AmountGTE applies the GTE predicate on the "amount" field. +func AmountGTE(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldAmount, v)) +} + +// AmountLT applies the LT predicate on the "amount" field. +func AmountLT(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldAmount, v)) +} + +// AmountLTE applies the LTE predicate on the "amount" field. +func AmountLTE(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldAmount, v)) +} + +// PayAmountEQ applies the EQ predicate on the "pay_amount" field. +func PayAmountEQ(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPayAmount, v)) +} + +// PayAmountNEQ applies the NEQ predicate on the "pay_amount" field. +func PayAmountNEQ(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldPayAmount, v)) +} + +// PayAmountIn applies the In predicate on the "pay_amount" field. +func PayAmountIn(vs ...float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldPayAmount, vs...)) +} + +// PayAmountNotIn applies the NotIn predicate on the "pay_amount" field. +func PayAmountNotIn(vs ...float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldPayAmount, vs...)) +} + +// PayAmountGT applies the GT predicate on the "pay_amount" field. +func PayAmountGT(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldPayAmount, v)) +} + +// PayAmountGTE applies the GTE predicate on the "pay_amount" field. +func PayAmountGTE(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldPayAmount, v)) +} + +// PayAmountLT applies the LT predicate on the "pay_amount" field. +func PayAmountLT(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldPayAmount, v)) +} + +// PayAmountLTE applies the LTE predicate on the "pay_amount" field. +func PayAmountLTE(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldPayAmount, v)) +} + +// FeeRateEQ applies the EQ predicate on the "fee_rate" field. +func FeeRateEQ(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldFeeRate, v)) +} + +// FeeRateNEQ applies the NEQ predicate on the "fee_rate" field. +func FeeRateNEQ(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldFeeRate, v)) +} + +// FeeRateIn applies the In predicate on the "fee_rate" field. +func FeeRateIn(vs ...float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldFeeRate, vs...)) +} + +// FeeRateNotIn applies the NotIn predicate on the "fee_rate" field. +func FeeRateNotIn(vs ...float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldFeeRate, vs...)) +} + +// FeeRateGT applies the GT predicate on the "fee_rate" field. +func FeeRateGT(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldFeeRate, v)) +} + +// FeeRateGTE applies the GTE predicate on the "fee_rate" field. +func FeeRateGTE(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldFeeRate, v)) +} + +// FeeRateLT applies the LT predicate on the "fee_rate" field. +func FeeRateLT(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldFeeRate, v)) +} + +// FeeRateLTE applies the LTE predicate on the "fee_rate" field. +func FeeRateLTE(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldFeeRate, v)) +} + +// RechargeCodeEQ applies the EQ predicate on the "recharge_code" field. +func RechargeCodeEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRechargeCode, v)) +} + +// RechargeCodeNEQ applies the NEQ predicate on the "recharge_code" field. +func RechargeCodeNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldRechargeCode, v)) +} + +// RechargeCodeIn applies the In predicate on the "recharge_code" field. +func RechargeCodeIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldRechargeCode, vs...)) +} + +// RechargeCodeNotIn applies the NotIn predicate on the "recharge_code" field. +func RechargeCodeNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldRechargeCode, vs...)) +} + +// RechargeCodeGT applies the GT predicate on the "recharge_code" field. +func RechargeCodeGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldRechargeCode, v)) +} + +// RechargeCodeGTE applies the GTE predicate on the "recharge_code" field. +func RechargeCodeGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldRechargeCode, v)) +} + +// RechargeCodeLT applies the LT predicate on the "recharge_code" field. +func RechargeCodeLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldRechargeCode, v)) +} + +// RechargeCodeLTE applies the LTE predicate on the "recharge_code" field. +func RechargeCodeLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldRechargeCode, v)) +} + +// RechargeCodeContains applies the Contains predicate on the "recharge_code" field. +func RechargeCodeContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldRechargeCode, v)) +} + +// RechargeCodeHasPrefix applies the HasPrefix predicate on the "recharge_code" field. +func RechargeCodeHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldRechargeCode, v)) +} + +// RechargeCodeHasSuffix applies the HasSuffix predicate on the "recharge_code" field. +func RechargeCodeHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldRechargeCode, v)) +} + +// RechargeCodeEqualFold applies the EqualFold predicate on the "recharge_code" field. +func RechargeCodeEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldRechargeCode, v)) +} + +// RechargeCodeContainsFold applies the ContainsFold predicate on the "recharge_code" field. +func RechargeCodeContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldRechargeCode, v)) +} + +// OutTradeNoEQ applies the EQ predicate on the "out_trade_no" field. +func OutTradeNoEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldOutTradeNo, v)) +} + +// OutTradeNoNEQ applies the NEQ predicate on the "out_trade_no" field. +func OutTradeNoNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldOutTradeNo, v)) +} + +// OutTradeNoIn applies the In predicate on the "out_trade_no" field. +func OutTradeNoIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldOutTradeNo, vs...)) +} + +// OutTradeNoNotIn applies the NotIn predicate on the "out_trade_no" field. +func OutTradeNoNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldOutTradeNo, vs...)) +} + +// OutTradeNoGT applies the GT predicate on the "out_trade_no" field. +func OutTradeNoGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldOutTradeNo, v)) +} + +// OutTradeNoGTE applies the GTE predicate on the "out_trade_no" field. +func OutTradeNoGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldOutTradeNo, v)) +} + +// OutTradeNoLT applies the LT predicate on the "out_trade_no" field. +func OutTradeNoLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldOutTradeNo, v)) +} + +// OutTradeNoLTE applies the LTE predicate on the "out_trade_no" field. +func OutTradeNoLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldOutTradeNo, v)) +} + +// OutTradeNoContains applies the Contains predicate on the "out_trade_no" field. +func OutTradeNoContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldOutTradeNo, v)) +} + +// OutTradeNoHasPrefix applies the HasPrefix predicate on the "out_trade_no" field. +func OutTradeNoHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldOutTradeNo, v)) +} + +// OutTradeNoHasSuffix applies the HasSuffix predicate on the "out_trade_no" field. +func OutTradeNoHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldOutTradeNo, v)) +} + +// OutTradeNoEqualFold applies the EqualFold predicate on the "out_trade_no" field. +func OutTradeNoEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldOutTradeNo, v)) +} + +// OutTradeNoContainsFold applies the ContainsFold predicate on the "out_trade_no" field. +func OutTradeNoContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldOutTradeNo, v)) +} + +// PaymentTypeEQ applies the EQ predicate on the "payment_type" field. +func PaymentTypeEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPaymentType, v)) +} + +// PaymentTypeNEQ applies the NEQ predicate on the "payment_type" field. +func PaymentTypeNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldPaymentType, v)) +} + +// PaymentTypeIn applies the In predicate on the "payment_type" field. +func PaymentTypeIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldPaymentType, vs...)) +} + +// PaymentTypeNotIn applies the NotIn predicate on the "payment_type" field. +func PaymentTypeNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldPaymentType, vs...)) +} + +// PaymentTypeGT applies the GT predicate on the "payment_type" field. +func PaymentTypeGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldPaymentType, v)) +} + +// PaymentTypeGTE applies the GTE predicate on the "payment_type" field. +func PaymentTypeGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldPaymentType, v)) +} + +// PaymentTypeLT applies the LT predicate on the "payment_type" field. +func PaymentTypeLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldPaymentType, v)) +} + +// PaymentTypeLTE applies the LTE predicate on the "payment_type" field. +func PaymentTypeLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldPaymentType, v)) +} + +// PaymentTypeContains applies the Contains predicate on the "payment_type" field. +func PaymentTypeContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldPaymentType, v)) +} + +// PaymentTypeHasPrefix applies the HasPrefix predicate on the "payment_type" field. +func PaymentTypeHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldPaymentType, v)) +} + +// PaymentTypeHasSuffix applies the HasSuffix predicate on the "payment_type" field. +func PaymentTypeHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldPaymentType, v)) +} + +// PaymentTypeEqualFold applies the EqualFold predicate on the "payment_type" field. +func PaymentTypeEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldPaymentType, v)) +} + +// PaymentTypeContainsFold applies the ContainsFold predicate on the "payment_type" field. +func PaymentTypeContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldPaymentType, v)) +} + +// PaymentTradeNoEQ applies the EQ predicate on the "payment_trade_no" field. +func PaymentTradeNoEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoNEQ applies the NEQ predicate on the "payment_trade_no" field. +func PaymentTradeNoNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoIn applies the In predicate on the "payment_trade_no" field. +func PaymentTradeNoIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldPaymentTradeNo, vs...)) +} + +// PaymentTradeNoNotIn applies the NotIn predicate on the "payment_trade_no" field. +func PaymentTradeNoNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldPaymentTradeNo, vs...)) +} + +// PaymentTradeNoGT applies the GT predicate on the "payment_trade_no" field. +func PaymentTradeNoGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoGTE applies the GTE predicate on the "payment_trade_no" field. +func PaymentTradeNoGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoLT applies the LT predicate on the "payment_trade_no" field. +func PaymentTradeNoLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoLTE applies the LTE predicate on the "payment_trade_no" field. +func PaymentTradeNoLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoContains applies the Contains predicate on the "payment_trade_no" field. +func PaymentTradeNoContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoHasPrefix applies the HasPrefix predicate on the "payment_trade_no" field. +func PaymentTradeNoHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoHasSuffix applies the HasSuffix predicate on the "payment_trade_no" field. +func PaymentTradeNoHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoEqualFold applies the EqualFold predicate on the "payment_trade_no" field. +func PaymentTradeNoEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldPaymentTradeNo, v)) +} + +// PaymentTradeNoContainsFold applies the ContainsFold predicate on the "payment_trade_no" field. +func PaymentTradeNoContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldPaymentTradeNo, v)) +} + +// PayURLEQ applies the EQ predicate on the "pay_url" field. +func PayURLEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPayURL, v)) +} + +// PayURLNEQ applies the NEQ predicate on the "pay_url" field. +func PayURLNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldPayURL, v)) +} + +// PayURLIn applies the In predicate on the "pay_url" field. +func PayURLIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldPayURL, vs...)) +} + +// PayURLNotIn applies the NotIn predicate on the "pay_url" field. +func PayURLNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldPayURL, vs...)) +} + +// PayURLGT applies the GT predicate on the "pay_url" field. +func PayURLGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldPayURL, v)) +} + +// PayURLGTE applies the GTE predicate on the "pay_url" field. +func PayURLGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldPayURL, v)) +} + +// PayURLLT applies the LT predicate on the "pay_url" field. +func PayURLLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldPayURL, v)) +} + +// PayURLLTE applies the LTE predicate on the "pay_url" field. +func PayURLLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldPayURL, v)) +} + +// PayURLContains applies the Contains predicate on the "pay_url" field. +func PayURLContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldPayURL, v)) +} + +// PayURLHasPrefix applies the HasPrefix predicate on the "pay_url" field. +func PayURLHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldPayURL, v)) +} + +// PayURLHasSuffix applies the HasSuffix predicate on the "pay_url" field. +func PayURLHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldPayURL, v)) +} + +// PayURLIsNil applies the IsNil predicate on the "pay_url" field. +func PayURLIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldPayURL)) +} + +// PayURLNotNil applies the NotNil predicate on the "pay_url" field. +func PayURLNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldPayURL)) +} + +// PayURLEqualFold applies the EqualFold predicate on the "pay_url" field. +func PayURLEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldPayURL, v)) +} + +// PayURLContainsFold applies the ContainsFold predicate on the "pay_url" field. +func PayURLContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldPayURL, v)) +} + +// QrCodeEQ applies the EQ predicate on the "qr_code" field. +func QrCodeEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldQrCode, v)) +} + +// QrCodeNEQ applies the NEQ predicate on the "qr_code" field. +func QrCodeNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldQrCode, v)) +} + +// QrCodeIn applies the In predicate on the "qr_code" field. +func QrCodeIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldQrCode, vs...)) +} + +// QrCodeNotIn applies the NotIn predicate on the "qr_code" field. +func QrCodeNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldQrCode, vs...)) +} + +// QrCodeGT applies the GT predicate on the "qr_code" field. +func QrCodeGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldQrCode, v)) +} + +// QrCodeGTE applies the GTE predicate on the "qr_code" field. +func QrCodeGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldQrCode, v)) +} + +// QrCodeLT applies the LT predicate on the "qr_code" field. +func QrCodeLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldQrCode, v)) +} + +// QrCodeLTE applies the LTE predicate on the "qr_code" field. +func QrCodeLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldQrCode, v)) +} + +// QrCodeContains applies the Contains predicate on the "qr_code" field. +func QrCodeContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldQrCode, v)) +} + +// QrCodeHasPrefix applies the HasPrefix predicate on the "qr_code" field. +func QrCodeHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldQrCode, v)) +} + +// QrCodeHasSuffix applies the HasSuffix predicate on the "qr_code" field. +func QrCodeHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldQrCode, v)) +} + +// QrCodeIsNil applies the IsNil predicate on the "qr_code" field. +func QrCodeIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldQrCode)) +} + +// QrCodeNotNil applies the NotNil predicate on the "qr_code" field. +func QrCodeNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldQrCode)) +} + +// QrCodeEqualFold applies the EqualFold predicate on the "qr_code" field. +func QrCodeEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldQrCode, v)) +} + +// QrCodeContainsFold applies the ContainsFold predicate on the "qr_code" field. +func QrCodeContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldQrCode, v)) +} + +// QrCodeImgEQ applies the EQ predicate on the "qr_code_img" field. +func QrCodeImgEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldQrCodeImg, v)) +} + +// QrCodeImgNEQ applies the NEQ predicate on the "qr_code_img" field. +func QrCodeImgNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldQrCodeImg, v)) +} + +// QrCodeImgIn applies the In predicate on the "qr_code_img" field. +func QrCodeImgIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldQrCodeImg, vs...)) +} + +// QrCodeImgNotIn applies the NotIn predicate on the "qr_code_img" field. +func QrCodeImgNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldQrCodeImg, vs...)) +} + +// QrCodeImgGT applies the GT predicate on the "qr_code_img" field. +func QrCodeImgGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldQrCodeImg, v)) +} + +// QrCodeImgGTE applies the GTE predicate on the "qr_code_img" field. +func QrCodeImgGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldQrCodeImg, v)) +} + +// QrCodeImgLT applies the LT predicate on the "qr_code_img" field. +func QrCodeImgLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldQrCodeImg, v)) +} + +// QrCodeImgLTE applies the LTE predicate on the "qr_code_img" field. +func QrCodeImgLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldQrCodeImg, v)) +} + +// QrCodeImgContains applies the Contains predicate on the "qr_code_img" field. +func QrCodeImgContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldQrCodeImg, v)) +} + +// QrCodeImgHasPrefix applies the HasPrefix predicate on the "qr_code_img" field. +func QrCodeImgHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldQrCodeImg, v)) +} + +// QrCodeImgHasSuffix applies the HasSuffix predicate on the "qr_code_img" field. +func QrCodeImgHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldQrCodeImg, v)) +} + +// QrCodeImgIsNil applies the IsNil predicate on the "qr_code_img" field. +func QrCodeImgIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldQrCodeImg)) +} + +// QrCodeImgNotNil applies the NotNil predicate on the "qr_code_img" field. +func QrCodeImgNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldQrCodeImg)) +} + +// QrCodeImgEqualFold applies the EqualFold predicate on the "qr_code_img" field. +func QrCodeImgEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldQrCodeImg, v)) +} + +// QrCodeImgContainsFold applies the ContainsFold predicate on the "qr_code_img" field. +func QrCodeImgContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldQrCodeImg, v)) +} + +// OrderTypeEQ applies the EQ predicate on the "order_type" field. +func OrderTypeEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldOrderType, v)) +} + +// OrderTypeNEQ applies the NEQ predicate on the "order_type" field. +func OrderTypeNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldOrderType, v)) +} + +// OrderTypeIn applies the In predicate on the "order_type" field. +func OrderTypeIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldOrderType, vs...)) +} + +// OrderTypeNotIn applies the NotIn predicate on the "order_type" field. +func OrderTypeNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldOrderType, vs...)) +} + +// OrderTypeGT applies the GT predicate on the "order_type" field. +func OrderTypeGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldOrderType, v)) +} + +// OrderTypeGTE applies the GTE predicate on the "order_type" field. +func OrderTypeGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldOrderType, v)) +} + +// OrderTypeLT applies the LT predicate on the "order_type" field. +func OrderTypeLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldOrderType, v)) +} + +// OrderTypeLTE applies the LTE predicate on the "order_type" field. +func OrderTypeLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldOrderType, v)) +} + +// OrderTypeContains applies the Contains predicate on the "order_type" field. +func OrderTypeContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldOrderType, v)) +} + +// OrderTypeHasPrefix applies the HasPrefix predicate on the "order_type" field. +func OrderTypeHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldOrderType, v)) +} + +// OrderTypeHasSuffix applies the HasSuffix predicate on the "order_type" field. +func OrderTypeHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldOrderType, v)) +} + +// OrderTypeEqualFold applies the EqualFold predicate on the "order_type" field. +func OrderTypeEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldOrderType, v)) +} + +// OrderTypeContainsFold applies the ContainsFold predicate on the "order_type" field. +func OrderTypeContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldOrderType, v)) +} + +// PlanIDEQ applies the EQ predicate on the "plan_id" field. +func PlanIDEQ(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPlanID, v)) +} + +// PlanIDNEQ applies the NEQ predicate on the "plan_id" field. +func PlanIDNEQ(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldPlanID, v)) +} + +// PlanIDIn applies the In predicate on the "plan_id" field. +func PlanIDIn(vs ...int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldPlanID, vs...)) +} + +// PlanIDNotIn applies the NotIn predicate on the "plan_id" field. +func PlanIDNotIn(vs ...int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldPlanID, vs...)) +} + +// PlanIDGT applies the GT predicate on the "plan_id" field. +func PlanIDGT(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldPlanID, v)) +} + +// PlanIDGTE applies the GTE predicate on the "plan_id" field. +func PlanIDGTE(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldPlanID, v)) +} + +// PlanIDLT applies the LT predicate on the "plan_id" field. +func PlanIDLT(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldPlanID, v)) +} + +// PlanIDLTE applies the LTE predicate on the "plan_id" field. +func PlanIDLTE(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldPlanID, v)) +} + +// PlanIDIsNil applies the IsNil predicate on the "plan_id" field. +func PlanIDIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldPlanID)) +} + +// PlanIDNotNil applies the NotNil predicate on the "plan_id" field. +func PlanIDNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldPlanID)) +} + +// SubscriptionGroupIDEQ applies the EQ predicate on the "subscription_group_id" field. +func SubscriptionGroupIDEQ(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldSubscriptionGroupID, v)) +} + +// SubscriptionGroupIDNEQ applies the NEQ predicate on the "subscription_group_id" field. +func SubscriptionGroupIDNEQ(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldSubscriptionGroupID, v)) +} + +// SubscriptionGroupIDIn applies the In predicate on the "subscription_group_id" field. +func SubscriptionGroupIDIn(vs ...int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldSubscriptionGroupID, vs...)) +} + +// SubscriptionGroupIDNotIn applies the NotIn predicate on the "subscription_group_id" field. +func SubscriptionGroupIDNotIn(vs ...int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldSubscriptionGroupID, vs...)) +} + +// SubscriptionGroupIDGT applies the GT predicate on the "subscription_group_id" field. +func SubscriptionGroupIDGT(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldSubscriptionGroupID, v)) +} + +// SubscriptionGroupIDGTE applies the GTE predicate on the "subscription_group_id" field. +func SubscriptionGroupIDGTE(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldSubscriptionGroupID, v)) +} + +// SubscriptionGroupIDLT applies the LT predicate on the "subscription_group_id" field. +func SubscriptionGroupIDLT(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldSubscriptionGroupID, v)) +} + +// SubscriptionGroupIDLTE applies the LTE predicate on the "subscription_group_id" field. +func SubscriptionGroupIDLTE(v int64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldSubscriptionGroupID, v)) +} + +// SubscriptionGroupIDIsNil applies the IsNil predicate on the "subscription_group_id" field. +func SubscriptionGroupIDIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldSubscriptionGroupID)) +} + +// SubscriptionGroupIDNotNil applies the NotNil predicate on the "subscription_group_id" field. +func SubscriptionGroupIDNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldSubscriptionGroupID)) +} + +// SubscriptionDaysEQ applies the EQ predicate on the "subscription_days" field. +func SubscriptionDaysEQ(v int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldSubscriptionDays, v)) +} + +// SubscriptionDaysNEQ applies the NEQ predicate on the "subscription_days" field. +func SubscriptionDaysNEQ(v int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldSubscriptionDays, v)) +} + +// SubscriptionDaysIn applies the In predicate on the "subscription_days" field. +func SubscriptionDaysIn(vs ...int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldSubscriptionDays, vs...)) +} + +// SubscriptionDaysNotIn applies the NotIn predicate on the "subscription_days" field. +func SubscriptionDaysNotIn(vs ...int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldSubscriptionDays, vs...)) +} + +// SubscriptionDaysGT applies the GT predicate on the "subscription_days" field. +func SubscriptionDaysGT(v int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldSubscriptionDays, v)) +} + +// SubscriptionDaysGTE applies the GTE predicate on the "subscription_days" field. +func SubscriptionDaysGTE(v int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldSubscriptionDays, v)) +} + +// SubscriptionDaysLT applies the LT predicate on the "subscription_days" field. +func SubscriptionDaysLT(v int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldSubscriptionDays, v)) +} + +// SubscriptionDaysLTE applies the LTE predicate on the "subscription_days" field. +func SubscriptionDaysLTE(v int) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldSubscriptionDays, v)) +} + +// SubscriptionDaysIsNil applies the IsNil predicate on the "subscription_days" field. +func SubscriptionDaysIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldSubscriptionDays)) +} + +// SubscriptionDaysNotNil applies the NotNil predicate on the "subscription_days" field. +func SubscriptionDaysNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldSubscriptionDays)) +} + +// ProviderInstanceIDEQ applies the EQ predicate on the "provider_instance_id" field. +func ProviderInstanceIDEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDNEQ applies the NEQ predicate on the "provider_instance_id" field. +func ProviderInstanceIDNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDIn applies the In predicate on the "provider_instance_id" field. +func ProviderInstanceIDIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldProviderInstanceID, vs...)) +} + +// ProviderInstanceIDNotIn applies the NotIn predicate on the "provider_instance_id" field. +func ProviderInstanceIDNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldProviderInstanceID, vs...)) +} + +// ProviderInstanceIDGT applies the GT predicate on the "provider_instance_id" field. +func ProviderInstanceIDGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDGTE applies the GTE predicate on the "provider_instance_id" field. +func ProviderInstanceIDGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDLT applies the LT predicate on the "provider_instance_id" field. +func ProviderInstanceIDLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDLTE applies the LTE predicate on the "provider_instance_id" field. +func ProviderInstanceIDLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDContains applies the Contains predicate on the "provider_instance_id" field. +func ProviderInstanceIDContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDHasPrefix applies the HasPrefix predicate on the "provider_instance_id" field. +func ProviderInstanceIDHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDHasSuffix applies the HasSuffix predicate on the "provider_instance_id" field. +func ProviderInstanceIDHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDIsNil applies the IsNil predicate on the "provider_instance_id" field. +func ProviderInstanceIDIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldProviderInstanceID)) +} + +// ProviderInstanceIDNotNil applies the NotNil predicate on the "provider_instance_id" field. +func ProviderInstanceIDNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldProviderInstanceID)) +} + +// ProviderInstanceIDEqualFold applies the EqualFold predicate on the "provider_instance_id" field. +func ProviderInstanceIDEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldProviderInstanceID, v)) +} + +// ProviderInstanceIDContainsFold applies the ContainsFold predicate on the "provider_instance_id" field. +func ProviderInstanceIDContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldProviderInstanceID, v)) +} + +// StatusEQ applies the EQ predicate on the "status" field. +func StatusEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldStatus, v)) +} + +// StatusNEQ applies the NEQ predicate on the "status" field. +func StatusNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldStatus, v)) +} + +// StatusIn applies the In predicate on the "status" field. +func StatusIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldStatus, vs...)) +} + +// StatusNotIn applies the NotIn predicate on the "status" field. +func StatusNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldStatus, vs...)) +} + +// StatusGT applies the GT predicate on the "status" field. +func StatusGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldStatus, v)) +} + +// StatusGTE applies the GTE predicate on the "status" field. +func StatusGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldStatus, v)) +} + +// StatusLT applies the LT predicate on the "status" field. +func StatusLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldStatus, v)) +} + +// StatusLTE applies the LTE predicate on the "status" field. +func StatusLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldStatus, v)) +} + +// StatusContains applies the Contains predicate on the "status" field. +func StatusContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldStatus, v)) +} + +// StatusHasPrefix applies the HasPrefix predicate on the "status" field. +func StatusHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldStatus, v)) +} + +// StatusHasSuffix applies the HasSuffix predicate on the "status" field. +func StatusHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldStatus, v)) +} + +// StatusEqualFold applies the EqualFold predicate on the "status" field. +func StatusEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldStatus, v)) +} + +// StatusContainsFold applies the ContainsFold predicate on the "status" field. +func StatusContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldStatus, v)) +} + +// RefundAmountEQ applies the EQ predicate on the "refund_amount" field. +func RefundAmountEQ(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundAmount, v)) +} + +// RefundAmountNEQ applies the NEQ predicate on the "refund_amount" field. +func RefundAmountNEQ(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldRefundAmount, v)) +} + +// RefundAmountIn applies the In predicate on the "refund_amount" field. +func RefundAmountIn(vs ...float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldRefundAmount, vs...)) +} + +// RefundAmountNotIn applies the NotIn predicate on the "refund_amount" field. +func RefundAmountNotIn(vs ...float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldRefundAmount, vs...)) +} + +// RefundAmountGT applies the GT predicate on the "refund_amount" field. +func RefundAmountGT(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldRefundAmount, v)) +} + +// RefundAmountGTE applies the GTE predicate on the "refund_amount" field. +func RefundAmountGTE(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldRefundAmount, v)) +} + +// RefundAmountLT applies the LT predicate on the "refund_amount" field. +func RefundAmountLT(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldRefundAmount, v)) +} + +// RefundAmountLTE applies the LTE predicate on the "refund_amount" field. +func RefundAmountLTE(v float64) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldRefundAmount, v)) +} + +// RefundReasonEQ applies the EQ predicate on the "refund_reason" field. +func RefundReasonEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundReason, v)) +} + +// RefundReasonNEQ applies the NEQ predicate on the "refund_reason" field. +func RefundReasonNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldRefundReason, v)) +} + +// RefundReasonIn applies the In predicate on the "refund_reason" field. +func RefundReasonIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldRefundReason, vs...)) +} + +// RefundReasonNotIn applies the NotIn predicate on the "refund_reason" field. +func RefundReasonNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldRefundReason, vs...)) +} + +// RefundReasonGT applies the GT predicate on the "refund_reason" field. +func RefundReasonGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldRefundReason, v)) +} + +// RefundReasonGTE applies the GTE predicate on the "refund_reason" field. +func RefundReasonGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldRefundReason, v)) +} + +// RefundReasonLT applies the LT predicate on the "refund_reason" field. +func RefundReasonLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldRefundReason, v)) +} + +// RefundReasonLTE applies the LTE predicate on the "refund_reason" field. +func RefundReasonLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldRefundReason, v)) +} + +// RefundReasonContains applies the Contains predicate on the "refund_reason" field. +func RefundReasonContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldRefundReason, v)) +} + +// RefundReasonHasPrefix applies the HasPrefix predicate on the "refund_reason" field. +func RefundReasonHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldRefundReason, v)) +} + +// RefundReasonHasSuffix applies the HasSuffix predicate on the "refund_reason" field. +func RefundReasonHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldRefundReason, v)) +} + +// RefundReasonIsNil applies the IsNil predicate on the "refund_reason" field. +func RefundReasonIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldRefundReason)) +} + +// RefundReasonNotNil applies the NotNil predicate on the "refund_reason" field. +func RefundReasonNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldRefundReason)) +} + +// RefundReasonEqualFold applies the EqualFold predicate on the "refund_reason" field. +func RefundReasonEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldRefundReason, v)) +} + +// RefundReasonContainsFold applies the ContainsFold predicate on the "refund_reason" field. +func RefundReasonContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldRefundReason, v)) +} + +// RefundAtEQ applies the EQ predicate on the "refund_at" field. +func RefundAtEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundAt, v)) +} + +// RefundAtNEQ applies the NEQ predicate on the "refund_at" field. +func RefundAtNEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldRefundAt, v)) +} + +// RefundAtIn applies the In predicate on the "refund_at" field. +func RefundAtIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldRefundAt, vs...)) +} + +// RefundAtNotIn applies the NotIn predicate on the "refund_at" field. +func RefundAtNotIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldRefundAt, vs...)) +} + +// RefundAtGT applies the GT predicate on the "refund_at" field. +func RefundAtGT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldRefundAt, v)) +} + +// RefundAtGTE applies the GTE predicate on the "refund_at" field. +func RefundAtGTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldRefundAt, v)) +} + +// RefundAtLT applies the LT predicate on the "refund_at" field. +func RefundAtLT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldRefundAt, v)) +} + +// RefundAtLTE applies the LTE predicate on the "refund_at" field. +func RefundAtLTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldRefundAt, v)) +} + +// RefundAtIsNil applies the IsNil predicate on the "refund_at" field. +func RefundAtIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldRefundAt)) +} + +// RefundAtNotNil applies the NotNil predicate on the "refund_at" field. +func RefundAtNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldRefundAt)) +} + +// ForceRefundEQ applies the EQ predicate on the "force_refund" field. +func ForceRefundEQ(v bool) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldForceRefund, v)) +} + +// ForceRefundNEQ applies the NEQ predicate on the "force_refund" field. +func ForceRefundNEQ(v bool) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldForceRefund, v)) +} + +// RefundRequestedAtEQ applies the EQ predicate on the "refund_requested_at" field. +func RefundRequestedAtEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundRequestedAt, v)) +} + +// RefundRequestedAtNEQ applies the NEQ predicate on the "refund_requested_at" field. +func RefundRequestedAtNEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldRefundRequestedAt, v)) +} + +// RefundRequestedAtIn applies the In predicate on the "refund_requested_at" field. +func RefundRequestedAtIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldRefundRequestedAt, vs...)) +} + +// RefundRequestedAtNotIn applies the NotIn predicate on the "refund_requested_at" field. +func RefundRequestedAtNotIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldRefundRequestedAt, vs...)) +} + +// RefundRequestedAtGT applies the GT predicate on the "refund_requested_at" field. +func RefundRequestedAtGT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldRefundRequestedAt, v)) +} + +// RefundRequestedAtGTE applies the GTE predicate on the "refund_requested_at" field. +func RefundRequestedAtGTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldRefundRequestedAt, v)) +} + +// RefundRequestedAtLT applies the LT predicate on the "refund_requested_at" field. +func RefundRequestedAtLT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldRefundRequestedAt, v)) +} + +// RefundRequestedAtLTE applies the LTE predicate on the "refund_requested_at" field. +func RefundRequestedAtLTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldRefundRequestedAt, v)) +} + +// RefundRequestedAtIsNil applies the IsNil predicate on the "refund_requested_at" field. +func RefundRequestedAtIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldRefundRequestedAt)) +} + +// RefundRequestedAtNotNil applies the NotNil predicate on the "refund_requested_at" field. +func RefundRequestedAtNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldRefundRequestedAt)) +} + +// RefundRequestReasonEQ applies the EQ predicate on the "refund_request_reason" field. +func RefundRequestReasonEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonNEQ applies the NEQ predicate on the "refund_request_reason" field. +func RefundRequestReasonNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonIn applies the In predicate on the "refund_request_reason" field. +func RefundRequestReasonIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldRefundRequestReason, vs...)) +} + +// RefundRequestReasonNotIn applies the NotIn predicate on the "refund_request_reason" field. +func RefundRequestReasonNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldRefundRequestReason, vs...)) +} + +// RefundRequestReasonGT applies the GT predicate on the "refund_request_reason" field. +func RefundRequestReasonGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonGTE applies the GTE predicate on the "refund_request_reason" field. +func RefundRequestReasonGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonLT applies the LT predicate on the "refund_request_reason" field. +func RefundRequestReasonLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonLTE applies the LTE predicate on the "refund_request_reason" field. +func RefundRequestReasonLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonContains applies the Contains predicate on the "refund_request_reason" field. +func RefundRequestReasonContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonHasPrefix applies the HasPrefix predicate on the "refund_request_reason" field. +func RefundRequestReasonHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonHasSuffix applies the HasSuffix predicate on the "refund_request_reason" field. +func RefundRequestReasonHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonIsNil applies the IsNil predicate on the "refund_request_reason" field. +func RefundRequestReasonIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldRefundRequestReason)) +} + +// RefundRequestReasonNotNil applies the NotNil predicate on the "refund_request_reason" field. +func RefundRequestReasonNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldRefundRequestReason)) +} + +// RefundRequestReasonEqualFold applies the EqualFold predicate on the "refund_request_reason" field. +func RefundRequestReasonEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldRefundRequestReason, v)) +} + +// RefundRequestReasonContainsFold applies the ContainsFold predicate on the "refund_request_reason" field. +func RefundRequestReasonContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldRefundRequestReason, v)) +} + +// RefundRequestedByEQ applies the EQ predicate on the "refund_requested_by" field. +func RefundRequestedByEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByNEQ applies the NEQ predicate on the "refund_requested_by" field. +func RefundRequestedByNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByIn applies the In predicate on the "refund_requested_by" field. +func RefundRequestedByIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldRefundRequestedBy, vs...)) +} + +// RefundRequestedByNotIn applies the NotIn predicate on the "refund_requested_by" field. +func RefundRequestedByNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldRefundRequestedBy, vs...)) +} + +// RefundRequestedByGT applies the GT predicate on the "refund_requested_by" field. +func RefundRequestedByGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByGTE applies the GTE predicate on the "refund_requested_by" field. +func RefundRequestedByGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByLT applies the LT predicate on the "refund_requested_by" field. +func RefundRequestedByLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByLTE applies the LTE predicate on the "refund_requested_by" field. +func RefundRequestedByLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByContains applies the Contains predicate on the "refund_requested_by" field. +func RefundRequestedByContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByHasPrefix applies the HasPrefix predicate on the "refund_requested_by" field. +func RefundRequestedByHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByHasSuffix applies the HasSuffix predicate on the "refund_requested_by" field. +func RefundRequestedByHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByIsNil applies the IsNil predicate on the "refund_requested_by" field. +func RefundRequestedByIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldRefundRequestedBy)) +} + +// RefundRequestedByNotNil applies the NotNil predicate on the "refund_requested_by" field. +func RefundRequestedByNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldRefundRequestedBy)) +} + +// RefundRequestedByEqualFold applies the EqualFold predicate on the "refund_requested_by" field. +func RefundRequestedByEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldRefundRequestedBy, v)) +} + +// RefundRequestedByContainsFold applies the ContainsFold predicate on the "refund_requested_by" field. +func RefundRequestedByContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldRefundRequestedBy, v)) +} + +// ExpiresAtEQ applies the EQ predicate on the "expires_at" field. +func ExpiresAtEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldExpiresAt, v)) +} + +// ExpiresAtNEQ applies the NEQ predicate on the "expires_at" field. +func ExpiresAtNEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldExpiresAt, v)) +} + +// ExpiresAtIn applies the In predicate on the "expires_at" field. +func ExpiresAtIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldExpiresAt, vs...)) +} + +// ExpiresAtNotIn applies the NotIn predicate on the "expires_at" field. +func ExpiresAtNotIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldExpiresAt, vs...)) +} + +// ExpiresAtGT applies the GT predicate on the "expires_at" field. +func ExpiresAtGT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldExpiresAt, v)) +} + +// ExpiresAtGTE applies the GTE predicate on the "expires_at" field. +func ExpiresAtGTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldExpiresAt, v)) +} + +// ExpiresAtLT applies the LT predicate on the "expires_at" field. +func ExpiresAtLT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldExpiresAt, v)) +} + +// ExpiresAtLTE applies the LTE predicate on the "expires_at" field. +func ExpiresAtLTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldExpiresAt, v)) +} + +// PaidAtEQ applies the EQ predicate on the "paid_at" field. +func PaidAtEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldPaidAt, v)) +} + +// PaidAtNEQ applies the NEQ predicate on the "paid_at" field. +func PaidAtNEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldPaidAt, v)) +} + +// PaidAtIn applies the In predicate on the "paid_at" field. +func PaidAtIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldPaidAt, vs...)) +} + +// PaidAtNotIn applies the NotIn predicate on the "paid_at" field. +func PaidAtNotIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldPaidAt, vs...)) +} + +// PaidAtGT applies the GT predicate on the "paid_at" field. +func PaidAtGT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldPaidAt, v)) +} + +// PaidAtGTE applies the GTE predicate on the "paid_at" field. +func PaidAtGTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldPaidAt, v)) +} + +// PaidAtLT applies the LT predicate on the "paid_at" field. +func PaidAtLT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldPaidAt, v)) +} + +// PaidAtLTE applies the LTE predicate on the "paid_at" field. +func PaidAtLTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldPaidAt, v)) +} + +// PaidAtIsNil applies the IsNil predicate on the "paid_at" field. +func PaidAtIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldPaidAt)) +} + +// PaidAtNotNil applies the NotNil predicate on the "paid_at" field. +func PaidAtNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldPaidAt)) +} + +// CompletedAtEQ applies the EQ predicate on the "completed_at" field. +func CompletedAtEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldCompletedAt, v)) +} + +// CompletedAtNEQ applies the NEQ predicate on the "completed_at" field. +func CompletedAtNEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldCompletedAt, v)) +} + +// CompletedAtIn applies the In predicate on the "completed_at" field. +func CompletedAtIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldCompletedAt, vs...)) +} + +// CompletedAtNotIn applies the NotIn predicate on the "completed_at" field. +func CompletedAtNotIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldCompletedAt, vs...)) +} + +// CompletedAtGT applies the GT predicate on the "completed_at" field. +func CompletedAtGT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldCompletedAt, v)) +} + +// CompletedAtGTE applies the GTE predicate on the "completed_at" field. +func CompletedAtGTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldCompletedAt, v)) +} + +// CompletedAtLT applies the LT predicate on the "completed_at" field. +func CompletedAtLT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldCompletedAt, v)) +} + +// CompletedAtLTE applies the LTE predicate on the "completed_at" field. +func CompletedAtLTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldCompletedAt, v)) +} + +// CompletedAtIsNil applies the IsNil predicate on the "completed_at" field. +func CompletedAtIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldCompletedAt)) +} + +// CompletedAtNotNil applies the NotNil predicate on the "completed_at" field. +func CompletedAtNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldCompletedAt)) +} + +// FailedAtEQ applies the EQ predicate on the "failed_at" field. +func FailedAtEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldFailedAt, v)) +} + +// FailedAtNEQ applies the NEQ predicate on the "failed_at" field. +func FailedAtNEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldFailedAt, v)) +} + +// FailedAtIn applies the In predicate on the "failed_at" field. +func FailedAtIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldFailedAt, vs...)) +} + +// FailedAtNotIn applies the NotIn predicate on the "failed_at" field. +func FailedAtNotIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldFailedAt, vs...)) +} + +// FailedAtGT applies the GT predicate on the "failed_at" field. +func FailedAtGT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldFailedAt, v)) +} + +// FailedAtGTE applies the GTE predicate on the "failed_at" field. +func FailedAtGTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldFailedAt, v)) +} + +// FailedAtLT applies the LT predicate on the "failed_at" field. +func FailedAtLT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldFailedAt, v)) +} + +// FailedAtLTE applies the LTE predicate on the "failed_at" field. +func FailedAtLTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldFailedAt, v)) +} + +// FailedAtIsNil applies the IsNil predicate on the "failed_at" field. +func FailedAtIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldFailedAt)) +} + +// FailedAtNotNil applies the NotNil predicate on the "failed_at" field. +func FailedAtNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldFailedAt)) +} + +// FailedReasonEQ applies the EQ predicate on the "failed_reason" field. +func FailedReasonEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldFailedReason, v)) +} + +// FailedReasonNEQ applies the NEQ predicate on the "failed_reason" field. +func FailedReasonNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldFailedReason, v)) +} + +// FailedReasonIn applies the In predicate on the "failed_reason" field. +func FailedReasonIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldFailedReason, vs...)) +} + +// FailedReasonNotIn applies the NotIn predicate on the "failed_reason" field. +func FailedReasonNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldFailedReason, vs...)) +} + +// FailedReasonGT applies the GT predicate on the "failed_reason" field. +func FailedReasonGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldFailedReason, v)) +} + +// FailedReasonGTE applies the GTE predicate on the "failed_reason" field. +func FailedReasonGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldFailedReason, v)) +} + +// FailedReasonLT applies the LT predicate on the "failed_reason" field. +func FailedReasonLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldFailedReason, v)) +} + +// FailedReasonLTE applies the LTE predicate on the "failed_reason" field. +func FailedReasonLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldFailedReason, v)) +} + +// FailedReasonContains applies the Contains predicate on the "failed_reason" field. +func FailedReasonContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldFailedReason, v)) +} + +// FailedReasonHasPrefix applies the HasPrefix predicate on the "failed_reason" field. +func FailedReasonHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldFailedReason, v)) +} + +// FailedReasonHasSuffix applies the HasSuffix predicate on the "failed_reason" field. +func FailedReasonHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldFailedReason, v)) +} + +// FailedReasonIsNil applies the IsNil predicate on the "failed_reason" field. +func FailedReasonIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldFailedReason)) +} + +// FailedReasonNotNil applies the NotNil predicate on the "failed_reason" field. +func FailedReasonNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldFailedReason)) +} + +// FailedReasonEqualFold applies the EqualFold predicate on the "failed_reason" field. +func FailedReasonEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldFailedReason, v)) +} + +// FailedReasonContainsFold applies the ContainsFold predicate on the "failed_reason" field. +func FailedReasonContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldFailedReason, v)) +} + +// ClientIPEQ applies the EQ predicate on the "client_ip" field. +func ClientIPEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldClientIP, v)) +} + +// ClientIPNEQ applies the NEQ predicate on the "client_ip" field. +func ClientIPNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldClientIP, v)) +} + +// ClientIPIn applies the In predicate on the "client_ip" field. +func ClientIPIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldClientIP, vs...)) +} + +// ClientIPNotIn applies the NotIn predicate on the "client_ip" field. +func ClientIPNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldClientIP, vs...)) +} + +// ClientIPGT applies the GT predicate on the "client_ip" field. +func ClientIPGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldClientIP, v)) +} + +// ClientIPGTE applies the GTE predicate on the "client_ip" field. +func ClientIPGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldClientIP, v)) +} + +// ClientIPLT applies the LT predicate on the "client_ip" field. +func ClientIPLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldClientIP, v)) +} + +// ClientIPLTE applies the LTE predicate on the "client_ip" field. +func ClientIPLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldClientIP, v)) +} + +// ClientIPContains applies the Contains predicate on the "client_ip" field. +func ClientIPContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldClientIP, v)) +} + +// ClientIPHasPrefix applies the HasPrefix predicate on the "client_ip" field. +func ClientIPHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldClientIP, v)) +} + +// ClientIPHasSuffix applies the HasSuffix predicate on the "client_ip" field. +func ClientIPHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldClientIP, v)) +} + +// ClientIPEqualFold applies the EqualFold predicate on the "client_ip" field. +func ClientIPEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldClientIP, v)) +} + +// ClientIPContainsFold applies the ContainsFold predicate on the "client_ip" field. +func ClientIPContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldClientIP, v)) +} + +// SrcHostEQ applies the EQ predicate on the "src_host" field. +func SrcHostEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldSrcHost, v)) +} + +// SrcHostNEQ applies the NEQ predicate on the "src_host" field. +func SrcHostNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldSrcHost, v)) +} + +// SrcHostIn applies the In predicate on the "src_host" field. +func SrcHostIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldSrcHost, vs...)) +} + +// SrcHostNotIn applies the NotIn predicate on the "src_host" field. +func SrcHostNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldSrcHost, vs...)) +} + +// SrcHostGT applies the GT predicate on the "src_host" field. +func SrcHostGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldSrcHost, v)) +} + +// SrcHostGTE applies the GTE predicate on the "src_host" field. +func SrcHostGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldSrcHost, v)) +} + +// SrcHostLT applies the LT predicate on the "src_host" field. +func SrcHostLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldSrcHost, v)) +} + +// SrcHostLTE applies the LTE predicate on the "src_host" field. +func SrcHostLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldSrcHost, v)) +} + +// SrcHostContains applies the Contains predicate on the "src_host" field. +func SrcHostContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldSrcHost, v)) +} + +// SrcHostHasPrefix applies the HasPrefix predicate on the "src_host" field. +func SrcHostHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldSrcHost, v)) +} + +// SrcHostHasSuffix applies the HasSuffix predicate on the "src_host" field. +func SrcHostHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldSrcHost, v)) +} + +// SrcHostEqualFold applies the EqualFold predicate on the "src_host" field. +func SrcHostEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldSrcHost, v)) +} + +// SrcHostContainsFold applies the ContainsFold predicate on the "src_host" field. +func SrcHostContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldSrcHost, v)) +} + +// SrcURLEQ applies the EQ predicate on the "src_url" field. +func SrcURLEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldSrcURL, v)) +} + +// SrcURLNEQ applies the NEQ predicate on the "src_url" field. +func SrcURLNEQ(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldSrcURL, v)) +} + +// SrcURLIn applies the In predicate on the "src_url" field. +func SrcURLIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldSrcURL, vs...)) +} + +// SrcURLNotIn applies the NotIn predicate on the "src_url" field. +func SrcURLNotIn(vs ...string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldSrcURL, vs...)) +} + +// SrcURLGT applies the GT predicate on the "src_url" field. +func SrcURLGT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldSrcURL, v)) +} + +// SrcURLGTE applies the GTE predicate on the "src_url" field. +func SrcURLGTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldSrcURL, v)) +} + +// SrcURLLT applies the LT predicate on the "src_url" field. +func SrcURLLT(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldSrcURL, v)) +} + +// SrcURLLTE applies the LTE predicate on the "src_url" field. +func SrcURLLTE(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldSrcURL, v)) +} + +// SrcURLContains applies the Contains predicate on the "src_url" field. +func SrcURLContains(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContains(FieldSrcURL, v)) +} + +// SrcURLHasPrefix applies the HasPrefix predicate on the "src_url" field. +func SrcURLHasPrefix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasPrefix(FieldSrcURL, v)) +} + +// SrcURLHasSuffix applies the HasSuffix predicate on the "src_url" field. +func SrcURLHasSuffix(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldHasSuffix(FieldSrcURL, v)) +} + +// SrcURLIsNil applies the IsNil predicate on the "src_url" field. +func SrcURLIsNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIsNull(FieldSrcURL)) +} + +// SrcURLNotNil applies the NotNil predicate on the "src_url" field. +func SrcURLNotNil() predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotNull(FieldSrcURL)) +} + +// SrcURLEqualFold applies the EqualFold predicate on the "src_url" field. +func SrcURLEqualFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEqualFold(FieldSrcURL, v)) +} + +// SrcURLContainsFold applies the ContainsFold predicate on the "src_url" field. +func SrcURLContainsFold(v string) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldContainsFold(FieldSrcURL, v)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. +func UpdatedAtEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. +func UpdatedAtNEQ(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtIn applies the In predicate on the "updated_at" field. +func UpdatedAtIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. +func UpdatedAtNotIn(vs ...time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldNotIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtGT applies the GT predicate on the "updated_at" field. +func UpdatedAtGT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGT(FieldUpdatedAt, v)) +} + +// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. +func UpdatedAtGTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldGTE(FieldUpdatedAt, v)) +} + +// UpdatedAtLT applies the LT predicate on the "updated_at" field. +func UpdatedAtLT(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLT(FieldUpdatedAt, v)) +} + +// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. +func UpdatedAtLTE(v time.Time) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.FieldLTE(FieldUpdatedAt, v)) +} + +// HasUser applies the HasEdge predicate on the "user" edge. +func HasUser() predicate.PaymentOrder { + return predicate.PaymentOrder(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates). +func HasUserWith(preds ...predicate.User) predicate.PaymentOrder { + return predicate.PaymentOrder(func(s *sql.Selector) { + step := newUserStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.PaymentOrder) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.PaymentOrder) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.PaymentOrder) predicate.PaymentOrder { + return predicate.PaymentOrder(sql.NotPredicates(p)) +} diff --git a/backend/ent/paymentorder_create.go b/backend/ent/paymentorder_create.go new file mode 100644 index 00000000..03098339 --- /dev/null +++ b/backend/ent/paymentorder_create.go @@ -0,0 +1,3109 @@ +// 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/paymentorder" + "github.com/Wei-Shaw/sub2api/ent/user" +) + +// PaymentOrderCreate is the builder for creating a PaymentOrder entity. +type PaymentOrderCreate struct { + config + mutation *PaymentOrderMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetUserID sets the "user_id" field. +func (_c *PaymentOrderCreate) SetUserID(v int64) *PaymentOrderCreate { + _c.mutation.SetUserID(v) + return _c +} + +// SetUserEmail sets the "user_email" field. +func (_c *PaymentOrderCreate) SetUserEmail(v string) *PaymentOrderCreate { + _c.mutation.SetUserEmail(v) + return _c +} + +// SetUserName sets the "user_name" field. +func (_c *PaymentOrderCreate) SetUserName(v string) *PaymentOrderCreate { + _c.mutation.SetUserName(v) + return _c +} + +// SetUserNotes sets the "user_notes" field. +func (_c *PaymentOrderCreate) SetUserNotes(v string) *PaymentOrderCreate { + _c.mutation.SetUserNotes(v) + return _c +} + +// SetNillableUserNotes sets the "user_notes" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableUserNotes(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetUserNotes(*v) + } + return _c +} + +// SetAmount sets the "amount" field. +func (_c *PaymentOrderCreate) SetAmount(v float64) *PaymentOrderCreate { + _c.mutation.SetAmount(v) + return _c +} + +// SetPayAmount sets the "pay_amount" field. +func (_c *PaymentOrderCreate) SetPayAmount(v float64) *PaymentOrderCreate { + _c.mutation.SetPayAmount(v) + return _c +} + +// SetFeeRate sets the "fee_rate" field. +func (_c *PaymentOrderCreate) SetFeeRate(v float64) *PaymentOrderCreate { + _c.mutation.SetFeeRate(v) + return _c +} + +// SetNillableFeeRate sets the "fee_rate" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableFeeRate(v *float64) *PaymentOrderCreate { + if v != nil { + _c.SetFeeRate(*v) + } + return _c +} + +// SetRechargeCode sets the "recharge_code" field. +func (_c *PaymentOrderCreate) SetRechargeCode(v string) *PaymentOrderCreate { + _c.mutation.SetRechargeCode(v) + return _c +} + +// SetOutTradeNo sets the "out_trade_no" field. +func (_c *PaymentOrderCreate) SetOutTradeNo(v string) *PaymentOrderCreate { + _c.mutation.SetOutTradeNo(v) + return _c +} + +// SetNillableOutTradeNo sets the "out_trade_no" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableOutTradeNo(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetOutTradeNo(*v) + } + return _c +} + +// SetPaymentType sets the "payment_type" field. +func (_c *PaymentOrderCreate) SetPaymentType(v string) *PaymentOrderCreate { + _c.mutation.SetPaymentType(v) + return _c +} + +// SetPaymentTradeNo sets the "payment_trade_no" field. +func (_c *PaymentOrderCreate) SetPaymentTradeNo(v string) *PaymentOrderCreate { + _c.mutation.SetPaymentTradeNo(v) + return _c +} + +// SetPayURL sets the "pay_url" field. +func (_c *PaymentOrderCreate) SetPayURL(v string) *PaymentOrderCreate { + _c.mutation.SetPayURL(v) + return _c +} + +// SetNillablePayURL sets the "pay_url" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillablePayURL(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetPayURL(*v) + } + return _c +} + +// SetQrCode sets the "qr_code" field. +func (_c *PaymentOrderCreate) SetQrCode(v string) *PaymentOrderCreate { + _c.mutation.SetQrCode(v) + return _c +} + +// SetNillableQrCode sets the "qr_code" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableQrCode(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetQrCode(*v) + } + return _c +} + +// SetQrCodeImg sets the "qr_code_img" field. +func (_c *PaymentOrderCreate) SetQrCodeImg(v string) *PaymentOrderCreate { + _c.mutation.SetQrCodeImg(v) + return _c +} + +// SetNillableQrCodeImg sets the "qr_code_img" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableQrCodeImg(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetQrCodeImg(*v) + } + return _c +} + +// SetOrderType sets the "order_type" field. +func (_c *PaymentOrderCreate) SetOrderType(v string) *PaymentOrderCreate { + _c.mutation.SetOrderType(v) + return _c +} + +// SetNillableOrderType sets the "order_type" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableOrderType(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetOrderType(*v) + } + return _c +} + +// SetPlanID sets the "plan_id" field. +func (_c *PaymentOrderCreate) SetPlanID(v int64) *PaymentOrderCreate { + _c.mutation.SetPlanID(v) + return _c +} + +// SetNillablePlanID sets the "plan_id" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillablePlanID(v *int64) *PaymentOrderCreate { + if v != nil { + _c.SetPlanID(*v) + } + return _c +} + +// SetSubscriptionGroupID sets the "subscription_group_id" field. +func (_c *PaymentOrderCreate) SetSubscriptionGroupID(v int64) *PaymentOrderCreate { + _c.mutation.SetSubscriptionGroupID(v) + return _c +} + +// SetNillableSubscriptionGroupID sets the "subscription_group_id" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableSubscriptionGroupID(v *int64) *PaymentOrderCreate { + if v != nil { + _c.SetSubscriptionGroupID(*v) + } + return _c +} + +// SetSubscriptionDays sets the "subscription_days" field. +func (_c *PaymentOrderCreate) SetSubscriptionDays(v int) *PaymentOrderCreate { + _c.mutation.SetSubscriptionDays(v) + return _c +} + +// SetNillableSubscriptionDays sets the "subscription_days" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableSubscriptionDays(v *int) *PaymentOrderCreate { + if v != nil { + _c.SetSubscriptionDays(*v) + } + return _c +} + +// SetProviderInstanceID sets the "provider_instance_id" field. +func (_c *PaymentOrderCreate) SetProviderInstanceID(v string) *PaymentOrderCreate { + _c.mutation.SetProviderInstanceID(v) + return _c +} + +// SetNillableProviderInstanceID sets the "provider_instance_id" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableProviderInstanceID(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetProviderInstanceID(*v) + } + return _c +} + +// SetStatus sets the "status" field. +func (_c *PaymentOrderCreate) SetStatus(v string) *PaymentOrderCreate { + _c.mutation.SetStatus(v) + return _c +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableStatus(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetStatus(*v) + } + return _c +} + +// SetRefundAmount sets the "refund_amount" field. +func (_c *PaymentOrderCreate) SetRefundAmount(v float64) *PaymentOrderCreate { + _c.mutation.SetRefundAmount(v) + return _c +} + +// SetNillableRefundAmount sets the "refund_amount" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableRefundAmount(v *float64) *PaymentOrderCreate { + if v != nil { + _c.SetRefundAmount(*v) + } + return _c +} + +// SetRefundReason sets the "refund_reason" field. +func (_c *PaymentOrderCreate) SetRefundReason(v string) *PaymentOrderCreate { + _c.mutation.SetRefundReason(v) + return _c +} + +// SetNillableRefundReason sets the "refund_reason" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableRefundReason(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetRefundReason(*v) + } + return _c +} + +// SetRefundAt sets the "refund_at" field. +func (_c *PaymentOrderCreate) SetRefundAt(v time.Time) *PaymentOrderCreate { + _c.mutation.SetRefundAt(v) + return _c +} + +// SetNillableRefundAt sets the "refund_at" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableRefundAt(v *time.Time) *PaymentOrderCreate { + if v != nil { + _c.SetRefundAt(*v) + } + return _c +} + +// SetForceRefund sets the "force_refund" field. +func (_c *PaymentOrderCreate) SetForceRefund(v bool) *PaymentOrderCreate { + _c.mutation.SetForceRefund(v) + return _c +} + +// SetNillableForceRefund sets the "force_refund" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableForceRefund(v *bool) *PaymentOrderCreate { + if v != nil { + _c.SetForceRefund(*v) + } + return _c +} + +// SetRefundRequestedAt sets the "refund_requested_at" field. +func (_c *PaymentOrderCreate) SetRefundRequestedAt(v time.Time) *PaymentOrderCreate { + _c.mutation.SetRefundRequestedAt(v) + return _c +} + +// SetNillableRefundRequestedAt sets the "refund_requested_at" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableRefundRequestedAt(v *time.Time) *PaymentOrderCreate { + if v != nil { + _c.SetRefundRequestedAt(*v) + } + return _c +} + +// SetRefundRequestReason sets the "refund_request_reason" field. +func (_c *PaymentOrderCreate) SetRefundRequestReason(v string) *PaymentOrderCreate { + _c.mutation.SetRefundRequestReason(v) + return _c +} + +// SetNillableRefundRequestReason sets the "refund_request_reason" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableRefundRequestReason(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetRefundRequestReason(*v) + } + return _c +} + +// SetRefundRequestedBy sets the "refund_requested_by" field. +func (_c *PaymentOrderCreate) SetRefundRequestedBy(v string) *PaymentOrderCreate { + _c.mutation.SetRefundRequestedBy(v) + return _c +} + +// SetNillableRefundRequestedBy sets the "refund_requested_by" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableRefundRequestedBy(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetRefundRequestedBy(*v) + } + return _c +} + +// SetExpiresAt sets the "expires_at" field. +func (_c *PaymentOrderCreate) SetExpiresAt(v time.Time) *PaymentOrderCreate { + _c.mutation.SetExpiresAt(v) + return _c +} + +// SetPaidAt sets the "paid_at" field. +func (_c *PaymentOrderCreate) SetPaidAt(v time.Time) *PaymentOrderCreate { + _c.mutation.SetPaidAt(v) + return _c +} + +// SetNillablePaidAt sets the "paid_at" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillablePaidAt(v *time.Time) *PaymentOrderCreate { + if v != nil { + _c.SetPaidAt(*v) + } + return _c +} + +// SetCompletedAt sets the "completed_at" field. +func (_c *PaymentOrderCreate) SetCompletedAt(v time.Time) *PaymentOrderCreate { + _c.mutation.SetCompletedAt(v) + return _c +} + +// SetNillableCompletedAt sets the "completed_at" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableCompletedAt(v *time.Time) *PaymentOrderCreate { + if v != nil { + _c.SetCompletedAt(*v) + } + return _c +} + +// SetFailedAt sets the "failed_at" field. +func (_c *PaymentOrderCreate) SetFailedAt(v time.Time) *PaymentOrderCreate { + _c.mutation.SetFailedAt(v) + return _c +} + +// SetNillableFailedAt sets the "failed_at" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableFailedAt(v *time.Time) *PaymentOrderCreate { + if v != nil { + _c.SetFailedAt(*v) + } + return _c +} + +// SetFailedReason sets the "failed_reason" field. +func (_c *PaymentOrderCreate) SetFailedReason(v string) *PaymentOrderCreate { + _c.mutation.SetFailedReason(v) + return _c +} + +// SetNillableFailedReason sets the "failed_reason" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableFailedReason(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetFailedReason(*v) + } + return _c +} + +// SetClientIP sets the "client_ip" field. +func (_c *PaymentOrderCreate) SetClientIP(v string) *PaymentOrderCreate { + _c.mutation.SetClientIP(v) + return _c +} + +// SetSrcHost sets the "src_host" field. +func (_c *PaymentOrderCreate) SetSrcHost(v string) *PaymentOrderCreate { + _c.mutation.SetSrcHost(v) + return _c +} + +// SetSrcURL sets the "src_url" field. +func (_c *PaymentOrderCreate) SetSrcURL(v string) *PaymentOrderCreate { + _c.mutation.SetSrcURL(v) + return _c +} + +// SetNillableSrcURL sets the "src_url" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableSrcURL(v *string) *PaymentOrderCreate { + if v != nil { + _c.SetSrcURL(*v) + } + return _c +} + +// SetCreatedAt sets the "created_at" field. +func (_c *PaymentOrderCreate) SetCreatedAt(v time.Time) *PaymentOrderCreate { + _c.mutation.SetCreatedAt(v) + return _c +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableCreatedAt(v *time.Time) *PaymentOrderCreate { + if v != nil { + _c.SetCreatedAt(*v) + } + return _c +} + +// SetUpdatedAt sets the "updated_at" field. +func (_c *PaymentOrderCreate) SetUpdatedAt(v time.Time) *PaymentOrderCreate { + _c.mutation.SetUpdatedAt(v) + return _c +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (_c *PaymentOrderCreate) SetNillableUpdatedAt(v *time.Time) *PaymentOrderCreate { + if v != nil { + _c.SetUpdatedAt(*v) + } + return _c +} + +// SetUser sets the "user" edge to the User entity. +func (_c *PaymentOrderCreate) SetUser(v *User) *PaymentOrderCreate { + return _c.SetUserID(v.ID) +} + +// Mutation returns the PaymentOrderMutation object of the builder. +func (_c *PaymentOrderCreate) Mutation() *PaymentOrderMutation { + return _c.mutation +} + +// Save creates the PaymentOrder in the database. +func (_c *PaymentOrderCreate) Save(ctx context.Context) (*PaymentOrder, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *PaymentOrderCreate) SaveX(ctx context.Context) *PaymentOrder { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *PaymentOrderCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *PaymentOrderCreate) 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 *PaymentOrderCreate) defaults() { + if _, ok := _c.mutation.FeeRate(); !ok { + v := paymentorder.DefaultFeeRate + _c.mutation.SetFeeRate(v) + } + if _, ok := _c.mutation.OutTradeNo(); !ok { + v := paymentorder.DefaultOutTradeNo + _c.mutation.SetOutTradeNo(v) + } + if _, ok := _c.mutation.OrderType(); !ok { + v := paymentorder.DefaultOrderType + _c.mutation.SetOrderType(v) + } + if _, ok := _c.mutation.Status(); !ok { + v := paymentorder.DefaultStatus + _c.mutation.SetStatus(v) + } + if _, ok := _c.mutation.RefundAmount(); !ok { + v := paymentorder.DefaultRefundAmount + _c.mutation.SetRefundAmount(v) + } + if _, ok := _c.mutation.ForceRefund(); !ok { + v := paymentorder.DefaultForceRefund + _c.mutation.SetForceRefund(v) + } + if _, ok := _c.mutation.CreatedAt(); !ok { + v := paymentorder.DefaultCreatedAt() + _c.mutation.SetCreatedAt(v) + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + v := paymentorder.DefaultUpdatedAt() + _c.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *PaymentOrderCreate) check() error { + if _, ok := _c.mutation.UserID(); !ok { + return &ValidationError{Name: "user_id", err: errors.New(`ent: missing required field "PaymentOrder.user_id"`)} + } + if _, ok := _c.mutation.UserEmail(); !ok { + return &ValidationError{Name: "user_email", err: errors.New(`ent: missing required field "PaymentOrder.user_email"`)} + } + if v, ok := _c.mutation.UserEmail(); ok { + if err := paymentorder.UserEmailValidator(v); err != nil { + return &ValidationError{Name: "user_email", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.user_email": %w`, err)} + } + } + if _, ok := _c.mutation.UserName(); !ok { + return &ValidationError{Name: "user_name", err: errors.New(`ent: missing required field "PaymentOrder.user_name"`)} + } + if v, ok := _c.mutation.UserName(); ok { + if err := paymentorder.UserNameValidator(v); err != nil { + return &ValidationError{Name: "user_name", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.user_name": %w`, err)} + } + } + if _, ok := _c.mutation.Amount(); !ok { + return &ValidationError{Name: "amount", err: errors.New(`ent: missing required field "PaymentOrder.amount"`)} + } + if _, ok := _c.mutation.PayAmount(); !ok { + return &ValidationError{Name: "pay_amount", err: errors.New(`ent: missing required field "PaymentOrder.pay_amount"`)} + } + if _, ok := _c.mutation.FeeRate(); !ok { + return &ValidationError{Name: "fee_rate", err: errors.New(`ent: missing required field "PaymentOrder.fee_rate"`)} + } + if _, ok := _c.mutation.RechargeCode(); !ok { + return &ValidationError{Name: "recharge_code", err: errors.New(`ent: missing required field "PaymentOrder.recharge_code"`)} + } + if v, ok := _c.mutation.RechargeCode(); ok { + if err := paymentorder.RechargeCodeValidator(v); err != nil { + return &ValidationError{Name: "recharge_code", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.recharge_code": %w`, err)} + } + } + if _, ok := _c.mutation.OutTradeNo(); !ok { + return &ValidationError{Name: "out_trade_no", err: errors.New(`ent: missing required field "PaymentOrder.out_trade_no"`)} + } + if v, ok := _c.mutation.OutTradeNo(); ok { + if err := paymentorder.OutTradeNoValidator(v); err != nil { + return &ValidationError{Name: "out_trade_no", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.out_trade_no": %w`, err)} + } + } + if _, ok := _c.mutation.PaymentType(); !ok { + return &ValidationError{Name: "payment_type", err: errors.New(`ent: missing required field "PaymentOrder.payment_type"`)} + } + if v, ok := _c.mutation.PaymentType(); ok { + if err := paymentorder.PaymentTypeValidator(v); err != nil { + return &ValidationError{Name: "payment_type", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.payment_type": %w`, err)} + } + } + if _, ok := _c.mutation.PaymentTradeNo(); !ok { + return &ValidationError{Name: "payment_trade_no", err: errors.New(`ent: missing required field "PaymentOrder.payment_trade_no"`)} + } + if v, ok := _c.mutation.PaymentTradeNo(); ok { + if err := paymentorder.PaymentTradeNoValidator(v); err != nil { + return &ValidationError{Name: "payment_trade_no", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.payment_trade_no": %w`, err)} + } + } + if _, ok := _c.mutation.OrderType(); !ok { + return &ValidationError{Name: "order_type", err: errors.New(`ent: missing required field "PaymentOrder.order_type"`)} + } + if v, ok := _c.mutation.OrderType(); ok { + if err := paymentorder.OrderTypeValidator(v); err != nil { + return &ValidationError{Name: "order_type", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.order_type": %w`, err)} + } + } + if v, ok := _c.mutation.ProviderInstanceID(); ok { + if err := paymentorder.ProviderInstanceIDValidator(v); err != nil { + return &ValidationError{Name: "provider_instance_id", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.provider_instance_id": %w`, err)} + } + } + if _, ok := _c.mutation.Status(); !ok { + return &ValidationError{Name: "status", err: errors.New(`ent: missing required field "PaymentOrder.status"`)} + } + if v, ok := _c.mutation.Status(); ok { + if err := paymentorder.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.status": %w`, err)} + } + } + if _, ok := _c.mutation.RefundAmount(); !ok { + return &ValidationError{Name: "refund_amount", err: errors.New(`ent: missing required field "PaymentOrder.refund_amount"`)} + } + if _, ok := _c.mutation.ForceRefund(); !ok { + return &ValidationError{Name: "force_refund", err: errors.New(`ent: missing required field "PaymentOrder.force_refund"`)} + } + if v, ok := _c.mutation.RefundRequestedBy(); ok { + if err := paymentorder.RefundRequestedByValidator(v); err != nil { + return &ValidationError{Name: "refund_requested_by", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.refund_requested_by": %w`, err)} + } + } + if _, ok := _c.mutation.ExpiresAt(); !ok { + return &ValidationError{Name: "expires_at", err: errors.New(`ent: missing required field "PaymentOrder.expires_at"`)} + } + if _, ok := _c.mutation.ClientIP(); !ok { + return &ValidationError{Name: "client_ip", err: errors.New(`ent: missing required field "PaymentOrder.client_ip"`)} + } + if v, ok := _c.mutation.ClientIP(); ok { + if err := paymentorder.ClientIPValidator(v); err != nil { + return &ValidationError{Name: "client_ip", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.client_ip": %w`, err)} + } + } + if _, ok := _c.mutation.SrcHost(); !ok { + return &ValidationError{Name: "src_host", err: errors.New(`ent: missing required field "PaymentOrder.src_host"`)} + } + if v, ok := _c.mutation.SrcHost(); ok { + if err := paymentorder.SrcHostValidator(v); err != nil { + return &ValidationError{Name: "src_host", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.src_host": %w`, err)} + } + } + if _, ok := _c.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "PaymentOrder.created_at"`)} + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "PaymentOrder.updated_at"`)} + } + if len(_c.mutation.UserIDs()) == 0 { + return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "PaymentOrder.user"`)} + } + return nil +} + +func (_c *PaymentOrderCreate) sqlSave(ctx context.Context) (*PaymentOrder, 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 *PaymentOrderCreate) createSpec() (*PaymentOrder, *sqlgraph.CreateSpec) { + var ( + _node = &PaymentOrder{config: _c.config} + _spec = sqlgraph.NewCreateSpec(paymentorder.Table, sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.UserEmail(); ok { + _spec.SetField(paymentorder.FieldUserEmail, field.TypeString, value) + _node.UserEmail = value + } + if value, ok := _c.mutation.UserName(); ok { + _spec.SetField(paymentorder.FieldUserName, field.TypeString, value) + _node.UserName = value + } + if value, ok := _c.mutation.UserNotes(); ok { + _spec.SetField(paymentorder.FieldUserNotes, field.TypeString, value) + _node.UserNotes = &value + } + if value, ok := _c.mutation.Amount(); ok { + _spec.SetField(paymentorder.FieldAmount, field.TypeFloat64, value) + _node.Amount = value + } + if value, ok := _c.mutation.PayAmount(); ok { + _spec.SetField(paymentorder.FieldPayAmount, field.TypeFloat64, value) + _node.PayAmount = value + } + if value, ok := _c.mutation.FeeRate(); ok { + _spec.SetField(paymentorder.FieldFeeRate, field.TypeFloat64, value) + _node.FeeRate = value + } + if value, ok := _c.mutation.RechargeCode(); ok { + _spec.SetField(paymentorder.FieldRechargeCode, field.TypeString, value) + _node.RechargeCode = value + } + if value, ok := _c.mutation.OutTradeNo(); ok { + _spec.SetField(paymentorder.FieldOutTradeNo, field.TypeString, value) + _node.OutTradeNo = value + } + if value, ok := _c.mutation.PaymentType(); ok { + _spec.SetField(paymentorder.FieldPaymentType, field.TypeString, value) + _node.PaymentType = value + } + if value, ok := _c.mutation.PaymentTradeNo(); ok { + _spec.SetField(paymentorder.FieldPaymentTradeNo, field.TypeString, value) + _node.PaymentTradeNo = value + } + if value, ok := _c.mutation.PayURL(); ok { + _spec.SetField(paymentorder.FieldPayURL, field.TypeString, value) + _node.PayURL = &value + } + if value, ok := _c.mutation.QrCode(); ok { + _spec.SetField(paymentorder.FieldQrCode, field.TypeString, value) + _node.QrCode = &value + } + if value, ok := _c.mutation.QrCodeImg(); ok { + _spec.SetField(paymentorder.FieldQrCodeImg, field.TypeString, value) + _node.QrCodeImg = &value + } + if value, ok := _c.mutation.OrderType(); ok { + _spec.SetField(paymentorder.FieldOrderType, field.TypeString, value) + _node.OrderType = value + } + if value, ok := _c.mutation.PlanID(); ok { + _spec.SetField(paymentorder.FieldPlanID, field.TypeInt64, value) + _node.PlanID = &value + } + if value, ok := _c.mutation.SubscriptionGroupID(); ok { + _spec.SetField(paymentorder.FieldSubscriptionGroupID, field.TypeInt64, value) + _node.SubscriptionGroupID = &value + } + if value, ok := _c.mutation.SubscriptionDays(); ok { + _spec.SetField(paymentorder.FieldSubscriptionDays, field.TypeInt, value) + _node.SubscriptionDays = &value + } + if value, ok := _c.mutation.ProviderInstanceID(); ok { + _spec.SetField(paymentorder.FieldProviderInstanceID, field.TypeString, value) + _node.ProviderInstanceID = &value + } + if value, ok := _c.mutation.Status(); ok { + _spec.SetField(paymentorder.FieldStatus, field.TypeString, value) + _node.Status = value + } + if value, ok := _c.mutation.RefundAmount(); ok { + _spec.SetField(paymentorder.FieldRefundAmount, field.TypeFloat64, value) + _node.RefundAmount = value + } + if value, ok := _c.mutation.RefundReason(); ok { + _spec.SetField(paymentorder.FieldRefundReason, field.TypeString, value) + _node.RefundReason = &value + } + if value, ok := _c.mutation.RefundAt(); ok { + _spec.SetField(paymentorder.FieldRefundAt, field.TypeTime, value) + _node.RefundAt = &value + } + if value, ok := _c.mutation.ForceRefund(); ok { + _spec.SetField(paymentorder.FieldForceRefund, field.TypeBool, value) + _node.ForceRefund = value + } + if value, ok := _c.mutation.RefundRequestedAt(); ok { + _spec.SetField(paymentorder.FieldRefundRequestedAt, field.TypeTime, value) + _node.RefundRequestedAt = &value + } + if value, ok := _c.mutation.RefundRequestReason(); ok { + _spec.SetField(paymentorder.FieldRefundRequestReason, field.TypeString, value) + _node.RefundRequestReason = &value + } + if value, ok := _c.mutation.RefundRequestedBy(); ok { + _spec.SetField(paymentorder.FieldRefundRequestedBy, field.TypeString, value) + _node.RefundRequestedBy = &value + } + if value, ok := _c.mutation.ExpiresAt(); ok { + _spec.SetField(paymentorder.FieldExpiresAt, field.TypeTime, value) + _node.ExpiresAt = value + } + if value, ok := _c.mutation.PaidAt(); ok { + _spec.SetField(paymentorder.FieldPaidAt, field.TypeTime, value) + _node.PaidAt = &value + } + if value, ok := _c.mutation.CompletedAt(); ok { + _spec.SetField(paymentorder.FieldCompletedAt, field.TypeTime, value) + _node.CompletedAt = &value + } + if value, ok := _c.mutation.FailedAt(); ok { + _spec.SetField(paymentorder.FieldFailedAt, field.TypeTime, value) + _node.FailedAt = &value + } + if value, ok := _c.mutation.FailedReason(); ok { + _spec.SetField(paymentorder.FieldFailedReason, field.TypeString, value) + _node.FailedReason = &value + } + if value, ok := _c.mutation.ClientIP(); ok { + _spec.SetField(paymentorder.FieldClientIP, field.TypeString, value) + _node.ClientIP = value + } + if value, ok := _c.mutation.SrcHost(); ok { + _spec.SetField(paymentorder.FieldSrcHost, field.TypeString, value) + _node.SrcHost = value + } + if value, ok := _c.mutation.SrcURL(); ok { + _spec.SetField(paymentorder.FieldSrcURL, field.TypeString, value) + _node.SrcURL = &value + } + if value, ok := _c.mutation.CreatedAt(); ok { + _spec.SetField(paymentorder.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := _c.mutation.UpdatedAt(); ok { + _spec.SetField(paymentorder.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + if nodes := _c.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: paymentorder.UserTable, + Columns: []string{paymentorder.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.UserID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.PaymentOrder.Create(). +// SetUserID(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.PaymentOrderUpsert) { +// SetUserID(v+v). +// }). +// Exec(ctx) +func (_c *PaymentOrderCreate) OnConflict(opts ...sql.ConflictOption) *PaymentOrderUpsertOne { + _c.conflict = opts + return &PaymentOrderUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.PaymentOrder.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *PaymentOrderCreate) OnConflictColumns(columns ...string) *PaymentOrderUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &PaymentOrderUpsertOne{ + create: _c, + } +} + +type ( + // PaymentOrderUpsertOne is the builder for "upsert"-ing + // one PaymentOrder node. + PaymentOrderUpsertOne struct { + create *PaymentOrderCreate + } + + // PaymentOrderUpsert is the "OnConflict" setter. + PaymentOrderUpsert struct { + *sql.UpdateSet + } +) + +// SetUserID sets the "user_id" field. +func (u *PaymentOrderUpsert) SetUserID(v int64) *PaymentOrderUpsert { + u.Set(paymentorder.FieldUserID, v) + return u +} + +// UpdateUserID sets the "user_id" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateUserID() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldUserID) + return u +} + +// SetUserEmail sets the "user_email" field. +func (u *PaymentOrderUpsert) SetUserEmail(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldUserEmail, v) + return u +} + +// UpdateUserEmail sets the "user_email" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateUserEmail() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldUserEmail) + return u +} + +// SetUserName sets the "user_name" field. +func (u *PaymentOrderUpsert) SetUserName(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldUserName, v) + return u +} + +// UpdateUserName sets the "user_name" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateUserName() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldUserName) + return u +} + +// SetUserNotes sets the "user_notes" field. +func (u *PaymentOrderUpsert) SetUserNotes(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldUserNotes, v) + return u +} + +// UpdateUserNotes sets the "user_notes" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateUserNotes() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldUserNotes) + return u +} + +// ClearUserNotes clears the value of the "user_notes" field. +func (u *PaymentOrderUpsert) ClearUserNotes() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldUserNotes) + return u +} + +// SetAmount sets the "amount" field. +func (u *PaymentOrderUpsert) SetAmount(v float64) *PaymentOrderUpsert { + u.Set(paymentorder.FieldAmount, v) + return u +} + +// UpdateAmount sets the "amount" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateAmount() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldAmount) + return u +} + +// AddAmount adds v to the "amount" field. +func (u *PaymentOrderUpsert) AddAmount(v float64) *PaymentOrderUpsert { + u.Add(paymentorder.FieldAmount, v) + return u +} + +// SetPayAmount sets the "pay_amount" field. +func (u *PaymentOrderUpsert) SetPayAmount(v float64) *PaymentOrderUpsert { + u.Set(paymentorder.FieldPayAmount, v) + return u +} + +// UpdatePayAmount sets the "pay_amount" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdatePayAmount() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldPayAmount) + return u +} + +// AddPayAmount adds v to the "pay_amount" field. +func (u *PaymentOrderUpsert) AddPayAmount(v float64) *PaymentOrderUpsert { + u.Add(paymentorder.FieldPayAmount, v) + return u +} + +// SetFeeRate sets the "fee_rate" field. +func (u *PaymentOrderUpsert) SetFeeRate(v float64) *PaymentOrderUpsert { + u.Set(paymentorder.FieldFeeRate, v) + return u +} + +// UpdateFeeRate sets the "fee_rate" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateFeeRate() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldFeeRate) + return u +} + +// AddFeeRate adds v to the "fee_rate" field. +func (u *PaymentOrderUpsert) AddFeeRate(v float64) *PaymentOrderUpsert { + u.Add(paymentorder.FieldFeeRate, v) + return u +} + +// SetRechargeCode sets the "recharge_code" field. +func (u *PaymentOrderUpsert) SetRechargeCode(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldRechargeCode, v) + return u +} + +// UpdateRechargeCode sets the "recharge_code" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateRechargeCode() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldRechargeCode) + return u +} + +// SetOutTradeNo sets the "out_trade_no" field. +func (u *PaymentOrderUpsert) SetOutTradeNo(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldOutTradeNo, v) + return u +} + +// UpdateOutTradeNo sets the "out_trade_no" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateOutTradeNo() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldOutTradeNo) + return u +} + +// SetPaymentType sets the "payment_type" field. +func (u *PaymentOrderUpsert) SetPaymentType(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldPaymentType, v) + return u +} + +// UpdatePaymentType sets the "payment_type" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdatePaymentType() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldPaymentType) + return u +} + +// SetPaymentTradeNo sets the "payment_trade_no" field. +func (u *PaymentOrderUpsert) SetPaymentTradeNo(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldPaymentTradeNo, v) + return u +} + +// UpdatePaymentTradeNo sets the "payment_trade_no" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdatePaymentTradeNo() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldPaymentTradeNo) + return u +} + +// SetPayURL sets the "pay_url" field. +func (u *PaymentOrderUpsert) SetPayURL(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldPayURL, v) + return u +} + +// UpdatePayURL sets the "pay_url" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdatePayURL() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldPayURL) + return u +} + +// ClearPayURL clears the value of the "pay_url" field. +func (u *PaymentOrderUpsert) ClearPayURL() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldPayURL) + return u +} + +// SetQrCode sets the "qr_code" field. +func (u *PaymentOrderUpsert) SetQrCode(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldQrCode, v) + return u +} + +// UpdateQrCode sets the "qr_code" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateQrCode() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldQrCode) + return u +} + +// ClearQrCode clears the value of the "qr_code" field. +func (u *PaymentOrderUpsert) ClearQrCode() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldQrCode) + return u +} + +// SetQrCodeImg sets the "qr_code_img" field. +func (u *PaymentOrderUpsert) SetQrCodeImg(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldQrCodeImg, v) + return u +} + +// UpdateQrCodeImg sets the "qr_code_img" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateQrCodeImg() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldQrCodeImg) + return u +} + +// ClearQrCodeImg clears the value of the "qr_code_img" field. +func (u *PaymentOrderUpsert) ClearQrCodeImg() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldQrCodeImg) + return u +} + +// SetOrderType sets the "order_type" field. +func (u *PaymentOrderUpsert) SetOrderType(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldOrderType, v) + return u +} + +// UpdateOrderType sets the "order_type" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateOrderType() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldOrderType) + return u +} + +// SetPlanID sets the "plan_id" field. +func (u *PaymentOrderUpsert) SetPlanID(v int64) *PaymentOrderUpsert { + u.Set(paymentorder.FieldPlanID, v) + return u +} + +// UpdatePlanID sets the "plan_id" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdatePlanID() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldPlanID) + return u +} + +// AddPlanID adds v to the "plan_id" field. +func (u *PaymentOrderUpsert) AddPlanID(v int64) *PaymentOrderUpsert { + u.Add(paymentorder.FieldPlanID, v) + return u +} + +// ClearPlanID clears the value of the "plan_id" field. +func (u *PaymentOrderUpsert) ClearPlanID() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldPlanID) + return u +} + +// SetSubscriptionGroupID sets the "subscription_group_id" field. +func (u *PaymentOrderUpsert) SetSubscriptionGroupID(v int64) *PaymentOrderUpsert { + u.Set(paymentorder.FieldSubscriptionGroupID, v) + return u +} + +// UpdateSubscriptionGroupID sets the "subscription_group_id" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateSubscriptionGroupID() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldSubscriptionGroupID) + return u +} + +// AddSubscriptionGroupID adds v to the "subscription_group_id" field. +func (u *PaymentOrderUpsert) AddSubscriptionGroupID(v int64) *PaymentOrderUpsert { + u.Add(paymentorder.FieldSubscriptionGroupID, v) + return u +} + +// ClearSubscriptionGroupID clears the value of the "subscription_group_id" field. +func (u *PaymentOrderUpsert) ClearSubscriptionGroupID() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldSubscriptionGroupID) + return u +} + +// SetSubscriptionDays sets the "subscription_days" field. +func (u *PaymentOrderUpsert) SetSubscriptionDays(v int) *PaymentOrderUpsert { + u.Set(paymentorder.FieldSubscriptionDays, v) + return u +} + +// UpdateSubscriptionDays sets the "subscription_days" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateSubscriptionDays() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldSubscriptionDays) + return u +} + +// AddSubscriptionDays adds v to the "subscription_days" field. +func (u *PaymentOrderUpsert) AddSubscriptionDays(v int) *PaymentOrderUpsert { + u.Add(paymentorder.FieldSubscriptionDays, v) + return u +} + +// ClearSubscriptionDays clears the value of the "subscription_days" field. +func (u *PaymentOrderUpsert) ClearSubscriptionDays() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldSubscriptionDays) + return u +} + +// SetProviderInstanceID sets the "provider_instance_id" field. +func (u *PaymentOrderUpsert) SetProviderInstanceID(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldProviderInstanceID, v) + return u +} + +// UpdateProviderInstanceID sets the "provider_instance_id" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateProviderInstanceID() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldProviderInstanceID) + return u +} + +// ClearProviderInstanceID clears the value of the "provider_instance_id" field. +func (u *PaymentOrderUpsert) ClearProviderInstanceID() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldProviderInstanceID) + return u +} + +// SetStatus sets the "status" field. +func (u *PaymentOrderUpsert) SetStatus(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldStatus, v) + return u +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateStatus() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldStatus) + return u +} + +// SetRefundAmount sets the "refund_amount" field. +func (u *PaymentOrderUpsert) SetRefundAmount(v float64) *PaymentOrderUpsert { + u.Set(paymentorder.FieldRefundAmount, v) + return u +} + +// UpdateRefundAmount sets the "refund_amount" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateRefundAmount() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldRefundAmount) + return u +} + +// AddRefundAmount adds v to the "refund_amount" field. +func (u *PaymentOrderUpsert) AddRefundAmount(v float64) *PaymentOrderUpsert { + u.Add(paymentorder.FieldRefundAmount, v) + return u +} + +// SetRefundReason sets the "refund_reason" field. +func (u *PaymentOrderUpsert) SetRefundReason(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldRefundReason, v) + return u +} + +// UpdateRefundReason sets the "refund_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateRefundReason() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldRefundReason) + return u +} + +// ClearRefundReason clears the value of the "refund_reason" field. +func (u *PaymentOrderUpsert) ClearRefundReason() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldRefundReason) + return u +} + +// SetRefundAt sets the "refund_at" field. +func (u *PaymentOrderUpsert) SetRefundAt(v time.Time) *PaymentOrderUpsert { + u.Set(paymentorder.FieldRefundAt, v) + return u +} + +// UpdateRefundAt sets the "refund_at" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateRefundAt() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldRefundAt) + return u +} + +// ClearRefundAt clears the value of the "refund_at" field. +func (u *PaymentOrderUpsert) ClearRefundAt() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldRefundAt) + return u +} + +// SetForceRefund sets the "force_refund" field. +func (u *PaymentOrderUpsert) SetForceRefund(v bool) *PaymentOrderUpsert { + u.Set(paymentorder.FieldForceRefund, v) + return u +} + +// UpdateForceRefund sets the "force_refund" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateForceRefund() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldForceRefund) + return u +} + +// SetRefundRequestedAt sets the "refund_requested_at" field. +func (u *PaymentOrderUpsert) SetRefundRequestedAt(v time.Time) *PaymentOrderUpsert { + u.Set(paymentorder.FieldRefundRequestedAt, v) + return u +} + +// UpdateRefundRequestedAt sets the "refund_requested_at" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateRefundRequestedAt() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldRefundRequestedAt) + return u +} + +// ClearRefundRequestedAt clears the value of the "refund_requested_at" field. +func (u *PaymentOrderUpsert) ClearRefundRequestedAt() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldRefundRequestedAt) + return u +} + +// SetRefundRequestReason sets the "refund_request_reason" field. +func (u *PaymentOrderUpsert) SetRefundRequestReason(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldRefundRequestReason, v) + return u +} + +// UpdateRefundRequestReason sets the "refund_request_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateRefundRequestReason() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldRefundRequestReason) + return u +} + +// ClearRefundRequestReason clears the value of the "refund_request_reason" field. +func (u *PaymentOrderUpsert) ClearRefundRequestReason() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldRefundRequestReason) + return u +} + +// SetRefundRequestedBy sets the "refund_requested_by" field. +func (u *PaymentOrderUpsert) SetRefundRequestedBy(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldRefundRequestedBy, v) + return u +} + +// UpdateRefundRequestedBy sets the "refund_requested_by" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateRefundRequestedBy() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldRefundRequestedBy) + return u +} + +// ClearRefundRequestedBy clears the value of the "refund_requested_by" field. +func (u *PaymentOrderUpsert) ClearRefundRequestedBy() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldRefundRequestedBy) + return u +} + +// SetExpiresAt sets the "expires_at" field. +func (u *PaymentOrderUpsert) SetExpiresAt(v time.Time) *PaymentOrderUpsert { + u.Set(paymentorder.FieldExpiresAt, v) + return u +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateExpiresAt() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldExpiresAt) + return u +} + +// SetPaidAt sets the "paid_at" field. +func (u *PaymentOrderUpsert) SetPaidAt(v time.Time) *PaymentOrderUpsert { + u.Set(paymentorder.FieldPaidAt, v) + return u +} + +// UpdatePaidAt sets the "paid_at" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdatePaidAt() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldPaidAt) + return u +} + +// ClearPaidAt clears the value of the "paid_at" field. +func (u *PaymentOrderUpsert) ClearPaidAt() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldPaidAt) + return u +} + +// SetCompletedAt sets the "completed_at" field. +func (u *PaymentOrderUpsert) SetCompletedAt(v time.Time) *PaymentOrderUpsert { + u.Set(paymentorder.FieldCompletedAt, v) + return u +} + +// UpdateCompletedAt sets the "completed_at" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateCompletedAt() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldCompletedAt) + return u +} + +// ClearCompletedAt clears the value of the "completed_at" field. +func (u *PaymentOrderUpsert) ClearCompletedAt() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldCompletedAt) + return u +} + +// SetFailedAt sets the "failed_at" field. +func (u *PaymentOrderUpsert) SetFailedAt(v time.Time) *PaymentOrderUpsert { + u.Set(paymentorder.FieldFailedAt, v) + return u +} + +// UpdateFailedAt sets the "failed_at" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateFailedAt() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldFailedAt) + return u +} + +// ClearFailedAt clears the value of the "failed_at" field. +func (u *PaymentOrderUpsert) ClearFailedAt() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldFailedAt) + return u +} + +// SetFailedReason sets the "failed_reason" field. +func (u *PaymentOrderUpsert) SetFailedReason(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldFailedReason, v) + return u +} + +// UpdateFailedReason sets the "failed_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateFailedReason() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldFailedReason) + return u +} + +// ClearFailedReason clears the value of the "failed_reason" field. +func (u *PaymentOrderUpsert) ClearFailedReason() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldFailedReason) + return u +} + +// SetClientIP sets the "client_ip" field. +func (u *PaymentOrderUpsert) SetClientIP(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldClientIP, v) + return u +} + +// UpdateClientIP sets the "client_ip" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateClientIP() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldClientIP) + return u +} + +// SetSrcHost sets the "src_host" field. +func (u *PaymentOrderUpsert) SetSrcHost(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldSrcHost, v) + return u +} + +// UpdateSrcHost sets the "src_host" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateSrcHost() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldSrcHost) + return u +} + +// SetSrcURL sets the "src_url" field. +func (u *PaymentOrderUpsert) SetSrcURL(v string) *PaymentOrderUpsert { + u.Set(paymentorder.FieldSrcURL, v) + return u +} + +// UpdateSrcURL sets the "src_url" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateSrcURL() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldSrcURL) + return u +} + +// ClearSrcURL clears the value of the "src_url" field. +func (u *PaymentOrderUpsert) ClearSrcURL() *PaymentOrderUpsert { + u.SetNull(paymentorder.FieldSrcURL) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *PaymentOrderUpsert) SetUpdatedAt(v time.Time) *PaymentOrderUpsert { + u.Set(paymentorder.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *PaymentOrderUpsert) UpdateUpdatedAt() *PaymentOrderUpsert { + u.SetExcluded(paymentorder.FieldUpdatedAt) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.PaymentOrder.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *PaymentOrderUpsertOne) UpdateNewValues() *PaymentOrderUpsertOne { + 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(paymentorder.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.PaymentOrder.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *PaymentOrderUpsertOne) Ignore() *PaymentOrderUpsertOne { + 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 *PaymentOrderUpsertOne) DoNothing() *PaymentOrderUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the PaymentOrderCreate.OnConflict +// documentation for more info. +func (u *PaymentOrderUpsertOne) Update(set func(*PaymentOrderUpsert)) *PaymentOrderUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&PaymentOrderUpsert{UpdateSet: update}) + })) + return u +} + +// SetUserID sets the "user_id" field. +func (u *PaymentOrderUpsertOne) SetUserID(v int64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUserID(v) + }) +} + +// UpdateUserID sets the "user_id" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateUserID() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUserID() + }) +} + +// SetUserEmail sets the "user_email" field. +func (u *PaymentOrderUpsertOne) SetUserEmail(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUserEmail(v) + }) +} + +// UpdateUserEmail sets the "user_email" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateUserEmail() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUserEmail() + }) +} + +// SetUserName sets the "user_name" field. +func (u *PaymentOrderUpsertOne) SetUserName(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUserName(v) + }) +} + +// UpdateUserName sets the "user_name" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateUserName() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUserName() + }) +} + +// SetUserNotes sets the "user_notes" field. +func (u *PaymentOrderUpsertOne) SetUserNotes(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUserNotes(v) + }) +} + +// UpdateUserNotes sets the "user_notes" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateUserNotes() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUserNotes() + }) +} + +// ClearUserNotes clears the value of the "user_notes" field. +func (u *PaymentOrderUpsertOne) ClearUserNotes() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearUserNotes() + }) +} + +// SetAmount sets the "amount" field. +func (u *PaymentOrderUpsertOne) SetAmount(v float64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetAmount(v) + }) +} + +// AddAmount adds v to the "amount" field. +func (u *PaymentOrderUpsertOne) AddAmount(v float64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddAmount(v) + }) +} + +// UpdateAmount sets the "amount" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateAmount() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateAmount() + }) +} + +// SetPayAmount sets the "pay_amount" field. +func (u *PaymentOrderUpsertOne) SetPayAmount(v float64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPayAmount(v) + }) +} + +// AddPayAmount adds v to the "pay_amount" field. +func (u *PaymentOrderUpsertOne) AddPayAmount(v float64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddPayAmount(v) + }) +} + +// UpdatePayAmount sets the "pay_amount" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdatePayAmount() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePayAmount() + }) +} + +// SetFeeRate sets the "fee_rate" field. +func (u *PaymentOrderUpsertOne) SetFeeRate(v float64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetFeeRate(v) + }) +} + +// AddFeeRate adds v to the "fee_rate" field. +func (u *PaymentOrderUpsertOne) AddFeeRate(v float64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddFeeRate(v) + }) +} + +// UpdateFeeRate sets the "fee_rate" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateFeeRate() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateFeeRate() + }) +} + +// SetRechargeCode sets the "recharge_code" field. +func (u *PaymentOrderUpsertOne) SetRechargeCode(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRechargeCode(v) + }) +} + +// UpdateRechargeCode sets the "recharge_code" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateRechargeCode() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRechargeCode() + }) +} + +// SetOutTradeNo sets the "out_trade_no" field. +func (u *PaymentOrderUpsertOne) SetOutTradeNo(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetOutTradeNo(v) + }) +} + +// UpdateOutTradeNo sets the "out_trade_no" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateOutTradeNo() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateOutTradeNo() + }) +} + +// SetPaymentType sets the "payment_type" field. +func (u *PaymentOrderUpsertOne) SetPaymentType(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPaymentType(v) + }) +} + +// UpdatePaymentType sets the "payment_type" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdatePaymentType() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePaymentType() + }) +} + +// SetPaymentTradeNo sets the "payment_trade_no" field. +func (u *PaymentOrderUpsertOne) SetPaymentTradeNo(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPaymentTradeNo(v) + }) +} + +// UpdatePaymentTradeNo sets the "payment_trade_no" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdatePaymentTradeNo() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePaymentTradeNo() + }) +} + +// SetPayURL sets the "pay_url" field. +func (u *PaymentOrderUpsertOne) SetPayURL(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPayURL(v) + }) +} + +// UpdatePayURL sets the "pay_url" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdatePayURL() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePayURL() + }) +} + +// ClearPayURL clears the value of the "pay_url" field. +func (u *PaymentOrderUpsertOne) ClearPayURL() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearPayURL() + }) +} + +// SetQrCode sets the "qr_code" field. +func (u *PaymentOrderUpsertOne) SetQrCode(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetQrCode(v) + }) +} + +// UpdateQrCode sets the "qr_code" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateQrCode() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateQrCode() + }) +} + +// ClearQrCode clears the value of the "qr_code" field. +func (u *PaymentOrderUpsertOne) ClearQrCode() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearQrCode() + }) +} + +// SetQrCodeImg sets the "qr_code_img" field. +func (u *PaymentOrderUpsertOne) SetQrCodeImg(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetQrCodeImg(v) + }) +} + +// UpdateQrCodeImg sets the "qr_code_img" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateQrCodeImg() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateQrCodeImg() + }) +} + +// ClearQrCodeImg clears the value of the "qr_code_img" field. +func (u *PaymentOrderUpsertOne) ClearQrCodeImg() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearQrCodeImg() + }) +} + +// SetOrderType sets the "order_type" field. +func (u *PaymentOrderUpsertOne) SetOrderType(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetOrderType(v) + }) +} + +// UpdateOrderType sets the "order_type" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateOrderType() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateOrderType() + }) +} + +// SetPlanID sets the "plan_id" field. +func (u *PaymentOrderUpsertOne) SetPlanID(v int64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPlanID(v) + }) +} + +// AddPlanID adds v to the "plan_id" field. +func (u *PaymentOrderUpsertOne) AddPlanID(v int64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddPlanID(v) + }) +} + +// UpdatePlanID sets the "plan_id" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdatePlanID() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePlanID() + }) +} + +// ClearPlanID clears the value of the "plan_id" field. +func (u *PaymentOrderUpsertOne) ClearPlanID() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearPlanID() + }) +} + +// SetSubscriptionGroupID sets the "subscription_group_id" field. +func (u *PaymentOrderUpsertOne) SetSubscriptionGroupID(v int64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetSubscriptionGroupID(v) + }) +} + +// AddSubscriptionGroupID adds v to the "subscription_group_id" field. +func (u *PaymentOrderUpsertOne) AddSubscriptionGroupID(v int64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddSubscriptionGroupID(v) + }) +} + +// UpdateSubscriptionGroupID sets the "subscription_group_id" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateSubscriptionGroupID() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateSubscriptionGroupID() + }) +} + +// ClearSubscriptionGroupID clears the value of the "subscription_group_id" field. +func (u *PaymentOrderUpsertOne) ClearSubscriptionGroupID() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearSubscriptionGroupID() + }) +} + +// SetSubscriptionDays sets the "subscription_days" field. +func (u *PaymentOrderUpsertOne) SetSubscriptionDays(v int) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetSubscriptionDays(v) + }) +} + +// AddSubscriptionDays adds v to the "subscription_days" field. +func (u *PaymentOrderUpsertOne) AddSubscriptionDays(v int) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddSubscriptionDays(v) + }) +} + +// UpdateSubscriptionDays sets the "subscription_days" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateSubscriptionDays() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateSubscriptionDays() + }) +} + +// ClearSubscriptionDays clears the value of the "subscription_days" field. +func (u *PaymentOrderUpsertOne) ClearSubscriptionDays() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearSubscriptionDays() + }) +} + +// SetProviderInstanceID sets the "provider_instance_id" field. +func (u *PaymentOrderUpsertOne) SetProviderInstanceID(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetProviderInstanceID(v) + }) +} + +// UpdateProviderInstanceID sets the "provider_instance_id" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateProviderInstanceID() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateProviderInstanceID() + }) +} + +// ClearProviderInstanceID clears the value of the "provider_instance_id" field. +func (u *PaymentOrderUpsertOne) ClearProviderInstanceID() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearProviderInstanceID() + }) +} + +// SetStatus sets the "status" field. +func (u *PaymentOrderUpsertOne) SetStatus(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetStatus(v) + }) +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateStatus() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateStatus() + }) +} + +// SetRefundAmount sets the "refund_amount" field. +func (u *PaymentOrderUpsertOne) SetRefundAmount(v float64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundAmount(v) + }) +} + +// AddRefundAmount adds v to the "refund_amount" field. +func (u *PaymentOrderUpsertOne) AddRefundAmount(v float64) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddRefundAmount(v) + }) +} + +// UpdateRefundAmount sets the "refund_amount" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateRefundAmount() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundAmount() + }) +} + +// SetRefundReason sets the "refund_reason" field. +func (u *PaymentOrderUpsertOne) SetRefundReason(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundReason(v) + }) +} + +// UpdateRefundReason sets the "refund_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateRefundReason() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundReason() + }) +} + +// ClearRefundReason clears the value of the "refund_reason" field. +func (u *PaymentOrderUpsertOne) ClearRefundReason() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundReason() + }) +} + +// SetRefundAt sets the "refund_at" field. +func (u *PaymentOrderUpsertOne) SetRefundAt(v time.Time) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundAt(v) + }) +} + +// UpdateRefundAt sets the "refund_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateRefundAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundAt() + }) +} + +// ClearRefundAt clears the value of the "refund_at" field. +func (u *PaymentOrderUpsertOne) ClearRefundAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundAt() + }) +} + +// SetForceRefund sets the "force_refund" field. +func (u *PaymentOrderUpsertOne) SetForceRefund(v bool) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetForceRefund(v) + }) +} + +// UpdateForceRefund sets the "force_refund" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateForceRefund() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateForceRefund() + }) +} + +// SetRefundRequestedAt sets the "refund_requested_at" field. +func (u *PaymentOrderUpsertOne) SetRefundRequestedAt(v time.Time) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundRequestedAt(v) + }) +} + +// UpdateRefundRequestedAt sets the "refund_requested_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateRefundRequestedAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundRequestedAt() + }) +} + +// ClearRefundRequestedAt clears the value of the "refund_requested_at" field. +func (u *PaymentOrderUpsertOne) ClearRefundRequestedAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundRequestedAt() + }) +} + +// SetRefundRequestReason sets the "refund_request_reason" field. +func (u *PaymentOrderUpsertOne) SetRefundRequestReason(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundRequestReason(v) + }) +} + +// UpdateRefundRequestReason sets the "refund_request_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateRefundRequestReason() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundRequestReason() + }) +} + +// ClearRefundRequestReason clears the value of the "refund_request_reason" field. +func (u *PaymentOrderUpsertOne) ClearRefundRequestReason() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundRequestReason() + }) +} + +// SetRefundRequestedBy sets the "refund_requested_by" field. +func (u *PaymentOrderUpsertOne) SetRefundRequestedBy(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundRequestedBy(v) + }) +} + +// UpdateRefundRequestedBy sets the "refund_requested_by" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateRefundRequestedBy() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundRequestedBy() + }) +} + +// ClearRefundRequestedBy clears the value of the "refund_requested_by" field. +func (u *PaymentOrderUpsertOne) ClearRefundRequestedBy() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundRequestedBy() + }) +} + +// SetExpiresAt sets the "expires_at" field. +func (u *PaymentOrderUpsertOne) SetExpiresAt(v time.Time) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetExpiresAt(v) + }) +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateExpiresAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateExpiresAt() + }) +} + +// SetPaidAt sets the "paid_at" field. +func (u *PaymentOrderUpsertOne) SetPaidAt(v time.Time) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPaidAt(v) + }) +} + +// UpdatePaidAt sets the "paid_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdatePaidAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePaidAt() + }) +} + +// ClearPaidAt clears the value of the "paid_at" field. +func (u *PaymentOrderUpsertOne) ClearPaidAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearPaidAt() + }) +} + +// SetCompletedAt sets the "completed_at" field. +func (u *PaymentOrderUpsertOne) SetCompletedAt(v time.Time) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetCompletedAt(v) + }) +} + +// UpdateCompletedAt sets the "completed_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateCompletedAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateCompletedAt() + }) +} + +// ClearCompletedAt clears the value of the "completed_at" field. +func (u *PaymentOrderUpsertOne) ClearCompletedAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearCompletedAt() + }) +} + +// SetFailedAt sets the "failed_at" field. +func (u *PaymentOrderUpsertOne) SetFailedAt(v time.Time) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetFailedAt(v) + }) +} + +// UpdateFailedAt sets the "failed_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateFailedAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateFailedAt() + }) +} + +// ClearFailedAt clears the value of the "failed_at" field. +func (u *PaymentOrderUpsertOne) ClearFailedAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearFailedAt() + }) +} + +// SetFailedReason sets the "failed_reason" field. +func (u *PaymentOrderUpsertOne) SetFailedReason(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetFailedReason(v) + }) +} + +// UpdateFailedReason sets the "failed_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateFailedReason() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateFailedReason() + }) +} + +// ClearFailedReason clears the value of the "failed_reason" field. +func (u *PaymentOrderUpsertOne) ClearFailedReason() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearFailedReason() + }) +} + +// SetClientIP sets the "client_ip" field. +func (u *PaymentOrderUpsertOne) SetClientIP(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetClientIP(v) + }) +} + +// UpdateClientIP sets the "client_ip" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateClientIP() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateClientIP() + }) +} + +// SetSrcHost sets the "src_host" field. +func (u *PaymentOrderUpsertOne) SetSrcHost(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetSrcHost(v) + }) +} + +// UpdateSrcHost sets the "src_host" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateSrcHost() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateSrcHost() + }) +} + +// SetSrcURL sets the "src_url" field. +func (u *PaymentOrderUpsertOne) SetSrcURL(v string) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetSrcURL(v) + }) +} + +// UpdateSrcURL sets the "src_url" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateSrcURL() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateSrcURL() + }) +} + +// ClearSrcURL clears the value of the "src_url" field. +func (u *PaymentOrderUpsertOne) ClearSrcURL() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearSrcURL() + }) +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *PaymentOrderUpsertOne) SetUpdatedAt(v time.Time) *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertOne) UpdateUpdatedAt() *PaymentOrderUpsertOne { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUpdatedAt() + }) +} + +// Exec executes the query. +func (u *PaymentOrderUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for PaymentOrderCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *PaymentOrderUpsertOne) 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 *PaymentOrderUpsertOne) 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 *PaymentOrderUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// PaymentOrderCreateBulk is the builder for creating many PaymentOrder entities in bulk. +type PaymentOrderCreateBulk struct { + config + err error + builders []*PaymentOrderCreate + conflict []sql.ConflictOption +} + +// Save creates the PaymentOrder entities in the database. +func (_c *PaymentOrderCreateBulk) Save(ctx context.Context) ([]*PaymentOrder, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*PaymentOrder, 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.(*PaymentOrderMutation) + 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 *PaymentOrderCreateBulk) SaveX(ctx context.Context) []*PaymentOrder { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *PaymentOrderCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *PaymentOrderCreateBulk) 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.PaymentOrder.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.PaymentOrderUpsert) { +// SetUserID(v+v). +// }). +// Exec(ctx) +func (_c *PaymentOrderCreateBulk) OnConflict(opts ...sql.ConflictOption) *PaymentOrderUpsertBulk { + _c.conflict = opts + return &PaymentOrderUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.PaymentOrder.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *PaymentOrderCreateBulk) OnConflictColumns(columns ...string) *PaymentOrderUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &PaymentOrderUpsertBulk{ + create: _c, + } +} + +// PaymentOrderUpsertBulk is the builder for "upsert"-ing +// a bulk of PaymentOrder nodes. +type PaymentOrderUpsertBulk struct { + create *PaymentOrderCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.PaymentOrder.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *PaymentOrderUpsertBulk) UpdateNewValues() *PaymentOrderUpsertBulk { + 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(paymentorder.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.PaymentOrder.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *PaymentOrderUpsertBulk) Ignore() *PaymentOrderUpsertBulk { + 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 *PaymentOrderUpsertBulk) DoNothing() *PaymentOrderUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the PaymentOrderCreateBulk.OnConflict +// documentation for more info. +func (u *PaymentOrderUpsertBulk) Update(set func(*PaymentOrderUpsert)) *PaymentOrderUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&PaymentOrderUpsert{UpdateSet: update}) + })) + return u +} + +// SetUserID sets the "user_id" field. +func (u *PaymentOrderUpsertBulk) SetUserID(v int64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUserID(v) + }) +} + +// UpdateUserID sets the "user_id" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateUserID() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUserID() + }) +} + +// SetUserEmail sets the "user_email" field. +func (u *PaymentOrderUpsertBulk) SetUserEmail(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUserEmail(v) + }) +} + +// UpdateUserEmail sets the "user_email" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateUserEmail() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUserEmail() + }) +} + +// SetUserName sets the "user_name" field. +func (u *PaymentOrderUpsertBulk) SetUserName(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUserName(v) + }) +} + +// UpdateUserName sets the "user_name" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateUserName() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUserName() + }) +} + +// SetUserNotes sets the "user_notes" field. +func (u *PaymentOrderUpsertBulk) SetUserNotes(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUserNotes(v) + }) +} + +// UpdateUserNotes sets the "user_notes" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateUserNotes() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUserNotes() + }) +} + +// ClearUserNotes clears the value of the "user_notes" field. +func (u *PaymentOrderUpsertBulk) ClearUserNotes() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearUserNotes() + }) +} + +// SetAmount sets the "amount" field. +func (u *PaymentOrderUpsertBulk) SetAmount(v float64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetAmount(v) + }) +} + +// AddAmount adds v to the "amount" field. +func (u *PaymentOrderUpsertBulk) AddAmount(v float64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddAmount(v) + }) +} + +// UpdateAmount sets the "amount" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateAmount() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateAmount() + }) +} + +// SetPayAmount sets the "pay_amount" field. +func (u *PaymentOrderUpsertBulk) SetPayAmount(v float64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPayAmount(v) + }) +} + +// AddPayAmount adds v to the "pay_amount" field. +func (u *PaymentOrderUpsertBulk) AddPayAmount(v float64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddPayAmount(v) + }) +} + +// UpdatePayAmount sets the "pay_amount" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdatePayAmount() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePayAmount() + }) +} + +// SetFeeRate sets the "fee_rate" field. +func (u *PaymentOrderUpsertBulk) SetFeeRate(v float64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetFeeRate(v) + }) +} + +// AddFeeRate adds v to the "fee_rate" field. +func (u *PaymentOrderUpsertBulk) AddFeeRate(v float64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddFeeRate(v) + }) +} + +// UpdateFeeRate sets the "fee_rate" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateFeeRate() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateFeeRate() + }) +} + +// SetRechargeCode sets the "recharge_code" field. +func (u *PaymentOrderUpsertBulk) SetRechargeCode(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRechargeCode(v) + }) +} + +// UpdateRechargeCode sets the "recharge_code" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateRechargeCode() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRechargeCode() + }) +} + +// SetOutTradeNo sets the "out_trade_no" field. +func (u *PaymentOrderUpsertBulk) SetOutTradeNo(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetOutTradeNo(v) + }) +} + +// UpdateOutTradeNo sets the "out_trade_no" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateOutTradeNo() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateOutTradeNo() + }) +} + +// SetPaymentType sets the "payment_type" field. +func (u *PaymentOrderUpsertBulk) SetPaymentType(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPaymentType(v) + }) +} + +// UpdatePaymentType sets the "payment_type" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdatePaymentType() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePaymentType() + }) +} + +// SetPaymentTradeNo sets the "payment_trade_no" field. +func (u *PaymentOrderUpsertBulk) SetPaymentTradeNo(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPaymentTradeNo(v) + }) +} + +// UpdatePaymentTradeNo sets the "payment_trade_no" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdatePaymentTradeNo() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePaymentTradeNo() + }) +} + +// SetPayURL sets the "pay_url" field. +func (u *PaymentOrderUpsertBulk) SetPayURL(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPayURL(v) + }) +} + +// UpdatePayURL sets the "pay_url" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdatePayURL() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePayURL() + }) +} + +// ClearPayURL clears the value of the "pay_url" field. +func (u *PaymentOrderUpsertBulk) ClearPayURL() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearPayURL() + }) +} + +// SetQrCode sets the "qr_code" field. +func (u *PaymentOrderUpsertBulk) SetQrCode(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetQrCode(v) + }) +} + +// UpdateQrCode sets the "qr_code" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateQrCode() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateQrCode() + }) +} + +// ClearQrCode clears the value of the "qr_code" field. +func (u *PaymentOrderUpsertBulk) ClearQrCode() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearQrCode() + }) +} + +// SetQrCodeImg sets the "qr_code_img" field. +func (u *PaymentOrderUpsertBulk) SetQrCodeImg(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetQrCodeImg(v) + }) +} + +// UpdateQrCodeImg sets the "qr_code_img" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateQrCodeImg() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateQrCodeImg() + }) +} + +// ClearQrCodeImg clears the value of the "qr_code_img" field. +func (u *PaymentOrderUpsertBulk) ClearQrCodeImg() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearQrCodeImg() + }) +} + +// SetOrderType sets the "order_type" field. +func (u *PaymentOrderUpsertBulk) SetOrderType(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetOrderType(v) + }) +} + +// UpdateOrderType sets the "order_type" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateOrderType() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateOrderType() + }) +} + +// SetPlanID sets the "plan_id" field. +func (u *PaymentOrderUpsertBulk) SetPlanID(v int64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPlanID(v) + }) +} + +// AddPlanID adds v to the "plan_id" field. +func (u *PaymentOrderUpsertBulk) AddPlanID(v int64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddPlanID(v) + }) +} + +// UpdatePlanID sets the "plan_id" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdatePlanID() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePlanID() + }) +} + +// ClearPlanID clears the value of the "plan_id" field. +func (u *PaymentOrderUpsertBulk) ClearPlanID() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearPlanID() + }) +} + +// SetSubscriptionGroupID sets the "subscription_group_id" field. +func (u *PaymentOrderUpsertBulk) SetSubscriptionGroupID(v int64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetSubscriptionGroupID(v) + }) +} + +// AddSubscriptionGroupID adds v to the "subscription_group_id" field. +func (u *PaymentOrderUpsertBulk) AddSubscriptionGroupID(v int64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddSubscriptionGroupID(v) + }) +} + +// UpdateSubscriptionGroupID sets the "subscription_group_id" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateSubscriptionGroupID() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateSubscriptionGroupID() + }) +} + +// ClearSubscriptionGroupID clears the value of the "subscription_group_id" field. +func (u *PaymentOrderUpsertBulk) ClearSubscriptionGroupID() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearSubscriptionGroupID() + }) +} + +// SetSubscriptionDays sets the "subscription_days" field. +func (u *PaymentOrderUpsertBulk) SetSubscriptionDays(v int) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetSubscriptionDays(v) + }) +} + +// AddSubscriptionDays adds v to the "subscription_days" field. +func (u *PaymentOrderUpsertBulk) AddSubscriptionDays(v int) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddSubscriptionDays(v) + }) +} + +// UpdateSubscriptionDays sets the "subscription_days" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateSubscriptionDays() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateSubscriptionDays() + }) +} + +// ClearSubscriptionDays clears the value of the "subscription_days" field. +func (u *PaymentOrderUpsertBulk) ClearSubscriptionDays() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearSubscriptionDays() + }) +} + +// SetProviderInstanceID sets the "provider_instance_id" field. +func (u *PaymentOrderUpsertBulk) SetProviderInstanceID(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetProviderInstanceID(v) + }) +} + +// UpdateProviderInstanceID sets the "provider_instance_id" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateProviderInstanceID() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateProviderInstanceID() + }) +} + +// ClearProviderInstanceID clears the value of the "provider_instance_id" field. +func (u *PaymentOrderUpsertBulk) ClearProviderInstanceID() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearProviderInstanceID() + }) +} + +// SetStatus sets the "status" field. +func (u *PaymentOrderUpsertBulk) SetStatus(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetStatus(v) + }) +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateStatus() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateStatus() + }) +} + +// SetRefundAmount sets the "refund_amount" field. +func (u *PaymentOrderUpsertBulk) SetRefundAmount(v float64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundAmount(v) + }) +} + +// AddRefundAmount adds v to the "refund_amount" field. +func (u *PaymentOrderUpsertBulk) AddRefundAmount(v float64) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.AddRefundAmount(v) + }) +} + +// UpdateRefundAmount sets the "refund_amount" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateRefundAmount() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundAmount() + }) +} + +// SetRefundReason sets the "refund_reason" field. +func (u *PaymentOrderUpsertBulk) SetRefundReason(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundReason(v) + }) +} + +// UpdateRefundReason sets the "refund_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateRefundReason() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundReason() + }) +} + +// ClearRefundReason clears the value of the "refund_reason" field. +func (u *PaymentOrderUpsertBulk) ClearRefundReason() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundReason() + }) +} + +// SetRefundAt sets the "refund_at" field. +func (u *PaymentOrderUpsertBulk) SetRefundAt(v time.Time) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundAt(v) + }) +} + +// UpdateRefundAt sets the "refund_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateRefundAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundAt() + }) +} + +// ClearRefundAt clears the value of the "refund_at" field. +func (u *PaymentOrderUpsertBulk) ClearRefundAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundAt() + }) +} + +// SetForceRefund sets the "force_refund" field. +func (u *PaymentOrderUpsertBulk) SetForceRefund(v bool) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetForceRefund(v) + }) +} + +// UpdateForceRefund sets the "force_refund" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateForceRefund() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateForceRefund() + }) +} + +// SetRefundRequestedAt sets the "refund_requested_at" field. +func (u *PaymentOrderUpsertBulk) SetRefundRequestedAt(v time.Time) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundRequestedAt(v) + }) +} + +// UpdateRefundRequestedAt sets the "refund_requested_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateRefundRequestedAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundRequestedAt() + }) +} + +// ClearRefundRequestedAt clears the value of the "refund_requested_at" field. +func (u *PaymentOrderUpsertBulk) ClearRefundRequestedAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundRequestedAt() + }) +} + +// SetRefundRequestReason sets the "refund_request_reason" field. +func (u *PaymentOrderUpsertBulk) SetRefundRequestReason(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundRequestReason(v) + }) +} + +// UpdateRefundRequestReason sets the "refund_request_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateRefundRequestReason() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundRequestReason() + }) +} + +// ClearRefundRequestReason clears the value of the "refund_request_reason" field. +func (u *PaymentOrderUpsertBulk) ClearRefundRequestReason() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundRequestReason() + }) +} + +// SetRefundRequestedBy sets the "refund_requested_by" field. +func (u *PaymentOrderUpsertBulk) SetRefundRequestedBy(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetRefundRequestedBy(v) + }) +} + +// UpdateRefundRequestedBy sets the "refund_requested_by" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateRefundRequestedBy() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateRefundRequestedBy() + }) +} + +// ClearRefundRequestedBy clears the value of the "refund_requested_by" field. +func (u *PaymentOrderUpsertBulk) ClearRefundRequestedBy() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearRefundRequestedBy() + }) +} + +// SetExpiresAt sets the "expires_at" field. +func (u *PaymentOrderUpsertBulk) SetExpiresAt(v time.Time) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetExpiresAt(v) + }) +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateExpiresAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateExpiresAt() + }) +} + +// SetPaidAt sets the "paid_at" field. +func (u *PaymentOrderUpsertBulk) SetPaidAt(v time.Time) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetPaidAt(v) + }) +} + +// UpdatePaidAt sets the "paid_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdatePaidAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdatePaidAt() + }) +} + +// ClearPaidAt clears the value of the "paid_at" field. +func (u *PaymentOrderUpsertBulk) ClearPaidAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearPaidAt() + }) +} + +// SetCompletedAt sets the "completed_at" field. +func (u *PaymentOrderUpsertBulk) SetCompletedAt(v time.Time) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetCompletedAt(v) + }) +} + +// UpdateCompletedAt sets the "completed_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateCompletedAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateCompletedAt() + }) +} + +// ClearCompletedAt clears the value of the "completed_at" field. +func (u *PaymentOrderUpsertBulk) ClearCompletedAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearCompletedAt() + }) +} + +// SetFailedAt sets the "failed_at" field. +func (u *PaymentOrderUpsertBulk) SetFailedAt(v time.Time) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetFailedAt(v) + }) +} + +// UpdateFailedAt sets the "failed_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateFailedAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateFailedAt() + }) +} + +// ClearFailedAt clears the value of the "failed_at" field. +func (u *PaymentOrderUpsertBulk) ClearFailedAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearFailedAt() + }) +} + +// SetFailedReason sets the "failed_reason" field. +func (u *PaymentOrderUpsertBulk) SetFailedReason(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetFailedReason(v) + }) +} + +// UpdateFailedReason sets the "failed_reason" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateFailedReason() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateFailedReason() + }) +} + +// ClearFailedReason clears the value of the "failed_reason" field. +func (u *PaymentOrderUpsertBulk) ClearFailedReason() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearFailedReason() + }) +} + +// SetClientIP sets the "client_ip" field. +func (u *PaymentOrderUpsertBulk) SetClientIP(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetClientIP(v) + }) +} + +// UpdateClientIP sets the "client_ip" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateClientIP() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateClientIP() + }) +} + +// SetSrcHost sets the "src_host" field. +func (u *PaymentOrderUpsertBulk) SetSrcHost(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetSrcHost(v) + }) +} + +// UpdateSrcHost sets the "src_host" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateSrcHost() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateSrcHost() + }) +} + +// SetSrcURL sets the "src_url" field. +func (u *PaymentOrderUpsertBulk) SetSrcURL(v string) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetSrcURL(v) + }) +} + +// UpdateSrcURL sets the "src_url" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateSrcURL() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateSrcURL() + }) +} + +// ClearSrcURL clears the value of the "src_url" field. +func (u *PaymentOrderUpsertBulk) ClearSrcURL() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.ClearSrcURL() + }) +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *PaymentOrderUpsertBulk) SetUpdatedAt(v time.Time) *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *PaymentOrderUpsertBulk) UpdateUpdatedAt() *PaymentOrderUpsertBulk { + return u.Update(func(s *PaymentOrderUpsert) { + s.UpdateUpdatedAt() + }) +} + +// Exec executes the query. +func (u *PaymentOrderUpsertBulk) 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 PaymentOrderCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for PaymentOrderCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *PaymentOrderUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/paymentorder_delete.go b/backend/ent/paymentorder_delete.go new file mode 100644 index 00000000..a4bc1bdf --- /dev/null +++ b/backend/ent/paymentorder_delete.go @@ -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) + } +} diff --git a/backend/ent/paymentorder_query.go b/backend/ent/paymentorder_query.go new file mode 100644 index 00000000..92fd74a7 --- /dev/null +++ b/backend/ent/paymentorder_query.go @@ -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) +} diff --git a/backend/ent/paymentorder_update.go b/backend/ent/paymentorder_update.go new file mode 100644 index 00000000..5978fc29 --- /dev/null +++ b/backend/ent/paymentorder_update.go @@ -0,0 +1,2083 @@ +// 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/paymentorder" + "github.com/Wei-Shaw/sub2api/ent/predicate" + "github.com/Wei-Shaw/sub2api/ent/user" +) + +// PaymentOrderUpdate is the builder for updating PaymentOrder entities. +type PaymentOrderUpdate struct { + config + hooks []Hook + mutation *PaymentOrderMutation +} + +// Where appends a list predicates to the PaymentOrderUpdate builder. +func (_u *PaymentOrderUpdate) Where(ps ...predicate.PaymentOrder) *PaymentOrderUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetUserID sets the "user_id" field. +func (_u *PaymentOrderUpdate) SetUserID(v int64) *PaymentOrderUpdate { + _u.mutation.SetUserID(v) + return _u +} + +// SetNillableUserID sets the "user_id" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableUserID(v *int64) *PaymentOrderUpdate { + if v != nil { + _u.SetUserID(*v) + } + return _u +} + +// SetUserEmail sets the "user_email" field. +func (_u *PaymentOrderUpdate) SetUserEmail(v string) *PaymentOrderUpdate { + _u.mutation.SetUserEmail(v) + return _u +} + +// SetNillableUserEmail sets the "user_email" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableUserEmail(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetUserEmail(*v) + } + return _u +} + +// SetUserName sets the "user_name" field. +func (_u *PaymentOrderUpdate) SetUserName(v string) *PaymentOrderUpdate { + _u.mutation.SetUserName(v) + return _u +} + +// SetNillableUserName sets the "user_name" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableUserName(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetUserName(*v) + } + return _u +} + +// SetUserNotes sets the "user_notes" field. +func (_u *PaymentOrderUpdate) SetUserNotes(v string) *PaymentOrderUpdate { + _u.mutation.SetUserNotes(v) + return _u +} + +// SetNillableUserNotes sets the "user_notes" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableUserNotes(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetUserNotes(*v) + } + return _u +} + +// ClearUserNotes clears the value of the "user_notes" field. +func (_u *PaymentOrderUpdate) ClearUserNotes() *PaymentOrderUpdate { + _u.mutation.ClearUserNotes() + return _u +} + +// SetAmount sets the "amount" field. +func (_u *PaymentOrderUpdate) SetAmount(v float64) *PaymentOrderUpdate { + _u.mutation.ResetAmount() + _u.mutation.SetAmount(v) + return _u +} + +// SetNillableAmount sets the "amount" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableAmount(v *float64) *PaymentOrderUpdate { + if v != nil { + _u.SetAmount(*v) + } + return _u +} + +// AddAmount adds value to the "amount" field. +func (_u *PaymentOrderUpdate) AddAmount(v float64) *PaymentOrderUpdate { + _u.mutation.AddAmount(v) + return _u +} + +// SetPayAmount sets the "pay_amount" field. +func (_u *PaymentOrderUpdate) SetPayAmount(v float64) *PaymentOrderUpdate { + _u.mutation.ResetPayAmount() + _u.mutation.SetPayAmount(v) + return _u +} + +// SetNillablePayAmount sets the "pay_amount" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillablePayAmount(v *float64) *PaymentOrderUpdate { + if v != nil { + _u.SetPayAmount(*v) + } + return _u +} + +// AddPayAmount adds value to the "pay_amount" field. +func (_u *PaymentOrderUpdate) AddPayAmount(v float64) *PaymentOrderUpdate { + _u.mutation.AddPayAmount(v) + return _u +} + +// SetFeeRate sets the "fee_rate" field. +func (_u *PaymentOrderUpdate) SetFeeRate(v float64) *PaymentOrderUpdate { + _u.mutation.ResetFeeRate() + _u.mutation.SetFeeRate(v) + return _u +} + +// SetNillableFeeRate sets the "fee_rate" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableFeeRate(v *float64) *PaymentOrderUpdate { + if v != nil { + _u.SetFeeRate(*v) + } + return _u +} + +// AddFeeRate adds value to the "fee_rate" field. +func (_u *PaymentOrderUpdate) AddFeeRate(v float64) *PaymentOrderUpdate { + _u.mutation.AddFeeRate(v) + return _u +} + +// SetRechargeCode sets the "recharge_code" field. +func (_u *PaymentOrderUpdate) SetRechargeCode(v string) *PaymentOrderUpdate { + _u.mutation.SetRechargeCode(v) + return _u +} + +// SetNillableRechargeCode sets the "recharge_code" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableRechargeCode(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetRechargeCode(*v) + } + return _u +} + +// SetOutTradeNo sets the "out_trade_no" field. +func (_u *PaymentOrderUpdate) SetOutTradeNo(v string) *PaymentOrderUpdate { + _u.mutation.SetOutTradeNo(v) + return _u +} + +// SetNillableOutTradeNo sets the "out_trade_no" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableOutTradeNo(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetOutTradeNo(*v) + } + return _u +} + +// SetPaymentType sets the "payment_type" field. +func (_u *PaymentOrderUpdate) SetPaymentType(v string) *PaymentOrderUpdate { + _u.mutation.SetPaymentType(v) + return _u +} + +// SetNillablePaymentType sets the "payment_type" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillablePaymentType(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetPaymentType(*v) + } + return _u +} + +// SetPaymentTradeNo sets the "payment_trade_no" field. +func (_u *PaymentOrderUpdate) SetPaymentTradeNo(v string) *PaymentOrderUpdate { + _u.mutation.SetPaymentTradeNo(v) + return _u +} + +// SetNillablePaymentTradeNo sets the "payment_trade_no" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillablePaymentTradeNo(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetPaymentTradeNo(*v) + } + return _u +} + +// SetPayURL sets the "pay_url" field. +func (_u *PaymentOrderUpdate) SetPayURL(v string) *PaymentOrderUpdate { + _u.mutation.SetPayURL(v) + return _u +} + +// SetNillablePayURL sets the "pay_url" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillablePayURL(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetPayURL(*v) + } + return _u +} + +// ClearPayURL clears the value of the "pay_url" field. +func (_u *PaymentOrderUpdate) ClearPayURL() *PaymentOrderUpdate { + _u.mutation.ClearPayURL() + return _u +} + +// SetQrCode sets the "qr_code" field. +func (_u *PaymentOrderUpdate) SetQrCode(v string) *PaymentOrderUpdate { + _u.mutation.SetQrCode(v) + return _u +} + +// SetNillableQrCode sets the "qr_code" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableQrCode(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetQrCode(*v) + } + return _u +} + +// ClearQrCode clears the value of the "qr_code" field. +func (_u *PaymentOrderUpdate) ClearQrCode() *PaymentOrderUpdate { + _u.mutation.ClearQrCode() + return _u +} + +// SetQrCodeImg sets the "qr_code_img" field. +func (_u *PaymentOrderUpdate) SetQrCodeImg(v string) *PaymentOrderUpdate { + _u.mutation.SetQrCodeImg(v) + return _u +} + +// SetNillableQrCodeImg sets the "qr_code_img" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableQrCodeImg(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetQrCodeImg(*v) + } + return _u +} + +// ClearQrCodeImg clears the value of the "qr_code_img" field. +func (_u *PaymentOrderUpdate) ClearQrCodeImg() *PaymentOrderUpdate { + _u.mutation.ClearQrCodeImg() + return _u +} + +// SetOrderType sets the "order_type" field. +func (_u *PaymentOrderUpdate) SetOrderType(v string) *PaymentOrderUpdate { + _u.mutation.SetOrderType(v) + return _u +} + +// SetNillableOrderType sets the "order_type" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableOrderType(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetOrderType(*v) + } + return _u +} + +// SetPlanID sets the "plan_id" field. +func (_u *PaymentOrderUpdate) SetPlanID(v int64) *PaymentOrderUpdate { + _u.mutation.ResetPlanID() + _u.mutation.SetPlanID(v) + return _u +} + +// SetNillablePlanID sets the "plan_id" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillablePlanID(v *int64) *PaymentOrderUpdate { + if v != nil { + _u.SetPlanID(*v) + } + return _u +} + +// AddPlanID adds value to the "plan_id" field. +func (_u *PaymentOrderUpdate) AddPlanID(v int64) *PaymentOrderUpdate { + _u.mutation.AddPlanID(v) + return _u +} + +// ClearPlanID clears the value of the "plan_id" field. +func (_u *PaymentOrderUpdate) ClearPlanID() *PaymentOrderUpdate { + _u.mutation.ClearPlanID() + return _u +} + +// SetSubscriptionGroupID sets the "subscription_group_id" field. +func (_u *PaymentOrderUpdate) SetSubscriptionGroupID(v int64) *PaymentOrderUpdate { + _u.mutation.ResetSubscriptionGroupID() + _u.mutation.SetSubscriptionGroupID(v) + return _u +} + +// SetNillableSubscriptionGroupID sets the "subscription_group_id" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableSubscriptionGroupID(v *int64) *PaymentOrderUpdate { + if v != nil { + _u.SetSubscriptionGroupID(*v) + } + return _u +} + +// AddSubscriptionGroupID adds value to the "subscription_group_id" field. +func (_u *PaymentOrderUpdate) AddSubscriptionGroupID(v int64) *PaymentOrderUpdate { + _u.mutation.AddSubscriptionGroupID(v) + return _u +} + +// ClearSubscriptionGroupID clears the value of the "subscription_group_id" field. +func (_u *PaymentOrderUpdate) ClearSubscriptionGroupID() *PaymentOrderUpdate { + _u.mutation.ClearSubscriptionGroupID() + return _u +} + +// SetSubscriptionDays sets the "subscription_days" field. +func (_u *PaymentOrderUpdate) SetSubscriptionDays(v int) *PaymentOrderUpdate { + _u.mutation.ResetSubscriptionDays() + _u.mutation.SetSubscriptionDays(v) + return _u +} + +// SetNillableSubscriptionDays sets the "subscription_days" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableSubscriptionDays(v *int) *PaymentOrderUpdate { + if v != nil { + _u.SetSubscriptionDays(*v) + } + return _u +} + +// AddSubscriptionDays adds value to the "subscription_days" field. +func (_u *PaymentOrderUpdate) AddSubscriptionDays(v int) *PaymentOrderUpdate { + _u.mutation.AddSubscriptionDays(v) + return _u +} + +// ClearSubscriptionDays clears the value of the "subscription_days" field. +func (_u *PaymentOrderUpdate) ClearSubscriptionDays() *PaymentOrderUpdate { + _u.mutation.ClearSubscriptionDays() + return _u +} + +// SetProviderInstanceID sets the "provider_instance_id" field. +func (_u *PaymentOrderUpdate) SetProviderInstanceID(v string) *PaymentOrderUpdate { + _u.mutation.SetProviderInstanceID(v) + return _u +} + +// SetNillableProviderInstanceID sets the "provider_instance_id" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableProviderInstanceID(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetProviderInstanceID(*v) + } + return _u +} + +// ClearProviderInstanceID clears the value of the "provider_instance_id" field. +func (_u *PaymentOrderUpdate) ClearProviderInstanceID() *PaymentOrderUpdate { + _u.mutation.ClearProviderInstanceID() + return _u +} + +// SetStatus sets the "status" field. +func (_u *PaymentOrderUpdate) SetStatus(v string) *PaymentOrderUpdate { + _u.mutation.SetStatus(v) + return _u +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableStatus(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetStatus(*v) + } + return _u +} + +// SetRefundAmount sets the "refund_amount" field. +func (_u *PaymentOrderUpdate) SetRefundAmount(v float64) *PaymentOrderUpdate { + _u.mutation.ResetRefundAmount() + _u.mutation.SetRefundAmount(v) + return _u +} + +// SetNillableRefundAmount sets the "refund_amount" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableRefundAmount(v *float64) *PaymentOrderUpdate { + if v != nil { + _u.SetRefundAmount(*v) + } + return _u +} + +// AddRefundAmount adds value to the "refund_amount" field. +func (_u *PaymentOrderUpdate) AddRefundAmount(v float64) *PaymentOrderUpdate { + _u.mutation.AddRefundAmount(v) + return _u +} + +// SetRefundReason sets the "refund_reason" field. +func (_u *PaymentOrderUpdate) SetRefundReason(v string) *PaymentOrderUpdate { + _u.mutation.SetRefundReason(v) + return _u +} + +// SetNillableRefundReason sets the "refund_reason" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableRefundReason(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetRefundReason(*v) + } + return _u +} + +// ClearRefundReason clears the value of the "refund_reason" field. +func (_u *PaymentOrderUpdate) ClearRefundReason() *PaymentOrderUpdate { + _u.mutation.ClearRefundReason() + return _u +} + +// SetRefundAt sets the "refund_at" field. +func (_u *PaymentOrderUpdate) SetRefundAt(v time.Time) *PaymentOrderUpdate { + _u.mutation.SetRefundAt(v) + return _u +} + +// SetNillableRefundAt sets the "refund_at" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableRefundAt(v *time.Time) *PaymentOrderUpdate { + if v != nil { + _u.SetRefundAt(*v) + } + return _u +} + +// ClearRefundAt clears the value of the "refund_at" field. +func (_u *PaymentOrderUpdate) ClearRefundAt() *PaymentOrderUpdate { + _u.mutation.ClearRefundAt() + return _u +} + +// SetForceRefund sets the "force_refund" field. +func (_u *PaymentOrderUpdate) SetForceRefund(v bool) *PaymentOrderUpdate { + _u.mutation.SetForceRefund(v) + return _u +} + +// SetNillableForceRefund sets the "force_refund" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableForceRefund(v *bool) *PaymentOrderUpdate { + if v != nil { + _u.SetForceRefund(*v) + } + return _u +} + +// SetRefundRequestedAt sets the "refund_requested_at" field. +func (_u *PaymentOrderUpdate) SetRefundRequestedAt(v time.Time) *PaymentOrderUpdate { + _u.mutation.SetRefundRequestedAt(v) + return _u +} + +// SetNillableRefundRequestedAt sets the "refund_requested_at" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableRefundRequestedAt(v *time.Time) *PaymentOrderUpdate { + if v != nil { + _u.SetRefundRequestedAt(*v) + } + return _u +} + +// ClearRefundRequestedAt clears the value of the "refund_requested_at" field. +func (_u *PaymentOrderUpdate) ClearRefundRequestedAt() *PaymentOrderUpdate { + _u.mutation.ClearRefundRequestedAt() + return _u +} + +// SetRefundRequestReason sets the "refund_request_reason" field. +func (_u *PaymentOrderUpdate) SetRefundRequestReason(v string) *PaymentOrderUpdate { + _u.mutation.SetRefundRequestReason(v) + return _u +} + +// SetNillableRefundRequestReason sets the "refund_request_reason" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableRefundRequestReason(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetRefundRequestReason(*v) + } + return _u +} + +// ClearRefundRequestReason clears the value of the "refund_request_reason" field. +func (_u *PaymentOrderUpdate) ClearRefundRequestReason() *PaymentOrderUpdate { + _u.mutation.ClearRefundRequestReason() + return _u +} + +// SetRefundRequestedBy sets the "refund_requested_by" field. +func (_u *PaymentOrderUpdate) SetRefundRequestedBy(v string) *PaymentOrderUpdate { + _u.mutation.SetRefundRequestedBy(v) + return _u +} + +// SetNillableRefundRequestedBy sets the "refund_requested_by" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableRefundRequestedBy(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetRefundRequestedBy(*v) + } + return _u +} + +// ClearRefundRequestedBy clears the value of the "refund_requested_by" field. +func (_u *PaymentOrderUpdate) ClearRefundRequestedBy() *PaymentOrderUpdate { + _u.mutation.ClearRefundRequestedBy() + return _u +} + +// SetExpiresAt sets the "expires_at" field. +func (_u *PaymentOrderUpdate) SetExpiresAt(v time.Time) *PaymentOrderUpdate { + _u.mutation.SetExpiresAt(v) + return _u +} + +// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableExpiresAt(v *time.Time) *PaymentOrderUpdate { + if v != nil { + _u.SetExpiresAt(*v) + } + return _u +} + +// SetPaidAt sets the "paid_at" field. +func (_u *PaymentOrderUpdate) SetPaidAt(v time.Time) *PaymentOrderUpdate { + _u.mutation.SetPaidAt(v) + return _u +} + +// SetNillablePaidAt sets the "paid_at" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillablePaidAt(v *time.Time) *PaymentOrderUpdate { + if v != nil { + _u.SetPaidAt(*v) + } + return _u +} + +// ClearPaidAt clears the value of the "paid_at" field. +func (_u *PaymentOrderUpdate) ClearPaidAt() *PaymentOrderUpdate { + _u.mutation.ClearPaidAt() + return _u +} + +// SetCompletedAt sets the "completed_at" field. +func (_u *PaymentOrderUpdate) SetCompletedAt(v time.Time) *PaymentOrderUpdate { + _u.mutation.SetCompletedAt(v) + return _u +} + +// SetNillableCompletedAt sets the "completed_at" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableCompletedAt(v *time.Time) *PaymentOrderUpdate { + if v != nil { + _u.SetCompletedAt(*v) + } + return _u +} + +// ClearCompletedAt clears the value of the "completed_at" field. +func (_u *PaymentOrderUpdate) ClearCompletedAt() *PaymentOrderUpdate { + _u.mutation.ClearCompletedAt() + return _u +} + +// SetFailedAt sets the "failed_at" field. +func (_u *PaymentOrderUpdate) SetFailedAt(v time.Time) *PaymentOrderUpdate { + _u.mutation.SetFailedAt(v) + return _u +} + +// SetNillableFailedAt sets the "failed_at" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableFailedAt(v *time.Time) *PaymentOrderUpdate { + if v != nil { + _u.SetFailedAt(*v) + } + return _u +} + +// ClearFailedAt clears the value of the "failed_at" field. +func (_u *PaymentOrderUpdate) ClearFailedAt() *PaymentOrderUpdate { + _u.mutation.ClearFailedAt() + return _u +} + +// SetFailedReason sets the "failed_reason" field. +func (_u *PaymentOrderUpdate) SetFailedReason(v string) *PaymentOrderUpdate { + _u.mutation.SetFailedReason(v) + return _u +} + +// SetNillableFailedReason sets the "failed_reason" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableFailedReason(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetFailedReason(*v) + } + return _u +} + +// ClearFailedReason clears the value of the "failed_reason" field. +func (_u *PaymentOrderUpdate) ClearFailedReason() *PaymentOrderUpdate { + _u.mutation.ClearFailedReason() + return _u +} + +// SetClientIP sets the "client_ip" field. +func (_u *PaymentOrderUpdate) SetClientIP(v string) *PaymentOrderUpdate { + _u.mutation.SetClientIP(v) + return _u +} + +// SetNillableClientIP sets the "client_ip" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableClientIP(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetClientIP(*v) + } + return _u +} + +// SetSrcHost sets the "src_host" field. +func (_u *PaymentOrderUpdate) SetSrcHost(v string) *PaymentOrderUpdate { + _u.mutation.SetSrcHost(v) + return _u +} + +// SetNillableSrcHost sets the "src_host" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableSrcHost(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetSrcHost(*v) + } + return _u +} + +// SetSrcURL sets the "src_url" field. +func (_u *PaymentOrderUpdate) SetSrcURL(v string) *PaymentOrderUpdate { + _u.mutation.SetSrcURL(v) + return _u +} + +// SetNillableSrcURL sets the "src_url" field if the given value is not nil. +func (_u *PaymentOrderUpdate) SetNillableSrcURL(v *string) *PaymentOrderUpdate { + if v != nil { + _u.SetSrcURL(*v) + } + return _u +} + +// ClearSrcURL clears the value of the "src_url" field. +func (_u *PaymentOrderUpdate) ClearSrcURL() *PaymentOrderUpdate { + _u.mutation.ClearSrcURL() + return _u +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *PaymentOrderUpdate) SetUpdatedAt(v time.Time) *PaymentOrderUpdate { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetUser sets the "user" edge to the User entity. +func (_u *PaymentOrderUpdate) SetUser(v *User) *PaymentOrderUpdate { + return _u.SetUserID(v.ID) +} + +// Mutation returns the PaymentOrderMutation object of the builder. +func (_u *PaymentOrderUpdate) Mutation() *PaymentOrderMutation { + return _u.mutation +} + +// ClearUser clears the "user" edge to the User entity. +func (_u *PaymentOrderUpdate) ClearUser() *PaymentOrderUpdate { + _u.mutation.ClearUser() + return _u +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *PaymentOrderUpdate) 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 *PaymentOrderUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *PaymentOrderUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *PaymentOrderUpdate) 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 *PaymentOrderUpdate) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := paymentorder.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *PaymentOrderUpdate) check() error { + if v, ok := _u.mutation.UserEmail(); ok { + if err := paymentorder.UserEmailValidator(v); err != nil { + return &ValidationError{Name: "user_email", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.user_email": %w`, err)} + } + } + if v, ok := _u.mutation.UserName(); ok { + if err := paymentorder.UserNameValidator(v); err != nil { + return &ValidationError{Name: "user_name", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.user_name": %w`, err)} + } + } + if v, ok := _u.mutation.RechargeCode(); ok { + if err := paymentorder.RechargeCodeValidator(v); err != nil { + return &ValidationError{Name: "recharge_code", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.recharge_code": %w`, err)} + } + } + if v, ok := _u.mutation.OutTradeNo(); ok { + if err := paymentorder.OutTradeNoValidator(v); err != nil { + return &ValidationError{Name: "out_trade_no", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.out_trade_no": %w`, err)} + } + } + if v, ok := _u.mutation.PaymentType(); ok { + if err := paymentorder.PaymentTypeValidator(v); err != nil { + return &ValidationError{Name: "payment_type", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.payment_type": %w`, err)} + } + } + if v, ok := _u.mutation.PaymentTradeNo(); ok { + if err := paymentorder.PaymentTradeNoValidator(v); err != nil { + return &ValidationError{Name: "payment_trade_no", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.payment_trade_no": %w`, err)} + } + } + if v, ok := _u.mutation.OrderType(); ok { + if err := paymentorder.OrderTypeValidator(v); err != nil { + return &ValidationError{Name: "order_type", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.order_type": %w`, err)} + } + } + if v, ok := _u.mutation.ProviderInstanceID(); ok { + if err := paymentorder.ProviderInstanceIDValidator(v); err != nil { + return &ValidationError{Name: "provider_instance_id", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.provider_instance_id": %w`, err)} + } + } + if v, ok := _u.mutation.Status(); ok { + if err := paymentorder.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.status": %w`, err)} + } + } + if v, ok := _u.mutation.RefundRequestedBy(); ok { + if err := paymentorder.RefundRequestedByValidator(v); err != nil { + return &ValidationError{Name: "refund_requested_by", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.refund_requested_by": %w`, err)} + } + } + if v, ok := _u.mutation.ClientIP(); ok { + if err := paymentorder.ClientIPValidator(v); err != nil { + return &ValidationError{Name: "client_ip", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.client_ip": %w`, err)} + } + } + if v, ok := _u.mutation.SrcHost(); ok { + if err := paymentorder.SrcHostValidator(v); err != nil { + return &ValidationError{Name: "src_host", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.src_host": %w`, err)} + } + } + if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "PaymentOrder.user"`) + } + return nil +} + +func (_u *PaymentOrderUpdate) sqlSave(ctx context.Context) (_node int, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(paymentorder.Table, paymentorder.Columns, sqlgraph.NewFieldSpec(paymentorder.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.UserEmail(); ok { + _spec.SetField(paymentorder.FieldUserEmail, field.TypeString, value) + } + if value, ok := _u.mutation.UserName(); ok { + _spec.SetField(paymentorder.FieldUserName, field.TypeString, value) + } + if value, ok := _u.mutation.UserNotes(); ok { + _spec.SetField(paymentorder.FieldUserNotes, field.TypeString, value) + } + if _u.mutation.UserNotesCleared() { + _spec.ClearField(paymentorder.FieldUserNotes, field.TypeString) + } + if value, ok := _u.mutation.Amount(); ok { + _spec.SetField(paymentorder.FieldAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedAmount(); ok { + _spec.AddField(paymentorder.FieldAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.PayAmount(); ok { + _spec.SetField(paymentorder.FieldPayAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedPayAmount(); ok { + _spec.AddField(paymentorder.FieldPayAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.FeeRate(); ok { + _spec.SetField(paymentorder.FieldFeeRate, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedFeeRate(); ok { + _spec.AddField(paymentorder.FieldFeeRate, field.TypeFloat64, value) + } + if value, ok := _u.mutation.RechargeCode(); ok { + _spec.SetField(paymentorder.FieldRechargeCode, field.TypeString, value) + } + if value, ok := _u.mutation.OutTradeNo(); ok { + _spec.SetField(paymentorder.FieldOutTradeNo, field.TypeString, value) + } + if value, ok := _u.mutation.PaymentType(); ok { + _spec.SetField(paymentorder.FieldPaymentType, field.TypeString, value) + } + if value, ok := _u.mutation.PaymentTradeNo(); ok { + _spec.SetField(paymentorder.FieldPaymentTradeNo, field.TypeString, value) + } + if value, ok := _u.mutation.PayURL(); ok { + _spec.SetField(paymentorder.FieldPayURL, field.TypeString, value) + } + if _u.mutation.PayURLCleared() { + _spec.ClearField(paymentorder.FieldPayURL, field.TypeString) + } + if value, ok := _u.mutation.QrCode(); ok { + _spec.SetField(paymentorder.FieldQrCode, field.TypeString, value) + } + if _u.mutation.QrCodeCleared() { + _spec.ClearField(paymentorder.FieldQrCode, field.TypeString) + } + if value, ok := _u.mutation.QrCodeImg(); ok { + _spec.SetField(paymentorder.FieldQrCodeImg, field.TypeString, value) + } + if _u.mutation.QrCodeImgCleared() { + _spec.ClearField(paymentorder.FieldQrCodeImg, field.TypeString) + } + if value, ok := _u.mutation.OrderType(); ok { + _spec.SetField(paymentorder.FieldOrderType, field.TypeString, value) + } + if value, ok := _u.mutation.PlanID(); ok { + _spec.SetField(paymentorder.FieldPlanID, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedPlanID(); ok { + _spec.AddField(paymentorder.FieldPlanID, field.TypeInt64, value) + } + if _u.mutation.PlanIDCleared() { + _spec.ClearField(paymentorder.FieldPlanID, field.TypeInt64) + } + if value, ok := _u.mutation.SubscriptionGroupID(); ok { + _spec.SetField(paymentorder.FieldSubscriptionGroupID, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedSubscriptionGroupID(); ok { + _spec.AddField(paymentorder.FieldSubscriptionGroupID, field.TypeInt64, value) + } + if _u.mutation.SubscriptionGroupIDCleared() { + _spec.ClearField(paymentorder.FieldSubscriptionGroupID, field.TypeInt64) + } + if value, ok := _u.mutation.SubscriptionDays(); ok { + _spec.SetField(paymentorder.FieldSubscriptionDays, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedSubscriptionDays(); ok { + _spec.AddField(paymentorder.FieldSubscriptionDays, field.TypeInt, value) + } + if _u.mutation.SubscriptionDaysCleared() { + _spec.ClearField(paymentorder.FieldSubscriptionDays, field.TypeInt) + } + if value, ok := _u.mutation.ProviderInstanceID(); ok { + _spec.SetField(paymentorder.FieldProviderInstanceID, field.TypeString, value) + } + if _u.mutation.ProviderInstanceIDCleared() { + _spec.ClearField(paymentorder.FieldProviderInstanceID, field.TypeString) + } + if value, ok := _u.mutation.Status(); ok { + _spec.SetField(paymentorder.FieldStatus, field.TypeString, value) + } + if value, ok := _u.mutation.RefundAmount(); ok { + _spec.SetField(paymentorder.FieldRefundAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedRefundAmount(); ok { + _spec.AddField(paymentorder.FieldRefundAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.RefundReason(); ok { + _spec.SetField(paymentorder.FieldRefundReason, field.TypeString, value) + } + if _u.mutation.RefundReasonCleared() { + _spec.ClearField(paymentorder.FieldRefundReason, field.TypeString) + } + if value, ok := _u.mutation.RefundAt(); ok { + _spec.SetField(paymentorder.FieldRefundAt, field.TypeTime, value) + } + if _u.mutation.RefundAtCleared() { + _spec.ClearField(paymentorder.FieldRefundAt, field.TypeTime) + } + if value, ok := _u.mutation.ForceRefund(); ok { + _spec.SetField(paymentorder.FieldForceRefund, field.TypeBool, value) + } + if value, ok := _u.mutation.RefundRequestedAt(); ok { + _spec.SetField(paymentorder.FieldRefundRequestedAt, field.TypeTime, value) + } + if _u.mutation.RefundRequestedAtCleared() { + _spec.ClearField(paymentorder.FieldRefundRequestedAt, field.TypeTime) + } + if value, ok := _u.mutation.RefundRequestReason(); ok { + _spec.SetField(paymentorder.FieldRefundRequestReason, field.TypeString, value) + } + if _u.mutation.RefundRequestReasonCleared() { + _spec.ClearField(paymentorder.FieldRefundRequestReason, field.TypeString) + } + if value, ok := _u.mutation.RefundRequestedBy(); ok { + _spec.SetField(paymentorder.FieldRefundRequestedBy, field.TypeString, value) + } + if _u.mutation.RefundRequestedByCleared() { + _spec.ClearField(paymentorder.FieldRefundRequestedBy, field.TypeString) + } + if value, ok := _u.mutation.ExpiresAt(); ok { + _spec.SetField(paymentorder.FieldExpiresAt, field.TypeTime, value) + } + if value, ok := _u.mutation.PaidAt(); ok { + _spec.SetField(paymentorder.FieldPaidAt, field.TypeTime, value) + } + if _u.mutation.PaidAtCleared() { + _spec.ClearField(paymentorder.FieldPaidAt, field.TypeTime) + } + if value, ok := _u.mutation.CompletedAt(); ok { + _spec.SetField(paymentorder.FieldCompletedAt, field.TypeTime, value) + } + if _u.mutation.CompletedAtCleared() { + _spec.ClearField(paymentorder.FieldCompletedAt, field.TypeTime) + } + if value, ok := _u.mutation.FailedAt(); ok { + _spec.SetField(paymentorder.FieldFailedAt, field.TypeTime, value) + } + if _u.mutation.FailedAtCleared() { + _spec.ClearField(paymentorder.FieldFailedAt, field.TypeTime) + } + if value, ok := _u.mutation.FailedReason(); ok { + _spec.SetField(paymentorder.FieldFailedReason, field.TypeString, value) + } + if _u.mutation.FailedReasonCleared() { + _spec.ClearField(paymentorder.FieldFailedReason, field.TypeString) + } + if value, ok := _u.mutation.ClientIP(); ok { + _spec.SetField(paymentorder.FieldClientIP, field.TypeString, value) + } + if value, ok := _u.mutation.SrcHost(); ok { + _spec.SetField(paymentorder.FieldSrcHost, field.TypeString, value) + } + if value, ok := _u.mutation.SrcURL(); ok { + _spec.SetField(paymentorder.FieldSrcURL, field.TypeString, value) + } + if _u.mutation.SrcURLCleared() { + _spec.ClearField(paymentorder.FieldSrcURL, field.TypeString) + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(paymentorder.FieldUpdatedAt, field.TypeTime, value) + } + if _u.mutation.UserCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: paymentorder.UserTable, + Columns: []string{paymentorder.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: paymentorder.UserTable, + Columns: []string{paymentorder.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.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{paymentorder.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// PaymentOrderUpdateOne is the builder for updating a single PaymentOrder entity. +type PaymentOrderUpdateOne struct { + config + fields []string + hooks []Hook + mutation *PaymentOrderMutation +} + +// SetUserID sets the "user_id" field. +func (_u *PaymentOrderUpdateOne) SetUserID(v int64) *PaymentOrderUpdateOne { + _u.mutation.SetUserID(v) + return _u +} + +// SetNillableUserID sets the "user_id" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableUserID(v *int64) *PaymentOrderUpdateOne { + if v != nil { + _u.SetUserID(*v) + } + return _u +} + +// SetUserEmail sets the "user_email" field. +func (_u *PaymentOrderUpdateOne) SetUserEmail(v string) *PaymentOrderUpdateOne { + _u.mutation.SetUserEmail(v) + return _u +} + +// SetNillableUserEmail sets the "user_email" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableUserEmail(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetUserEmail(*v) + } + return _u +} + +// SetUserName sets the "user_name" field. +func (_u *PaymentOrderUpdateOne) SetUserName(v string) *PaymentOrderUpdateOne { + _u.mutation.SetUserName(v) + return _u +} + +// SetNillableUserName sets the "user_name" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableUserName(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetUserName(*v) + } + return _u +} + +// SetUserNotes sets the "user_notes" field. +func (_u *PaymentOrderUpdateOne) SetUserNotes(v string) *PaymentOrderUpdateOne { + _u.mutation.SetUserNotes(v) + return _u +} + +// SetNillableUserNotes sets the "user_notes" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableUserNotes(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetUserNotes(*v) + } + return _u +} + +// ClearUserNotes clears the value of the "user_notes" field. +func (_u *PaymentOrderUpdateOne) ClearUserNotes() *PaymentOrderUpdateOne { + _u.mutation.ClearUserNotes() + return _u +} + +// SetAmount sets the "amount" field. +func (_u *PaymentOrderUpdateOne) SetAmount(v float64) *PaymentOrderUpdateOne { + _u.mutation.ResetAmount() + _u.mutation.SetAmount(v) + return _u +} + +// SetNillableAmount sets the "amount" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableAmount(v *float64) *PaymentOrderUpdateOne { + if v != nil { + _u.SetAmount(*v) + } + return _u +} + +// AddAmount adds value to the "amount" field. +func (_u *PaymentOrderUpdateOne) AddAmount(v float64) *PaymentOrderUpdateOne { + _u.mutation.AddAmount(v) + return _u +} + +// SetPayAmount sets the "pay_amount" field. +func (_u *PaymentOrderUpdateOne) SetPayAmount(v float64) *PaymentOrderUpdateOne { + _u.mutation.ResetPayAmount() + _u.mutation.SetPayAmount(v) + return _u +} + +// SetNillablePayAmount sets the "pay_amount" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillablePayAmount(v *float64) *PaymentOrderUpdateOne { + if v != nil { + _u.SetPayAmount(*v) + } + return _u +} + +// AddPayAmount adds value to the "pay_amount" field. +func (_u *PaymentOrderUpdateOne) AddPayAmount(v float64) *PaymentOrderUpdateOne { + _u.mutation.AddPayAmount(v) + return _u +} + +// SetFeeRate sets the "fee_rate" field. +func (_u *PaymentOrderUpdateOne) SetFeeRate(v float64) *PaymentOrderUpdateOne { + _u.mutation.ResetFeeRate() + _u.mutation.SetFeeRate(v) + return _u +} + +// SetNillableFeeRate sets the "fee_rate" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableFeeRate(v *float64) *PaymentOrderUpdateOne { + if v != nil { + _u.SetFeeRate(*v) + } + return _u +} + +// AddFeeRate adds value to the "fee_rate" field. +func (_u *PaymentOrderUpdateOne) AddFeeRate(v float64) *PaymentOrderUpdateOne { + _u.mutation.AddFeeRate(v) + return _u +} + +// SetRechargeCode sets the "recharge_code" field. +func (_u *PaymentOrderUpdateOne) SetRechargeCode(v string) *PaymentOrderUpdateOne { + _u.mutation.SetRechargeCode(v) + return _u +} + +// SetNillableRechargeCode sets the "recharge_code" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableRechargeCode(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetRechargeCode(*v) + } + return _u +} + +// SetOutTradeNo sets the "out_trade_no" field. +func (_u *PaymentOrderUpdateOne) SetOutTradeNo(v string) *PaymentOrderUpdateOne { + _u.mutation.SetOutTradeNo(v) + return _u +} + +// SetNillableOutTradeNo sets the "out_trade_no" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableOutTradeNo(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetOutTradeNo(*v) + } + return _u +} + +// SetPaymentType sets the "payment_type" field. +func (_u *PaymentOrderUpdateOne) SetPaymentType(v string) *PaymentOrderUpdateOne { + _u.mutation.SetPaymentType(v) + return _u +} + +// SetNillablePaymentType sets the "payment_type" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillablePaymentType(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetPaymentType(*v) + } + return _u +} + +// SetPaymentTradeNo sets the "payment_trade_no" field. +func (_u *PaymentOrderUpdateOne) SetPaymentTradeNo(v string) *PaymentOrderUpdateOne { + _u.mutation.SetPaymentTradeNo(v) + return _u +} + +// SetNillablePaymentTradeNo sets the "payment_trade_no" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillablePaymentTradeNo(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetPaymentTradeNo(*v) + } + return _u +} + +// SetPayURL sets the "pay_url" field. +func (_u *PaymentOrderUpdateOne) SetPayURL(v string) *PaymentOrderUpdateOne { + _u.mutation.SetPayURL(v) + return _u +} + +// SetNillablePayURL sets the "pay_url" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillablePayURL(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetPayURL(*v) + } + return _u +} + +// ClearPayURL clears the value of the "pay_url" field. +func (_u *PaymentOrderUpdateOne) ClearPayURL() *PaymentOrderUpdateOne { + _u.mutation.ClearPayURL() + return _u +} + +// SetQrCode sets the "qr_code" field. +func (_u *PaymentOrderUpdateOne) SetQrCode(v string) *PaymentOrderUpdateOne { + _u.mutation.SetQrCode(v) + return _u +} + +// SetNillableQrCode sets the "qr_code" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableQrCode(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetQrCode(*v) + } + return _u +} + +// ClearQrCode clears the value of the "qr_code" field. +func (_u *PaymentOrderUpdateOne) ClearQrCode() *PaymentOrderUpdateOne { + _u.mutation.ClearQrCode() + return _u +} + +// SetQrCodeImg sets the "qr_code_img" field. +func (_u *PaymentOrderUpdateOne) SetQrCodeImg(v string) *PaymentOrderUpdateOne { + _u.mutation.SetQrCodeImg(v) + return _u +} + +// SetNillableQrCodeImg sets the "qr_code_img" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableQrCodeImg(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetQrCodeImg(*v) + } + return _u +} + +// ClearQrCodeImg clears the value of the "qr_code_img" field. +func (_u *PaymentOrderUpdateOne) ClearQrCodeImg() *PaymentOrderUpdateOne { + _u.mutation.ClearQrCodeImg() + return _u +} + +// SetOrderType sets the "order_type" field. +func (_u *PaymentOrderUpdateOne) SetOrderType(v string) *PaymentOrderUpdateOne { + _u.mutation.SetOrderType(v) + return _u +} + +// SetNillableOrderType sets the "order_type" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableOrderType(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetOrderType(*v) + } + return _u +} + +// SetPlanID sets the "plan_id" field. +func (_u *PaymentOrderUpdateOne) SetPlanID(v int64) *PaymentOrderUpdateOne { + _u.mutation.ResetPlanID() + _u.mutation.SetPlanID(v) + return _u +} + +// SetNillablePlanID sets the "plan_id" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillablePlanID(v *int64) *PaymentOrderUpdateOne { + if v != nil { + _u.SetPlanID(*v) + } + return _u +} + +// AddPlanID adds value to the "plan_id" field. +func (_u *PaymentOrderUpdateOne) AddPlanID(v int64) *PaymentOrderUpdateOne { + _u.mutation.AddPlanID(v) + return _u +} + +// ClearPlanID clears the value of the "plan_id" field. +func (_u *PaymentOrderUpdateOne) ClearPlanID() *PaymentOrderUpdateOne { + _u.mutation.ClearPlanID() + return _u +} + +// SetSubscriptionGroupID sets the "subscription_group_id" field. +func (_u *PaymentOrderUpdateOne) SetSubscriptionGroupID(v int64) *PaymentOrderUpdateOne { + _u.mutation.ResetSubscriptionGroupID() + _u.mutation.SetSubscriptionGroupID(v) + return _u +} + +// SetNillableSubscriptionGroupID sets the "subscription_group_id" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableSubscriptionGroupID(v *int64) *PaymentOrderUpdateOne { + if v != nil { + _u.SetSubscriptionGroupID(*v) + } + return _u +} + +// AddSubscriptionGroupID adds value to the "subscription_group_id" field. +func (_u *PaymentOrderUpdateOne) AddSubscriptionGroupID(v int64) *PaymentOrderUpdateOne { + _u.mutation.AddSubscriptionGroupID(v) + return _u +} + +// ClearSubscriptionGroupID clears the value of the "subscription_group_id" field. +func (_u *PaymentOrderUpdateOne) ClearSubscriptionGroupID() *PaymentOrderUpdateOne { + _u.mutation.ClearSubscriptionGroupID() + return _u +} + +// SetSubscriptionDays sets the "subscription_days" field. +func (_u *PaymentOrderUpdateOne) SetSubscriptionDays(v int) *PaymentOrderUpdateOne { + _u.mutation.ResetSubscriptionDays() + _u.mutation.SetSubscriptionDays(v) + return _u +} + +// SetNillableSubscriptionDays sets the "subscription_days" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableSubscriptionDays(v *int) *PaymentOrderUpdateOne { + if v != nil { + _u.SetSubscriptionDays(*v) + } + return _u +} + +// AddSubscriptionDays adds value to the "subscription_days" field. +func (_u *PaymentOrderUpdateOne) AddSubscriptionDays(v int) *PaymentOrderUpdateOne { + _u.mutation.AddSubscriptionDays(v) + return _u +} + +// ClearSubscriptionDays clears the value of the "subscription_days" field. +func (_u *PaymentOrderUpdateOne) ClearSubscriptionDays() *PaymentOrderUpdateOne { + _u.mutation.ClearSubscriptionDays() + return _u +} + +// SetProviderInstanceID sets the "provider_instance_id" field. +func (_u *PaymentOrderUpdateOne) SetProviderInstanceID(v string) *PaymentOrderUpdateOne { + _u.mutation.SetProviderInstanceID(v) + return _u +} + +// SetNillableProviderInstanceID sets the "provider_instance_id" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableProviderInstanceID(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetProviderInstanceID(*v) + } + return _u +} + +// ClearProviderInstanceID clears the value of the "provider_instance_id" field. +func (_u *PaymentOrderUpdateOne) ClearProviderInstanceID() *PaymentOrderUpdateOne { + _u.mutation.ClearProviderInstanceID() + return _u +} + +// SetStatus sets the "status" field. +func (_u *PaymentOrderUpdateOne) SetStatus(v string) *PaymentOrderUpdateOne { + _u.mutation.SetStatus(v) + return _u +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableStatus(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetStatus(*v) + } + return _u +} + +// SetRefundAmount sets the "refund_amount" field. +func (_u *PaymentOrderUpdateOne) SetRefundAmount(v float64) *PaymentOrderUpdateOne { + _u.mutation.ResetRefundAmount() + _u.mutation.SetRefundAmount(v) + return _u +} + +// SetNillableRefundAmount sets the "refund_amount" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableRefundAmount(v *float64) *PaymentOrderUpdateOne { + if v != nil { + _u.SetRefundAmount(*v) + } + return _u +} + +// AddRefundAmount adds value to the "refund_amount" field. +func (_u *PaymentOrderUpdateOne) AddRefundAmount(v float64) *PaymentOrderUpdateOne { + _u.mutation.AddRefundAmount(v) + return _u +} + +// SetRefundReason sets the "refund_reason" field. +func (_u *PaymentOrderUpdateOne) SetRefundReason(v string) *PaymentOrderUpdateOne { + _u.mutation.SetRefundReason(v) + return _u +} + +// SetNillableRefundReason sets the "refund_reason" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableRefundReason(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetRefundReason(*v) + } + return _u +} + +// ClearRefundReason clears the value of the "refund_reason" field. +func (_u *PaymentOrderUpdateOne) ClearRefundReason() *PaymentOrderUpdateOne { + _u.mutation.ClearRefundReason() + return _u +} + +// SetRefundAt sets the "refund_at" field. +func (_u *PaymentOrderUpdateOne) SetRefundAt(v time.Time) *PaymentOrderUpdateOne { + _u.mutation.SetRefundAt(v) + return _u +} + +// SetNillableRefundAt sets the "refund_at" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableRefundAt(v *time.Time) *PaymentOrderUpdateOne { + if v != nil { + _u.SetRefundAt(*v) + } + return _u +} + +// ClearRefundAt clears the value of the "refund_at" field. +func (_u *PaymentOrderUpdateOne) ClearRefundAt() *PaymentOrderUpdateOne { + _u.mutation.ClearRefundAt() + return _u +} + +// SetForceRefund sets the "force_refund" field. +func (_u *PaymentOrderUpdateOne) SetForceRefund(v bool) *PaymentOrderUpdateOne { + _u.mutation.SetForceRefund(v) + return _u +} + +// SetNillableForceRefund sets the "force_refund" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableForceRefund(v *bool) *PaymentOrderUpdateOne { + if v != nil { + _u.SetForceRefund(*v) + } + return _u +} + +// SetRefundRequestedAt sets the "refund_requested_at" field. +func (_u *PaymentOrderUpdateOne) SetRefundRequestedAt(v time.Time) *PaymentOrderUpdateOne { + _u.mutation.SetRefundRequestedAt(v) + return _u +} + +// SetNillableRefundRequestedAt sets the "refund_requested_at" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableRefundRequestedAt(v *time.Time) *PaymentOrderUpdateOne { + if v != nil { + _u.SetRefundRequestedAt(*v) + } + return _u +} + +// ClearRefundRequestedAt clears the value of the "refund_requested_at" field. +func (_u *PaymentOrderUpdateOne) ClearRefundRequestedAt() *PaymentOrderUpdateOne { + _u.mutation.ClearRefundRequestedAt() + return _u +} + +// SetRefundRequestReason sets the "refund_request_reason" field. +func (_u *PaymentOrderUpdateOne) SetRefundRequestReason(v string) *PaymentOrderUpdateOne { + _u.mutation.SetRefundRequestReason(v) + return _u +} + +// SetNillableRefundRequestReason sets the "refund_request_reason" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableRefundRequestReason(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetRefundRequestReason(*v) + } + return _u +} + +// ClearRefundRequestReason clears the value of the "refund_request_reason" field. +func (_u *PaymentOrderUpdateOne) ClearRefundRequestReason() *PaymentOrderUpdateOne { + _u.mutation.ClearRefundRequestReason() + return _u +} + +// SetRefundRequestedBy sets the "refund_requested_by" field. +func (_u *PaymentOrderUpdateOne) SetRefundRequestedBy(v string) *PaymentOrderUpdateOne { + _u.mutation.SetRefundRequestedBy(v) + return _u +} + +// SetNillableRefundRequestedBy sets the "refund_requested_by" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableRefundRequestedBy(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetRefundRequestedBy(*v) + } + return _u +} + +// ClearRefundRequestedBy clears the value of the "refund_requested_by" field. +func (_u *PaymentOrderUpdateOne) ClearRefundRequestedBy() *PaymentOrderUpdateOne { + _u.mutation.ClearRefundRequestedBy() + return _u +} + +// SetExpiresAt sets the "expires_at" field. +func (_u *PaymentOrderUpdateOne) SetExpiresAt(v time.Time) *PaymentOrderUpdateOne { + _u.mutation.SetExpiresAt(v) + return _u +} + +// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableExpiresAt(v *time.Time) *PaymentOrderUpdateOne { + if v != nil { + _u.SetExpiresAt(*v) + } + return _u +} + +// SetPaidAt sets the "paid_at" field. +func (_u *PaymentOrderUpdateOne) SetPaidAt(v time.Time) *PaymentOrderUpdateOne { + _u.mutation.SetPaidAt(v) + return _u +} + +// SetNillablePaidAt sets the "paid_at" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillablePaidAt(v *time.Time) *PaymentOrderUpdateOne { + if v != nil { + _u.SetPaidAt(*v) + } + return _u +} + +// ClearPaidAt clears the value of the "paid_at" field. +func (_u *PaymentOrderUpdateOne) ClearPaidAt() *PaymentOrderUpdateOne { + _u.mutation.ClearPaidAt() + return _u +} + +// SetCompletedAt sets the "completed_at" field. +func (_u *PaymentOrderUpdateOne) SetCompletedAt(v time.Time) *PaymentOrderUpdateOne { + _u.mutation.SetCompletedAt(v) + return _u +} + +// SetNillableCompletedAt sets the "completed_at" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableCompletedAt(v *time.Time) *PaymentOrderUpdateOne { + if v != nil { + _u.SetCompletedAt(*v) + } + return _u +} + +// ClearCompletedAt clears the value of the "completed_at" field. +func (_u *PaymentOrderUpdateOne) ClearCompletedAt() *PaymentOrderUpdateOne { + _u.mutation.ClearCompletedAt() + return _u +} + +// SetFailedAt sets the "failed_at" field. +func (_u *PaymentOrderUpdateOne) SetFailedAt(v time.Time) *PaymentOrderUpdateOne { + _u.mutation.SetFailedAt(v) + return _u +} + +// SetNillableFailedAt sets the "failed_at" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableFailedAt(v *time.Time) *PaymentOrderUpdateOne { + if v != nil { + _u.SetFailedAt(*v) + } + return _u +} + +// ClearFailedAt clears the value of the "failed_at" field. +func (_u *PaymentOrderUpdateOne) ClearFailedAt() *PaymentOrderUpdateOne { + _u.mutation.ClearFailedAt() + return _u +} + +// SetFailedReason sets the "failed_reason" field. +func (_u *PaymentOrderUpdateOne) SetFailedReason(v string) *PaymentOrderUpdateOne { + _u.mutation.SetFailedReason(v) + return _u +} + +// SetNillableFailedReason sets the "failed_reason" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableFailedReason(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetFailedReason(*v) + } + return _u +} + +// ClearFailedReason clears the value of the "failed_reason" field. +func (_u *PaymentOrderUpdateOne) ClearFailedReason() *PaymentOrderUpdateOne { + _u.mutation.ClearFailedReason() + return _u +} + +// SetClientIP sets the "client_ip" field. +func (_u *PaymentOrderUpdateOne) SetClientIP(v string) *PaymentOrderUpdateOne { + _u.mutation.SetClientIP(v) + return _u +} + +// SetNillableClientIP sets the "client_ip" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableClientIP(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetClientIP(*v) + } + return _u +} + +// SetSrcHost sets the "src_host" field. +func (_u *PaymentOrderUpdateOne) SetSrcHost(v string) *PaymentOrderUpdateOne { + _u.mutation.SetSrcHost(v) + return _u +} + +// SetNillableSrcHost sets the "src_host" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableSrcHost(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetSrcHost(*v) + } + return _u +} + +// SetSrcURL sets the "src_url" field. +func (_u *PaymentOrderUpdateOne) SetSrcURL(v string) *PaymentOrderUpdateOne { + _u.mutation.SetSrcURL(v) + return _u +} + +// SetNillableSrcURL sets the "src_url" field if the given value is not nil. +func (_u *PaymentOrderUpdateOne) SetNillableSrcURL(v *string) *PaymentOrderUpdateOne { + if v != nil { + _u.SetSrcURL(*v) + } + return _u +} + +// ClearSrcURL clears the value of the "src_url" field. +func (_u *PaymentOrderUpdateOne) ClearSrcURL() *PaymentOrderUpdateOne { + _u.mutation.ClearSrcURL() + return _u +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *PaymentOrderUpdateOne) SetUpdatedAt(v time.Time) *PaymentOrderUpdateOne { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetUser sets the "user" edge to the User entity. +func (_u *PaymentOrderUpdateOne) SetUser(v *User) *PaymentOrderUpdateOne { + return _u.SetUserID(v.ID) +} + +// Mutation returns the PaymentOrderMutation object of the builder. +func (_u *PaymentOrderUpdateOne) Mutation() *PaymentOrderMutation { + return _u.mutation +} + +// ClearUser clears the "user" edge to the User entity. +func (_u *PaymentOrderUpdateOne) ClearUser() *PaymentOrderUpdateOne { + _u.mutation.ClearUser() + return _u +} + +// Where appends a list predicates to the PaymentOrderUpdate builder. +func (_u *PaymentOrderUpdateOne) Where(ps ...predicate.PaymentOrder) *PaymentOrderUpdateOne { + _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 *PaymentOrderUpdateOne) Select(field string, fields ...string) *PaymentOrderUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated PaymentOrder entity. +func (_u *PaymentOrderUpdateOne) Save(ctx context.Context) (*PaymentOrder, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *PaymentOrderUpdateOne) SaveX(ctx context.Context) *PaymentOrder { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *PaymentOrderUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *PaymentOrderUpdateOne) 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 *PaymentOrderUpdateOne) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := paymentorder.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *PaymentOrderUpdateOne) check() error { + if v, ok := _u.mutation.UserEmail(); ok { + if err := paymentorder.UserEmailValidator(v); err != nil { + return &ValidationError{Name: "user_email", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.user_email": %w`, err)} + } + } + if v, ok := _u.mutation.UserName(); ok { + if err := paymentorder.UserNameValidator(v); err != nil { + return &ValidationError{Name: "user_name", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.user_name": %w`, err)} + } + } + if v, ok := _u.mutation.RechargeCode(); ok { + if err := paymentorder.RechargeCodeValidator(v); err != nil { + return &ValidationError{Name: "recharge_code", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.recharge_code": %w`, err)} + } + } + if v, ok := _u.mutation.OutTradeNo(); ok { + if err := paymentorder.OutTradeNoValidator(v); err != nil { + return &ValidationError{Name: "out_trade_no", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.out_trade_no": %w`, err)} + } + } + if v, ok := _u.mutation.PaymentType(); ok { + if err := paymentorder.PaymentTypeValidator(v); err != nil { + return &ValidationError{Name: "payment_type", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.payment_type": %w`, err)} + } + } + if v, ok := _u.mutation.PaymentTradeNo(); ok { + if err := paymentorder.PaymentTradeNoValidator(v); err != nil { + return &ValidationError{Name: "payment_trade_no", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.payment_trade_no": %w`, err)} + } + } + if v, ok := _u.mutation.OrderType(); ok { + if err := paymentorder.OrderTypeValidator(v); err != nil { + return &ValidationError{Name: "order_type", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.order_type": %w`, err)} + } + } + if v, ok := _u.mutation.ProviderInstanceID(); ok { + if err := paymentorder.ProviderInstanceIDValidator(v); err != nil { + return &ValidationError{Name: "provider_instance_id", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.provider_instance_id": %w`, err)} + } + } + if v, ok := _u.mutation.Status(); ok { + if err := paymentorder.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.status": %w`, err)} + } + } + if v, ok := _u.mutation.RefundRequestedBy(); ok { + if err := paymentorder.RefundRequestedByValidator(v); err != nil { + return &ValidationError{Name: "refund_requested_by", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.refund_requested_by": %w`, err)} + } + } + if v, ok := _u.mutation.ClientIP(); ok { + if err := paymentorder.ClientIPValidator(v); err != nil { + return &ValidationError{Name: "client_ip", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.client_ip": %w`, err)} + } + } + if v, ok := _u.mutation.SrcHost(); ok { + if err := paymentorder.SrcHostValidator(v); err != nil { + return &ValidationError{Name: "src_host", err: fmt.Errorf(`ent: validator failed for field "PaymentOrder.src_host": %w`, err)} + } + } + if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 { + return errors.New(`ent: clearing a required unique edge "PaymentOrder.user"`) + } + return nil +} + +func (_u *PaymentOrderUpdateOne) sqlSave(ctx context.Context) (_node *PaymentOrder, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(paymentorder.Table, paymentorder.Columns, sqlgraph.NewFieldSpec(paymentorder.FieldID, field.TypeInt64)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "PaymentOrder.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, paymentorder.FieldID) + for _, f := range fields { + if !paymentorder.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != paymentorder.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.UserEmail(); ok { + _spec.SetField(paymentorder.FieldUserEmail, field.TypeString, value) + } + if value, ok := _u.mutation.UserName(); ok { + _spec.SetField(paymentorder.FieldUserName, field.TypeString, value) + } + if value, ok := _u.mutation.UserNotes(); ok { + _spec.SetField(paymentorder.FieldUserNotes, field.TypeString, value) + } + if _u.mutation.UserNotesCleared() { + _spec.ClearField(paymentorder.FieldUserNotes, field.TypeString) + } + if value, ok := _u.mutation.Amount(); ok { + _spec.SetField(paymentorder.FieldAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedAmount(); ok { + _spec.AddField(paymentorder.FieldAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.PayAmount(); ok { + _spec.SetField(paymentorder.FieldPayAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedPayAmount(); ok { + _spec.AddField(paymentorder.FieldPayAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.FeeRate(); ok { + _spec.SetField(paymentorder.FieldFeeRate, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedFeeRate(); ok { + _spec.AddField(paymentorder.FieldFeeRate, field.TypeFloat64, value) + } + if value, ok := _u.mutation.RechargeCode(); ok { + _spec.SetField(paymentorder.FieldRechargeCode, field.TypeString, value) + } + if value, ok := _u.mutation.OutTradeNo(); ok { + _spec.SetField(paymentorder.FieldOutTradeNo, field.TypeString, value) + } + if value, ok := _u.mutation.PaymentType(); ok { + _spec.SetField(paymentorder.FieldPaymentType, field.TypeString, value) + } + if value, ok := _u.mutation.PaymentTradeNo(); ok { + _spec.SetField(paymentorder.FieldPaymentTradeNo, field.TypeString, value) + } + if value, ok := _u.mutation.PayURL(); ok { + _spec.SetField(paymentorder.FieldPayURL, field.TypeString, value) + } + if _u.mutation.PayURLCleared() { + _spec.ClearField(paymentorder.FieldPayURL, field.TypeString) + } + if value, ok := _u.mutation.QrCode(); ok { + _spec.SetField(paymentorder.FieldQrCode, field.TypeString, value) + } + if _u.mutation.QrCodeCleared() { + _spec.ClearField(paymentorder.FieldQrCode, field.TypeString) + } + if value, ok := _u.mutation.QrCodeImg(); ok { + _spec.SetField(paymentorder.FieldQrCodeImg, field.TypeString, value) + } + if _u.mutation.QrCodeImgCleared() { + _spec.ClearField(paymentorder.FieldQrCodeImg, field.TypeString) + } + if value, ok := _u.mutation.OrderType(); ok { + _spec.SetField(paymentorder.FieldOrderType, field.TypeString, value) + } + if value, ok := _u.mutation.PlanID(); ok { + _spec.SetField(paymentorder.FieldPlanID, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedPlanID(); ok { + _spec.AddField(paymentorder.FieldPlanID, field.TypeInt64, value) + } + if _u.mutation.PlanIDCleared() { + _spec.ClearField(paymentorder.FieldPlanID, field.TypeInt64) + } + if value, ok := _u.mutation.SubscriptionGroupID(); ok { + _spec.SetField(paymentorder.FieldSubscriptionGroupID, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedSubscriptionGroupID(); ok { + _spec.AddField(paymentorder.FieldSubscriptionGroupID, field.TypeInt64, value) + } + if _u.mutation.SubscriptionGroupIDCleared() { + _spec.ClearField(paymentorder.FieldSubscriptionGroupID, field.TypeInt64) + } + if value, ok := _u.mutation.SubscriptionDays(); ok { + _spec.SetField(paymentorder.FieldSubscriptionDays, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedSubscriptionDays(); ok { + _spec.AddField(paymentorder.FieldSubscriptionDays, field.TypeInt, value) + } + if _u.mutation.SubscriptionDaysCleared() { + _spec.ClearField(paymentorder.FieldSubscriptionDays, field.TypeInt) + } + if value, ok := _u.mutation.ProviderInstanceID(); ok { + _spec.SetField(paymentorder.FieldProviderInstanceID, field.TypeString, value) + } + if _u.mutation.ProviderInstanceIDCleared() { + _spec.ClearField(paymentorder.FieldProviderInstanceID, field.TypeString) + } + if value, ok := _u.mutation.Status(); ok { + _spec.SetField(paymentorder.FieldStatus, field.TypeString, value) + } + if value, ok := _u.mutation.RefundAmount(); ok { + _spec.SetField(paymentorder.FieldRefundAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.AddedRefundAmount(); ok { + _spec.AddField(paymentorder.FieldRefundAmount, field.TypeFloat64, value) + } + if value, ok := _u.mutation.RefundReason(); ok { + _spec.SetField(paymentorder.FieldRefundReason, field.TypeString, value) + } + if _u.mutation.RefundReasonCleared() { + _spec.ClearField(paymentorder.FieldRefundReason, field.TypeString) + } + if value, ok := _u.mutation.RefundAt(); ok { + _spec.SetField(paymentorder.FieldRefundAt, field.TypeTime, value) + } + if _u.mutation.RefundAtCleared() { + _spec.ClearField(paymentorder.FieldRefundAt, field.TypeTime) + } + if value, ok := _u.mutation.ForceRefund(); ok { + _spec.SetField(paymentorder.FieldForceRefund, field.TypeBool, value) + } + if value, ok := _u.mutation.RefundRequestedAt(); ok { + _spec.SetField(paymentorder.FieldRefundRequestedAt, field.TypeTime, value) + } + if _u.mutation.RefundRequestedAtCleared() { + _spec.ClearField(paymentorder.FieldRefundRequestedAt, field.TypeTime) + } + if value, ok := _u.mutation.RefundRequestReason(); ok { + _spec.SetField(paymentorder.FieldRefundRequestReason, field.TypeString, value) + } + if _u.mutation.RefundRequestReasonCleared() { + _spec.ClearField(paymentorder.FieldRefundRequestReason, field.TypeString) + } + if value, ok := _u.mutation.RefundRequestedBy(); ok { + _spec.SetField(paymentorder.FieldRefundRequestedBy, field.TypeString, value) + } + if _u.mutation.RefundRequestedByCleared() { + _spec.ClearField(paymentorder.FieldRefundRequestedBy, field.TypeString) + } + if value, ok := _u.mutation.ExpiresAt(); ok { + _spec.SetField(paymentorder.FieldExpiresAt, field.TypeTime, value) + } + if value, ok := _u.mutation.PaidAt(); ok { + _spec.SetField(paymentorder.FieldPaidAt, field.TypeTime, value) + } + if _u.mutation.PaidAtCleared() { + _spec.ClearField(paymentorder.FieldPaidAt, field.TypeTime) + } + if value, ok := _u.mutation.CompletedAt(); ok { + _spec.SetField(paymentorder.FieldCompletedAt, field.TypeTime, value) + } + if _u.mutation.CompletedAtCleared() { + _spec.ClearField(paymentorder.FieldCompletedAt, field.TypeTime) + } + if value, ok := _u.mutation.FailedAt(); ok { + _spec.SetField(paymentorder.FieldFailedAt, field.TypeTime, value) + } + if _u.mutation.FailedAtCleared() { + _spec.ClearField(paymentorder.FieldFailedAt, field.TypeTime) + } + if value, ok := _u.mutation.FailedReason(); ok { + _spec.SetField(paymentorder.FieldFailedReason, field.TypeString, value) + } + if _u.mutation.FailedReasonCleared() { + _spec.ClearField(paymentorder.FieldFailedReason, field.TypeString) + } + if value, ok := _u.mutation.ClientIP(); ok { + _spec.SetField(paymentorder.FieldClientIP, field.TypeString, value) + } + if value, ok := _u.mutation.SrcHost(); ok { + _spec.SetField(paymentorder.FieldSrcHost, field.TypeString, value) + } + if value, ok := _u.mutation.SrcURL(); ok { + _spec.SetField(paymentorder.FieldSrcURL, field.TypeString, value) + } + if _u.mutation.SrcURLCleared() { + _spec.ClearField(paymentorder.FieldSrcURL, field.TypeString) + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(paymentorder.FieldUpdatedAt, field.TypeTime, value) + } + if _u.mutation.UserCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: paymentorder.UserTable, + Columns: []string{paymentorder.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: paymentorder.UserTable, + Columns: []string{paymentorder.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &PaymentOrder{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{paymentorder.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + _u.mutation.done = true + return _node, nil +} diff --git a/backend/ent/paymentproviderinstance.go b/backend/ent/paymentproviderinstance.go new file mode 100644 index 00000000..087cb13a --- /dev/null +++ b/backend/ent/paymentproviderinstance.go @@ -0,0 +1,218 @@ +// 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"` + // PaymentMode holds the value of the "payment_mode" field. + PaymentMode string `json:"payment_mode,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.FieldPaymentMode, 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.FieldPaymentMode: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field payment_mode", values[i]) + } else if value.Valid { + _m.PaymentMode = value.String + } + 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("payment_mode=") + builder.WriteString(_m.PaymentMode) + 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 diff --git a/backend/ent/paymentproviderinstance/paymentproviderinstance.go b/backend/ent/paymentproviderinstance/paymentproviderinstance.go new file mode 100644 index 00000000..c430fef6 --- /dev/null +++ b/backend/ent/paymentproviderinstance/paymentproviderinstance.go @@ -0,0 +1,160 @@ +// 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" + // FieldPaymentMode holds the string denoting the payment_mode field in the database. + FieldPaymentMode = "payment_mode" + // 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, + FieldPaymentMode, + 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 + // DefaultPaymentMode holds the default value on creation for the "payment_mode" field. + DefaultPaymentMode string + // PaymentModeValidator is a validator for the "payment_mode" field. It is called by the builders before save. + PaymentModeValidator func(string) error + // 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() +} + +// ByPaymentMode orders the results by the payment_mode field. +func ByPaymentMode(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPaymentMode, 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() +} diff --git a/backend/ent/paymentproviderinstance/where.go b/backend/ent/paymentproviderinstance/where.go new file mode 100644 index 00000000..7b99517f --- /dev/null +++ b/backend/ent/paymentproviderinstance/where.go @@ -0,0 +1,655 @@ +// 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)) +} + +// PaymentMode applies equality check predicate on the "payment_mode" field. It's identical to PaymentModeEQ. +func PaymentMode(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldEQ(FieldPaymentMode, 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)) +} + +// PaymentModeEQ applies the EQ predicate on the "payment_mode" field. +func PaymentModeEQ(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldEQ(FieldPaymentMode, v)) +} + +// PaymentModeNEQ applies the NEQ predicate on the "payment_mode" field. +func PaymentModeNEQ(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldNEQ(FieldPaymentMode, v)) +} + +// PaymentModeIn applies the In predicate on the "payment_mode" field. +func PaymentModeIn(vs ...string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldIn(FieldPaymentMode, vs...)) +} + +// PaymentModeNotIn applies the NotIn predicate on the "payment_mode" field. +func PaymentModeNotIn(vs ...string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldNotIn(FieldPaymentMode, vs...)) +} + +// PaymentModeGT applies the GT predicate on the "payment_mode" field. +func PaymentModeGT(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldGT(FieldPaymentMode, v)) +} + +// PaymentModeGTE applies the GTE predicate on the "payment_mode" field. +func PaymentModeGTE(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldGTE(FieldPaymentMode, v)) +} + +// PaymentModeLT applies the LT predicate on the "payment_mode" field. +func PaymentModeLT(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldLT(FieldPaymentMode, v)) +} + +// PaymentModeLTE applies the LTE predicate on the "payment_mode" field. +func PaymentModeLTE(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldLTE(FieldPaymentMode, v)) +} + +// PaymentModeContains applies the Contains predicate on the "payment_mode" field. +func PaymentModeContains(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldContains(FieldPaymentMode, v)) +} + +// PaymentModeHasPrefix applies the HasPrefix predicate on the "payment_mode" field. +func PaymentModeHasPrefix(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldHasPrefix(FieldPaymentMode, v)) +} + +// PaymentModeHasSuffix applies the HasSuffix predicate on the "payment_mode" field. +func PaymentModeHasSuffix(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldHasSuffix(FieldPaymentMode, v)) +} + +// PaymentModeEqualFold applies the EqualFold predicate on the "payment_mode" field. +func PaymentModeEqualFold(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldEqualFold(FieldPaymentMode, v)) +} + +// PaymentModeContainsFold applies the ContainsFold predicate on the "payment_mode" field. +func PaymentModeContainsFold(v string) predicate.PaymentProviderInstance { + return predicate.PaymentProviderInstance(sql.FieldContainsFold(FieldPaymentMode, 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)) +} diff --git a/backend/ent/paymentproviderinstance_create.go b/backend/ent/paymentproviderinstance_create.go new file mode 100644 index 00000000..20b16ddd --- /dev/null +++ b/backend/ent/paymentproviderinstance_create.go @@ -0,0 +1,1111 @@ +// 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" +) + +// PaymentProviderInstanceCreate is the builder for creating a PaymentProviderInstance entity. +type PaymentProviderInstanceCreate struct { + config + mutation *PaymentProviderInstanceMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetProviderKey sets the "provider_key" field. +func (_c *PaymentProviderInstanceCreate) SetProviderKey(v string) *PaymentProviderInstanceCreate { + _c.mutation.SetProviderKey(v) + return _c +} + +// SetName sets the "name" field. +func (_c *PaymentProviderInstanceCreate) SetName(v string) *PaymentProviderInstanceCreate { + _c.mutation.SetName(v) + return _c +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillableName(v *string) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetName(*v) + } + return _c +} + +// SetConfig sets the "config" field. +func (_c *PaymentProviderInstanceCreate) SetConfig(v string) *PaymentProviderInstanceCreate { + _c.mutation.SetConfig(v) + return _c +} + +// SetSupportedTypes sets the "supported_types" field. +func (_c *PaymentProviderInstanceCreate) SetSupportedTypes(v string) *PaymentProviderInstanceCreate { + _c.mutation.SetSupportedTypes(v) + return _c +} + +// SetNillableSupportedTypes sets the "supported_types" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillableSupportedTypes(v *string) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetSupportedTypes(*v) + } + return _c +} + +// SetEnabled sets the "enabled" field. +func (_c *PaymentProviderInstanceCreate) SetEnabled(v bool) *PaymentProviderInstanceCreate { + _c.mutation.SetEnabled(v) + return _c +} + +// SetNillableEnabled sets the "enabled" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillableEnabled(v *bool) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetEnabled(*v) + } + return _c +} + +// SetPaymentMode sets the "payment_mode" field. +func (_c *PaymentProviderInstanceCreate) SetPaymentMode(v string) *PaymentProviderInstanceCreate { + _c.mutation.SetPaymentMode(v) + return _c +} + +// SetNillablePaymentMode sets the "payment_mode" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillablePaymentMode(v *string) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetPaymentMode(*v) + } + return _c +} + +// SetSortOrder sets the "sort_order" field. +func (_c *PaymentProviderInstanceCreate) SetSortOrder(v int) *PaymentProviderInstanceCreate { + _c.mutation.SetSortOrder(v) + return _c +} + +// SetNillableSortOrder sets the "sort_order" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillableSortOrder(v *int) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetSortOrder(*v) + } + return _c +} + +// SetLimits sets the "limits" field. +func (_c *PaymentProviderInstanceCreate) SetLimits(v string) *PaymentProviderInstanceCreate { + _c.mutation.SetLimits(v) + return _c +} + +// SetNillableLimits sets the "limits" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillableLimits(v *string) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetLimits(*v) + } + return _c +} + +// SetRefundEnabled sets the "refund_enabled" field. +func (_c *PaymentProviderInstanceCreate) SetRefundEnabled(v bool) *PaymentProviderInstanceCreate { + _c.mutation.SetRefundEnabled(v) + return _c +} + +// SetNillableRefundEnabled sets the "refund_enabled" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillableRefundEnabled(v *bool) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetRefundEnabled(*v) + } + return _c +} + +// SetCreatedAt sets the "created_at" field. +func (_c *PaymentProviderInstanceCreate) SetCreatedAt(v time.Time) *PaymentProviderInstanceCreate { + _c.mutation.SetCreatedAt(v) + return _c +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillableCreatedAt(v *time.Time) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetCreatedAt(*v) + } + return _c +} + +// SetUpdatedAt sets the "updated_at" field. +func (_c *PaymentProviderInstanceCreate) SetUpdatedAt(v time.Time) *PaymentProviderInstanceCreate { + _c.mutation.SetUpdatedAt(v) + return _c +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (_c *PaymentProviderInstanceCreate) SetNillableUpdatedAt(v *time.Time) *PaymentProviderInstanceCreate { + if v != nil { + _c.SetUpdatedAt(*v) + } + return _c +} + +// Mutation returns the PaymentProviderInstanceMutation object of the builder. +func (_c *PaymentProviderInstanceCreate) Mutation() *PaymentProviderInstanceMutation { + return _c.mutation +} + +// Save creates the PaymentProviderInstance in the database. +func (_c *PaymentProviderInstanceCreate) Save(ctx context.Context) (*PaymentProviderInstance, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *PaymentProviderInstanceCreate) SaveX(ctx context.Context) *PaymentProviderInstance { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *PaymentProviderInstanceCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *PaymentProviderInstanceCreate) 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 *PaymentProviderInstanceCreate) defaults() { + if _, ok := _c.mutation.Name(); !ok { + v := paymentproviderinstance.DefaultName + _c.mutation.SetName(v) + } + if _, ok := _c.mutation.SupportedTypes(); !ok { + v := paymentproviderinstance.DefaultSupportedTypes + _c.mutation.SetSupportedTypes(v) + } + if _, ok := _c.mutation.Enabled(); !ok { + v := paymentproviderinstance.DefaultEnabled + _c.mutation.SetEnabled(v) + } + if _, ok := _c.mutation.PaymentMode(); !ok { + v := paymentproviderinstance.DefaultPaymentMode + _c.mutation.SetPaymentMode(v) + } + if _, ok := _c.mutation.SortOrder(); !ok { + v := paymentproviderinstance.DefaultSortOrder + _c.mutation.SetSortOrder(v) + } + if _, ok := _c.mutation.Limits(); !ok { + v := paymentproviderinstance.DefaultLimits + _c.mutation.SetLimits(v) + } + if _, ok := _c.mutation.RefundEnabled(); !ok { + v := paymentproviderinstance.DefaultRefundEnabled + _c.mutation.SetRefundEnabled(v) + } + if _, ok := _c.mutation.CreatedAt(); !ok { + v := paymentproviderinstance.DefaultCreatedAt() + _c.mutation.SetCreatedAt(v) + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + v := paymentproviderinstance.DefaultUpdatedAt() + _c.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *PaymentProviderInstanceCreate) check() error { + if _, ok := _c.mutation.ProviderKey(); !ok { + return &ValidationError{Name: "provider_key", err: errors.New(`ent: missing required field "PaymentProviderInstance.provider_key"`)} + } + if v, ok := _c.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 _, ok := _c.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "PaymentProviderInstance.name"`)} + } + if v, ok := _c.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 _, ok := _c.mutation.Config(); !ok { + return &ValidationError{Name: "config", err: errors.New(`ent: missing required field "PaymentProviderInstance.config"`)} + } + if _, ok := _c.mutation.SupportedTypes(); !ok { + return &ValidationError{Name: "supported_types", err: errors.New(`ent: missing required field "PaymentProviderInstance.supported_types"`)} + } + if v, ok := _c.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)} + } + } + if _, ok := _c.mutation.Enabled(); !ok { + return &ValidationError{Name: "enabled", err: errors.New(`ent: missing required field "PaymentProviderInstance.enabled"`)} + } + if _, ok := _c.mutation.PaymentMode(); !ok { + return &ValidationError{Name: "payment_mode", err: errors.New(`ent: missing required field "PaymentProviderInstance.payment_mode"`)} + } + if v, ok := _c.mutation.PaymentMode(); ok { + if err := paymentproviderinstance.PaymentModeValidator(v); err != nil { + return &ValidationError{Name: "payment_mode", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.payment_mode": %w`, err)} + } + } + if _, ok := _c.mutation.SortOrder(); !ok { + return &ValidationError{Name: "sort_order", err: errors.New(`ent: missing required field "PaymentProviderInstance.sort_order"`)} + } + if _, ok := _c.mutation.Limits(); !ok { + return &ValidationError{Name: "limits", err: errors.New(`ent: missing required field "PaymentProviderInstance.limits"`)} + } + if _, ok := _c.mutation.RefundEnabled(); !ok { + return &ValidationError{Name: "refund_enabled", err: errors.New(`ent: missing required field "PaymentProviderInstance.refund_enabled"`)} + } + if _, ok := _c.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "PaymentProviderInstance.created_at"`)} + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "PaymentProviderInstance.updated_at"`)} + } + return nil +} + +func (_c *PaymentProviderInstanceCreate) sqlSave(ctx context.Context) (*PaymentProviderInstance, 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 *PaymentProviderInstanceCreate) createSpec() (*PaymentProviderInstance, *sqlgraph.CreateSpec) { + var ( + _node = &PaymentProviderInstance{config: _c.config} + _spec = sqlgraph.NewCreateSpec(paymentproviderinstance.Table, sqlgraph.NewFieldSpec(paymentproviderinstance.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.ProviderKey(); ok { + _spec.SetField(paymentproviderinstance.FieldProviderKey, field.TypeString, value) + _node.ProviderKey = value + } + if value, ok := _c.mutation.Name(); ok { + _spec.SetField(paymentproviderinstance.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := _c.mutation.Config(); ok { + _spec.SetField(paymentproviderinstance.FieldConfig, field.TypeString, value) + _node.Config = value + } + if value, ok := _c.mutation.SupportedTypes(); ok { + _spec.SetField(paymentproviderinstance.FieldSupportedTypes, field.TypeString, value) + _node.SupportedTypes = value + } + if value, ok := _c.mutation.Enabled(); ok { + _spec.SetField(paymentproviderinstance.FieldEnabled, field.TypeBool, value) + _node.Enabled = value + } + if value, ok := _c.mutation.PaymentMode(); ok { + _spec.SetField(paymentproviderinstance.FieldPaymentMode, field.TypeString, value) + _node.PaymentMode = value + } + if value, ok := _c.mutation.SortOrder(); ok { + _spec.SetField(paymentproviderinstance.FieldSortOrder, field.TypeInt, value) + _node.SortOrder = value + } + if value, ok := _c.mutation.Limits(); ok { + _spec.SetField(paymentproviderinstance.FieldLimits, field.TypeString, value) + _node.Limits = value + } + if value, ok := _c.mutation.RefundEnabled(); ok { + _spec.SetField(paymentproviderinstance.FieldRefundEnabled, field.TypeBool, value) + _node.RefundEnabled = value + } + if value, ok := _c.mutation.CreatedAt(); ok { + _spec.SetField(paymentproviderinstance.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := _c.mutation.UpdatedAt(); ok { + _spec.SetField(paymentproviderinstance.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.PaymentProviderInstance.Create(). +// SetProviderKey(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.PaymentProviderInstanceUpsert) { +// SetProviderKey(v+v). +// }). +// Exec(ctx) +func (_c *PaymentProviderInstanceCreate) OnConflict(opts ...sql.ConflictOption) *PaymentProviderInstanceUpsertOne { + _c.conflict = opts + return &PaymentProviderInstanceUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.PaymentProviderInstance.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *PaymentProviderInstanceCreate) OnConflictColumns(columns ...string) *PaymentProviderInstanceUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &PaymentProviderInstanceUpsertOne{ + create: _c, + } +} + +type ( + // PaymentProviderInstanceUpsertOne is the builder for "upsert"-ing + // one PaymentProviderInstance node. + PaymentProviderInstanceUpsertOne struct { + create *PaymentProviderInstanceCreate + } + + // PaymentProviderInstanceUpsert is the "OnConflict" setter. + PaymentProviderInstanceUpsert struct { + *sql.UpdateSet + } +) + +// SetProviderKey sets the "provider_key" field. +func (u *PaymentProviderInstanceUpsert) SetProviderKey(v string) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldProviderKey, v) + return u +} + +// UpdateProviderKey sets the "provider_key" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateProviderKey() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldProviderKey) + return u +} + +// SetName sets the "name" field. +func (u *PaymentProviderInstanceUpsert) SetName(v string) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldName, v) + return u +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateName() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldName) + return u +} + +// SetConfig sets the "config" field. +func (u *PaymentProviderInstanceUpsert) SetConfig(v string) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldConfig, v) + return u +} + +// UpdateConfig sets the "config" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateConfig() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldConfig) + return u +} + +// SetSupportedTypes sets the "supported_types" field. +func (u *PaymentProviderInstanceUpsert) SetSupportedTypes(v string) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldSupportedTypes, v) + return u +} + +// UpdateSupportedTypes sets the "supported_types" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateSupportedTypes() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldSupportedTypes) + return u +} + +// SetEnabled sets the "enabled" field. +func (u *PaymentProviderInstanceUpsert) SetEnabled(v bool) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldEnabled, v) + return u +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateEnabled() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldEnabled) + return u +} + +// SetPaymentMode sets the "payment_mode" field. +func (u *PaymentProviderInstanceUpsert) SetPaymentMode(v string) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldPaymentMode, v) + return u +} + +// UpdatePaymentMode sets the "payment_mode" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdatePaymentMode() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldPaymentMode) + return u +} + +// SetSortOrder sets the "sort_order" field. +func (u *PaymentProviderInstanceUpsert) SetSortOrder(v int) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldSortOrder, v) + return u +} + +// UpdateSortOrder sets the "sort_order" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateSortOrder() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldSortOrder) + return u +} + +// AddSortOrder adds v to the "sort_order" field. +func (u *PaymentProviderInstanceUpsert) AddSortOrder(v int) *PaymentProviderInstanceUpsert { + u.Add(paymentproviderinstance.FieldSortOrder, v) + return u +} + +// SetLimits sets the "limits" field. +func (u *PaymentProviderInstanceUpsert) SetLimits(v string) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldLimits, v) + return u +} + +// UpdateLimits sets the "limits" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateLimits() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldLimits) + return u +} + +// SetRefundEnabled sets the "refund_enabled" field. +func (u *PaymentProviderInstanceUpsert) SetRefundEnabled(v bool) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldRefundEnabled, v) + return u +} + +// UpdateRefundEnabled sets the "refund_enabled" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateRefundEnabled() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldRefundEnabled) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *PaymentProviderInstanceUpsert) SetUpdatedAt(v time.Time) *PaymentProviderInstanceUpsert { + u.Set(paymentproviderinstance.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsert) UpdateUpdatedAt() *PaymentProviderInstanceUpsert { + u.SetExcluded(paymentproviderinstance.FieldUpdatedAt) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.PaymentProviderInstance.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *PaymentProviderInstanceUpsertOne) UpdateNewValues() *PaymentProviderInstanceUpsertOne { + 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(paymentproviderinstance.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.PaymentProviderInstance.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *PaymentProviderInstanceUpsertOne) Ignore() *PaymentProviderInstanceUpsertOne { + 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 *PaymentProviderInstanceUpsertOne) DoNothing() *PaymentProviderInstanceUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the PaymentProviderInstanceCreate.OnConflict +// documentation for more info. +func (u *PaymentProviderInstanceUpsertOne) Update(set func(*PaymentProviderInstanceUpsert)) *PaymentProviderInstanceUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&PaymentProviderInstanceUpsert{UpdateSet: update}) + })) + return u +} + +// SetProviderKey sets the "provider_key" field. +func (u *PaymentProviderInstanceUpsertOne) SetProviderKey(v string) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetProviderKey(v) + }) +} + +// UpdateProviderKey sets the "provider_key" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateProviderKey() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateProviderKey() + }) +} + +// SetName sets the "name" field. +func (u *PaymentProviderInstanceUpsertOne) SetName(v string) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateName() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateName() + }) +} + +// SetConfig sets the "config" field. +func (u *PaymentProviderInstanceUpsertOne) SetConfig(v string) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetConfig(v) + }) +} + +// UpdateConfig sets the "config" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateConfig() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateConfig() + }) +} + +// SetSupportedTypes sets the "supported_types" field. +func (u *PaymentProviderInstanceUpsertOne) SetSupportedTypes(v string) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetSupportedTypes(v) + }) +} + +// UpdateSupportedTypes sets the "supported_types" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateSupportedTypes() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateSupportedTypes() + }) +} + +// SetEnabled sets the "enabled" field. +func (u *PaymentProviderInstanceUpsertOne) SetEnabled(v bool) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetEnabled(v) + }) +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateEnabled() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateEnabled() + }) +} + +// SetPaymentMode sets the "payment_mode" field. +func (u *PaymentProviderInstanceUpsertOne) SetPaymentMode(v string) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetPaymentMode(v) + }) +} + +// UpdatePaymentMode sets the "payment_mode" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdatePaymentMode() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdatePaymentMode() + }) +} + +// SetSortOrder sets the "sort_order" field. +func (u *PaymentProviderInstanceUpsertOne) SetSortOrder(v int) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetSortOrder(v) + }) +} + +// AddSortOrder adds v to the "sort_order" field. +func (u *PaymentProviderInstanceUpsertOne) AddSortOrder(v int) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.AddSortOrder(v) + }) +} + +// UpdateSortOrder sets the "sort_order" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateSortOrder() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateSortOrder() + }) +} + +// SetLimits sets the "limits" field. +func (u *PaymentProviderInstanceUpsertOne) SetLimits(v string) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetLimits(v) + }) +} + +// UpdateLimits sets the "limits" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateLimits() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateLimits() + }) +} + +// SetRefundEnabled sets the "refund_enabled" field. +func (u *PaymentProviderInstanceUpsertOne) SetRefundEnabled(v bool) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetRefundEnabled(v) + }) +} + +// UpdateRefundEnabled sets the "refund_enabled" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateRefundEnabled() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateRefundEnabled() + }) +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *PaymentProviderInstanceUpsertOne) SetUpdatedAt(v time.Time) *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertOne) UpdateUpdatedAt() *PaymentProviderInstanceUpsertOne { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateUpdatedAt() + }) +} + +// Exec executes the query. +func (u *PaymentProviderInstanceUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for PaymentProviderInstanceCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *PaymentProviderInstanceUpsertOne) 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 *PaymentProviderInstanceUpsertOne) 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 *PaymentProviderInstanceUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// PaymentProviderInstanceCreateBulk is the builder for creating many PaymentProviderInstance entities in bulk. +type PaymentProviderInstanceCreateBulk struct { + config + err error + builders []*PaymentProviderInstanceCreate + conflict []sql.ConflictOption +} + +// Save creates the PaymentProviderInstance entities in the database. +func (_c *PaymentProviderInstanceCreateBulk) Save(ctx context.Context) ([]*PaymentProviderInstance, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*PaymentProviderInstance, 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.(*PaymentProviderInstanceMutation) + 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 *PaymentProviderInstanceCreateBulk) SaveX(ctx context.Context) []*PaymentProviderInstance { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *PaymentProviderInstanceCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *PaymentProviderInstanceCreateBulk) 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.PaymentProviderInstance.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.PaymentProviderInstanceUpsert) { +// SetProviderKey(v+v). +// }). +// Exec(ctx) +func (_c *PaymentProviderInstanceCreateBulk) OnConflict(opts ...sql.ConflictOption) *PaymentProviderInstanceUpsertBulk { + _c.conflict = opts + return &PaymentProviderInstanceUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.PaymentProviderInstance.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *PaymentProviderInstanceCreateBulk) OnConflictColumns(columns ...string) *PaymentProviderInstanceUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &PaymentProviderInstanceUpsertBulk{ + create: _c, + } +} + +// PaymentProviderInstanceUpsertBulk is the builder for "upsert"-ing +// a bulk of PaymentProviderInstance nodes. +type PaymentProviderInstanceUpsertBulk struct { + create *PaymentProviderInstanceCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.PaymentProviderInstance.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *PaymentProviderInstanceUpsertBulk) UpdateNewValues() *PaymentProviderInstanceUpsertBulk { + 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(paymentproviderinstance.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.PaymentProviderInstance.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *PaymentProviderInstanceUpsertBulk) Ignore() *PaymentProviderInstanceUpsertBulk { + 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 *PaymentProviderInstanceUpsertBulk) DoNothing() *PaymentProviderInstanceUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the PaymentProviderInstanceCreateBulk.OnConflict +// documentation for more info. +func (u *PaymentProviderInstanceUpsertBulk) Update(set func(*PaymentProviderInstanceUpsert)) *PaymentProviderInstanceUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&PaymentProviderInstanceUpsert{UpdateSet: update}) + })) + return u +} + +// SetProviderKey sets the "provider_key" field. +func (u *PaymentProviderInstanceUpsertBulk) SetProviderKey(v string) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetProviderKey(v) + }) +} + +// UpdateProviderKey sets the "provider_key" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateProviderKey() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateProviderKey() + }) +} + +// SetName sets the "name" field. +func (u *PaymentProviderInstanceUpsertBulk) SetName(v string) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateName() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateName() + }) +} + +// SetConfig sets the "config" field. +func (u *PaymentProviderInstanceUpsertBulk) SetConfig(v string) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetConfig(v) + }) +} + +// UpdateConfig sets the "config" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateConfig() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateConfig() + }) +} + +// SetSupportedTypes sets the "supported_types" field. +func (u *PaymentProviderInstanceUpsertBulk) SetSupportedTypes(v string) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetSupportedTypes(v) + }) +} + +// UpdateSupportedTypes sets the "supported_types" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateSupportedTypes() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateSupportedTypes() + }) +} + +// SetEnabled sets the "enabled" field. +func (u *PaymentProviderInstanceUpsertBulk) SetEnabled(v bool) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetEnabled(v) + }) +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateEnabled() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateEnabled() + }) +} + +// SetPaymentMode sets the "payment_mode" field. +func (u *PaymentProviderInstanceUpsertBulk) SetPaymentMode(v string) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetPaymentMode(v) + }) +} + +// UpdatePaymentMode sets the "payment_mode" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdatePaymentMode() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdatePaymentMode() + }) +} + +// SetSortOrder sets the "sort_order" field. +func (u *PaymentProviderInstanceUpsertBulk) SetSortOrder(v int) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetSortOrder(v) + }) +} + +// AddSortOrder adds v to the "sort_order" field. +func (u *PaymentProviderInstanceUpsertBulk) AddSortOrder(v int) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.AddSortOrder(v) + }) +} + +// UpdateSortOrder sets the "sort_order" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateSortOrder() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateSortOrder() + }) +} + +// SetLimits sets the "limits" field. +func (u *PaymentProviderInstanceUpsertBulk) SetLimits(v string) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetLimits(v) + }) +} + +// UpdateLimits sets the "limits" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateLimits() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateLimits() + }) +} + +// SetRefundEnabled sets the "refund_enabled" field. +func (u *PaymentProviderInstanceUpsertBulk) SetRefundEnabled(v bool) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetRefundEnabled(v) + }) +} + +// UpdateRefundEnabled sets the "refund_enabled" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateRefundEnabled() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateRefundEnabled() + }) +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *PaymentProviderInstanceUpsertBulk) SetUpdatedAt(v time.Time) *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *PaymentProviderInstanceUpsertBulk) UpdateUpdatedAt() *PaymentProviderInstanceUpsertBulk { + return u.Update(func(s *PaymentProviderInstanceUpsert) { + s.UpdateUpdatedAt() + }) +} + +// Exec executes the query. +func (u *PaymentProviderInstanceUpsertBulk) 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 PaymentProviderInstanceCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for PaymentProviderInstanceCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *PaymentProviderInstanceUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/paymentproviderinstance_delete.go b/backend/ent/paymentproviderinstance_delete.go new file mode 100644 index 00000000..0cffe731 --- /dev/null +++ b/backend/ent/paymentproviderinstance_delete.go @@ -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) + } +} diff --git a/backend/ent/paymentproviderinstance_query.go b/backend/ent/paymentproviderinstance_query.go new file mode 100644 index 00000000..c0212088 --- /dev/null +++ b/backend/ent/paymentproviderinstance_query.go @@ -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) +} diff --git a/backend/ent/paymentproviderinstance_update.go b/backend/ent/paymentproviderinstance_update.go new file mode 100644 index 00000000..06dba527 --- /dev/null +++ b/backend/ent/paymentproviderinstance_update.go @@ -0,0 +1,594 @@ +// 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 +} + +// SetPaymentMode sets the "payment_mode" field. +func (_u *PaymentProviderInstanceUpdate) SetPaymentMode(v string) *PaymentProviderInstanceUpdate { + _u.mutation.SetPaymentMode(v) + return _u +} + +// SetNillablePaymentMode sets the "payment_mode" field if the given value is not nil. +func (_u *PaymentProviderInstanceUpdate) SetNillablePaymentMode(v *string) *PaymentProviderInstanceUpdate { + if v != nil { + _u.SetPaymentMode(*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)} + } + } + if v, ok := _u.mutation.PaymentMode(); ok { + if err := paymentproviderinstance.PaymentModeValidator(v); err != nil { + return &ValidationError{Name: "payment_mode", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.payment_mode": %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.PaymentMode(); ok { + _spec.SetField(paymentproviderinstance.FieldPaymentMode, field.TypeString, 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 +} + +// SetPaymentMode sets the "payment_mode" field. +func (_u *PaymentProviderInstanceUpdateOne) SetPaymentMode(v string) *PaymentProviderInstanceUpdateOne { + _u.mutation.SetPaymentMode(v) + return _u +} + +// SetNillablePaymentMode sets the "payment_mode" field if the given value is not nil. +func (_u *PaymentProviderInstanceUpdateOne) SetNillablePaymentMode(v *string) *PaymentProviderInstanceUpdateOne { + if v != nil { + _u.SetPaymentMode(*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)} + } + } + if v, ok := _u.mutation.PaymentMode(); ok { + if err := paymentproviderinstance.PaymentModeValidator(v); err != nil { + return &ValidationError{Name: "payment_mode", err: fmt.Errorf(`ent: validator failed for field "PaymentProviderInstance.payment_mode": %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.PaymentMode(); ok { + _spec.SetField(paymentproviderinstance.FieldPaymentMode, field.TypeString, 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 +} diff --git a/backend/ent/predicate/predicate.go b/backend/ent/predicate/predicate.go index a652ab3f..ef551940 100644 --- a/backend/ent/predicate/predicate.go +++ b/backend/ent/predicate/predicate.go @@ -30,6 +30,15 @@ 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 +57,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) diff --git a/backend/ent/runtime/runtime.go b/backend/ent/runtime/runtime.go index 792f0566..821b7d66 100644 --- a/backend/ent/runtime/runtime.go +++ b/backend/ent/runtime/runtime.go @@ -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" @@ -508,6 +512,172 @@ 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) + // paymentorderDescOutTradeNo is the schema descriptor for out_trade_no field. + paymentorderDescOutTradeNo := paymentorderFields[8].Descriptor() + // paymentorder.DefaultOutTradeNo holds the default value on creation for the out_trade_no field. + paymentorder.DefaultOutTradeNo = paymentorderDescOutTradeNo.Default.(string) + // paymentorder.OutTradeNoValidator is a validator for the "out_trade_no" field. It is called by the builders before save. + paymentorder.OutTradeNoValidator = paymentorderDescOutTradeNo.Validators[0].(func(string) error) + // paymentorderDescPaymentType is the schema descriptor for payment_type field. + paymentorderDescPaymentType := paymentorderFields[9].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[10].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[14].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[18].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[19].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[20].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[23].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[26].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[32].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[33].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[35].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[36].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) + // paymentproviderinstanceDescPaymentMode is the schema descriptor for payment_mode field. + paymentproviderinstanceDescPaymentMode := paymentproviderinstanceFields[5].Descriptor() + // paymentproviderinstance.DefaultPaymentMode holds the default value on creation for the payment_mode field. + paymentproviderinstance.DefaultPaymentMode = paymentproviderinstanceDescPaymentMode.Default.(string) + // paymentproviderinstance.PaymentModeValidator is a validator for the "payment_mode" field. It is called by the builders before save. + paymentproviderinstance.PaymentModeValidator = paymentproviderinstanceDescPaymentMode.Validators[0].(func(string) error) + // paymentproviderinstanceDescSortOrder is the schema descriptor for sort_order field. + paymentproviderinstanceDescSortOrder := paymentproviderinstanceFields[6].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[7].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[8].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[9].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[10].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. @@ -756,6 +926,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 diff --git a/backend/ent/schema/payment_audit_log.go b/backend/ent/schema/payment_audit_log.go new file mode 100644 index 00000000..7f8a8c04 --- /dev/null +++ b/backend/ent/schema/payment_audit_log.go @@ -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"), + } +} diff --git a/backend/ent/schema/payment_order.go b/backend/ent/schema/payment_order.go new file mode 100644 index 00000000..a9576d2a --- /dev/null +++ b/backend/ent/schema/payment_order.go @@ -0,0 +1,190 @@ +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("out_trade_no"). + MaxLen(64). + Default(""), + 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("out_trade_no"), + 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"), + } +} diff --git a/backend/ent/schema/payment_provider_instance.go b/backend/ent/schema/payment_provider_instance.go new file mode 100644 index 00000000..08ab7d31 --- /dev/null +++ b/backend/ent/schema/payment_provider_instance.go @@ -0,0 +1,72 @@ +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.String("payment_mode"). + MaxLen(20). + Default(""), + 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"), + } +} diff --git a/backend/ent/schema/subscription_plan.go b/backend/ent/schema/subscription_plan.go new file mode 100644 index 00000000..3e30490b --- /dev/null +++ b/backend/ent/schema/subscription_plan.go @@ -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"), + } +} diff --git a/backend/ent/schema/user.go b/backend/ent/schema/user.go index d443ef45..af143d38 100644 --- a/backend/ent/schema/user.go +++ b/backend/ent/schema/user.go @@ -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), } } diff --git a/backend/ent/subscriptionplan.go b/backend/ent/subscriptionplan.go new file mode 100644 index 00000000..fa4d7ae3 --- /dev/null +++ b/backend/ent/subscriptionplan.go @@ -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 diff --git a/backend/ent/subscriptionplan/subscriptionplan.go b/backend/ent/subscriptionplan/subscriptionplan.go new file mode 100644 index 00000000..fa125aa7 --- /dev/null +++ b/backend/ent/subscriptionplan/subscriptionplan.go @@ -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() +} diff --git a/backend/ent/subscriptionplan/where.go b/backend/ent/subscriptionplan/where.go new file mode 100644 index 00000000..319cfdb5 --- /dev/null +++ b/backend/ent/subscriptionplan/where.go @@ -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)) +} diff --git a/backend/ent/subscriptionplan_create.go b/backend/ent/subscriptionplan_create.go new file mode 100644 index 00000000..9109db3a --- /dev/null +++ b/backend/ent/subscriptionplan_create.go @@ -0,0 +1,1317 @@ +// 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/subscriptionplan" +) + +// SubscriptionPlanCreate is the builder for creating a SubscriptionPlan entity. +type SubscriptionPlanCreate struct { + config + mutation *SubscriptionPlanMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetGroupID sets the "group_id" field. +func (_c *SubscriptionPlanCreate) SetGroupID(v int64) *SubscriptionPlanCreate { + _c.mutation.SetGroupID(v) + return _c +} + +// SetName sets the "name" field. +func (_c *SubscriptionPlanCreate) SetName(v string) *SubscriptionPlanCreate { + _c.mutation.SetName(v) + return _c +} + +// SetDescription sets the "description" field. +func (_c *SubscriptionPlanCreate) SetDescription(v string) *SubscriptionPlanCreate { + _c.mutation.SetDescription(v) + return _c +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableDescription(v *string) *SubscriptionPlanCreate { + if v != nil { + _c.SetDescription(*v) + } + return _c +} + +// SetPrice sets the "price" field. +func (_c *SubscriptionPlanCreate) SetPrice(v float64) *SubscriptionPlanCreate { + _c.mutation.SetPrice(v) + return _c +} + +// SetOriginalPrice sets the "original_price" field. +func (_c *SubscriptionPlanCreate) SetOriginalPrice(v float64) *SubscriptionPlanCreate { + _c.mutation.SetOriginalPrice(v) + return _c +} + +// SetNillableOriginalPrice sets the "original_price" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableOriginalPrice(v *float64) *SubscriptionPlanCreate { + if v != nil { + _c.SetOriginalPrice(*v) + } + return _c +} + +// SetValidityDays sets the "validity_days" field. +func (_c *SubscriptionPlanCreate) SetValidityDays(v int) *SubscriptionPlanCreate { + _c.mutation.SetValidityDays(v) + return _c +} + +// SetNillableValidityDays sets the "validity_days" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableValidityDays(v *int) *SubscriptionPlanCreate { + if v != nil { + _c.SetValidityDays(*v) + } + return _c +} + +// SetValidityUnit sets the "validity_unit" field. +func (_c *SubscriptionPlanCreate) SetValidityUnit(v string) *SubscriptionPlanCreate { + _c.mutation.SetValidityUnit(v) + return _c +} + +// SetNillableValidityUnit sets the "validity_unit" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableValidityUnit(v *string) *SubscriptionPlanCreate { + if v != nil { + _c.SetValidityUnit(*v) + } + return _c +} + +// SetFeatures sets the "features" field. +func (_c *SubscriptionPlanCreate) SetFeatures(v string) *SubscriptionPlanCreate { + _c.mutation.SetFeatures(v) + return _c +} + +// SetNillableFeatures sets the "features" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableFeatures(v *string) *SubscriptionPlanCreate { + if v != nil { + _c.SetFeatures(*v) + } + return _c +} + +// SetProductName sets the "product_name" field. +func (_c *SubscriptionPlanCreate) SetProductName(v string) *SubscriptionPlanCreate { + _c.mutation.SetProductName(v) + return _c +} + +// SetNillableProductName sets the "product_name" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableProductName(v *string) *SubscriptionPlanCreate { + if v != nil { + _c.SetProductName(*v) + } + return _c +} + +// SetForSale sets the "for_sale" field. +func (_c *SubscriptionPlanCreate) SetForSale(v bool) *SubscriptionPlanCreate { + _c.mutation.SetForSale(v) + return _c +} + +// SetNillableForSale sets the "for_sale" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableForSale(v *bool) *SubscriptionPlanCreate { + if v != nil { + _c.SetForSale(*v) + } + return _c +} + +// SetSortOrder sets the "sort_order" field. +func (_c *SubscriptionPlanCreate) SetSortOrder(v int) *SubscriptionPlanCreate { + _c.mutation.SetSortOrder(v) + return _c +} + +// SetNillableSortOrder sets the "sort_order" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableSortOrder(v *int) *SubscriptionPlanCreate { + if v != nil { + _c.SetSortOrder(*v) + } + return _c +} + +// SetCreatedAt sets the "created_at" field. +func (_c *SubscriptionPlanCreate) SetCreatedAt(v time.Time) *SubscriptionPlanCreate { + _c.mutation.SetCreatedAt(v) + return _c +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableCreatedAt(v *time.Time) *SubscriptionPlanCreate { + if v != nil { + _c.SetCreatedAt(*v) + } + return _c +} + +// SetUpdatedAt sets the "updated_at" field. +func (_c *SubscriptionPlanCreate) SetUpdatedAt(v time.Time) *SubscriptionPlanCreate { + _c.mutation.SetUpdatedAt(v) + return _c +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (_c *SubscriptionPlanCreate) SetNillableUpdatedAt(v *time.Time) *SubscriptionPlanCreate { + if v != nil { + _c.SetUpdatedAt(*v) + } + return _c +} + +// Mutation returns the SubscriptionPlanMutation object of the builder. +func (_c *SubscriptionPlanCreate) Mutation() *SubscriptionPlanMutation { + return _c.mutation +} + +// Save creates the SubscriptionPlan in the database. +func (_c *SubscriptionPlanCreate) Save(ctx context.Context) (*SubscriptionPlan, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *SubscriptionPlanCreate) SaveX(ctx context.Context) *SubscriptionPlan { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *SubscriptionPlanCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *SubscriptionPlanCreate) 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 *SubscriptionPlanCreate) defaults() { + if _, ok := _c.mutation.Description(); !ok { + v := subscriptionplan.DefaultDescription + _c.mutation.SetDescription(v) + } + if _, ok := _c.mutation.ValidityDays(); !ok { + v := subscriptionplan.DefaultValidityDays + _c.mutation.SetValidityDays(v) + } + if _, ok := _c.mutation.ValidityUnit(); !ok { + v := subscriptionplan.DefaultValidityUnit + _c.mutation.SetValidityUnit(v) + } + if _, ok := _c.mutation.Features(); !ok { + v := subscriptionplan.DefaultFeatures + _c.mutation.SetFeatures(v) + } + if _, ok := _c.mutation.ProductName(); !ok { + v := subscriptionplan.DefaultProductName + _c.mutation.SetProductName(v) + } + if _, ok := _c.mutation.ForSale(); !ok { + v := subscriptionplan.DefaultForSale + _c.mutation.SetForSale(v) + } + if _, ok := _c.mutation.SortOrder(); !ok { + v := subscriptionplan.DefaultSortOrder + _c.mutation.SetSortOrder(v) + } + if _, ok := _c.mutation.CreatedAt(); !ok { + v := subscriptionplan.DefaultCreatedAt() + _c.mutation.SetCreatedAt(v) + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + v := subscriptionplan.DefaultUpdatedAt() + _c.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *SubscriptionPlanCreate) check() error { + if _, ok := _c.mutation.GroupID(); !ok { + return &ValidationError{Name: "group_id", err: errors.New(`ent: missing required field "SubscriptionPlan.group_id"`)} + } + if _, ok := _c.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "SubscriptionPlan.name"`)} + } + if v, ok := _c.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 _, ok := _c.mutation.Description(); !ok { + return &ValidationError{Name: "description", err: errors.New(`ent: missing required field "SubscriptionPlan.description"`)} + } + if _, ok := _c.mutation.Price(); !ok { + return &ValidationError{Name: "price", err: errors.New(`ent: missing required field "SubscriptionPlan.price"`)} + } + if _, ok := _c.mutation.ValidityDays(); !ok { + return &ValidationError{Name: "validity_days", err: errors.New(`ent: missing required field "SubscriptionPlan.validity_days"`)} + } + if _, ok := _c.mutation.ValidityUnit(); !ok { + return &ValidationError{Name: "validity_unit", err: errors.New(`ent: missing required field "SubscriptionPlan.validity_unit"`)} + } + if v, ok := _c.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 _, ok := _c.mutation.Features(); !ok { + return &ValidationError{Name: "features", err: errors.New(`ent: missing required field "SubscriptionPlan.features"`)} + } + if _, ok := _c.mutation.ProductName(); !ok { + return &ValidationError{Name: "product_name", err: errors.New(`ent: missing required field "SubscriptionPlan.product_name"`)} + } + if v, ok := _c.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)} + } + } + if _, ok := _c.mutation.ForSale(); !ok { + return &ValidationError{Name: "for_sale", err: errors.New(`ent: missing required field "SubscriptionPlan.for_sale"`)} + } + if _, ok := _c.mutation.SortOrder(); !ok { + return &ValidationError{Name: "sort_order", err: errors.New(`ent: missing required field "SubscriptionPlan.sort_order"`)} + } + if _, ok := _c.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "SubscriptionPlan.created_at"`)} + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "SubscriptionPlan.updated_at"`)} + } + return nil +} + +func (_c *SubscriptionPlanCreate) sqlSave(ctx context.Context) (*SubscriptionPlan, 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 *SubscriptionPlanCreate) createSpec() (*SubscriptionPlan, *sqlgraph.CreateSpec) { + var ( + _node = &SubscriptionPlan{config: _c.config} + _spec = sqlgraph.NewCreateSpec(subscriptionplan.Table, sqlgraph.NewFieldSpec(subscriptionplan.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.GroupID(); ok { + _spec.SetField(subscriptionplan.FieldGroupID, field.TypeInt64, value) + _node.GroupID = value + } + if value, ok := _c.mutation.Name(); ok { + _spec.SetField(subscriptionplan.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := _c.mutation.Description(); ok { + _spec.SetField(subscriptionplan.FieldDescription, field.TypeString, value) + _node.Description = value + } + if value, ok := _c.mutation.Price(); ok { + _spec.SetField(subscriptionplan.FieldPrice, field.TypeFloat64, value) + _node.Price = value + } + if value, ok := _c.mutation.OriginalPrice(); ok { + _spec.SetField(subscriptionplan.FieldOriginalPrice, field.TypeFloat64, value) + _node.OriginalPrice = &value + } + if value, ok := _c.mutation.ValidityDays(); ok { + _spec.SetField(subscriptionplan.FieldValidityDays, field.TypeInt, value) + _node.ValidityDays = value + } + if value, ok := _c.mutation.ValidityUnit(); ok { + _spec.SetField(subscriptionplan.FieldValidityUnit, field.TypeString, value) + _node.ValidityUnit = value + } + if value, ok := _c.mutation.Features(); ok { + _spec.SetField(subscriptionplan.FieldFeatures, field.TypeString, value) + _node.Features = value + } + if value, ok := _c.mutation.ProductName(); ok { + _spec.SetField(subscriptionplan.FieldProductName, field.TypeString, value) + _node.ProductName = value + } + if value, ok := _c.mutation.ForSale(); ok { + _spec.SetField(subscriptionplan.FieldForSale, field.TypeBool, value) + _node.ForSale = value + } + if value, ok := _c.mutation.SortOrder(); ok { + _spec.SetField(subscriptionplan.FieldSortOrder, field.TypeInt, value) + _node.SortOrder = value + } + if value, ok := _c.mutation.CreatedAt(); ok { + _spec.SetField(subscriptionplan.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := _c.mutation.UpdatedAt(); ok { + _spec.SetField(subscriptionplan.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.SubscriptionPlan.Create(). +// SetGroupID(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.SubscriptionPlanUpsert) { +// SetGroupID(v+v). +// }). +// Exec(ctx) +func (_c *SubscriptionPlanCreate) OnConflict(opts ...sql.ConflictOption) *SubscriptionPlanUpsertOne { + _c.conflict = opts + return &SubscriptionPlanUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.SubscriptionPlan.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *SubscriptionPlanCreate) OnConflictColumns(columns ...string) *SubscriptionPlanUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &SubscriptionPlanUpsertOne{ + create: _c, + } +} + +type ( + // SubscriptionPlanUpsertOne is the builder for "upsert"-ing + // one SubscriptionPlan node. + SubscriptionPlanUpsertOne struct { + create *SubscriptionPlanCreate + } + + // SubscriptionPlanUpsert is the "OnConflict" setter. + SubscriptionPlanUpsert struct { + *sql.UpdateSet + } +) + +// SetGroupID sets the "group_id" field. +func (u *SubscriptionPlanUpsert) SetGroupID(v int64) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldGroupID, v) + return u +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateGroupID() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldGroupID) + return u +} + +// AddGroupID adds v to the "group_id" field. +func (u *SubscriptionPlanUpsert) AddGroupID(v int64) *SubscriptionPlanUpsert { + u.Add(subscriptionplan.FieldGroupID, v) + return u +} + +// SetName sets the "name" field. +func (u *SubscriptionPlanUpsert) SetName(v string) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldName, v) + return u +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateName() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldName) + return u +} + +// SetDescription sets the "description" field. +func (u *SubscriptionPlanUpsert) SetDescription(v string) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldDescription, v) + return u +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateDescription() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldDescription) + return u +} + +// SetPrice sets the "price" field. +func (u *SubscriptionPlanUpsert) SetPrice(v float64) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldPrice, v) + return u +} + +// UpdatePrice sets the "price" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdatePrice() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldPrice) + return u +} + +// AddPrice adds v to the "price" field. +func (u *SubscriptionPlanUpsert) AddPrice(v float64) *SubscriptionPlanUpsert { + u.Add(subscriptionplan.FieldPrice, v) + return u +} + +// SetOriginalPrice sets the "original_price" field. +func (u *SubscriptionPlanUpsert) SetOriginalPrice(v float64) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldOriginalPrice, v) + return u +} + +// UpdateOriginalPrice sets the "original_price" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateOriginalPrice() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldOriginalPrice) + return u +} + +// AddOriginalPrice adds v to the "original_price" field. +func (u *SubscriptionPlanUpsert) AddOriginalPrice(v float64) *SubscriptionPlanUpsert { + u.Add(subscriptionplan.FieldOriginalPrice, v) + return u +} + +// ClearOriginalPrice clears the value of the "original_price" field. +func (u *SubscriptionPlanUpsert) ClearOriginalPrice() *SubscriptionPlanUpsert { + u.SetNull(subscriptionplan.FieldOriginalPrice) + return u +} + +// SetValidityDays sets the "validity_days" field. +func (u *SubscriptionPlanUpsert) SetValidityDays(v int) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldValidityDays, v) + return u +} + +// UpdateValidityDays sets the "validity_days" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateValidityDays() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldValidityDays) + return u +} + +// AddValidityDays adds v to the "validity_days" field. +func (u *SubscriptionPlanUpsert) AddValidityDays(v int) *SubscriptionPlanUpsert { + u.Add(subscriptionplan.FieldValidityDays, v) + return u +} + +// SetValidityUnit sets the "validity_unit" field. +func (u *SubscriptionPlanUpsert) SetValidityUnit(v string) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldValidityUnit, v) + return u +} + +// UpdateValidityUnit sets the "validity_unit" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateValidityUnit() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldValidityUnit) + return u +} + +// SetFeatures sets the "features" field. +func (u *SubscriptionPlanUpsert) SetFeatures(v string) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldFeatures, v) + return u +} + +// UpdateFeatures sets the "features" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateFeatures() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldFeatures) + return u +} + +// SetProductName sets the "product_name" field. +func (u *SubscriptionPlanUpsert) SetProductName(v string) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldProductName, v) + return u +} + +// UpdateProductName sets the "product_name" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateProductName() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldProductName) + return u +} + +// SetForSale sets the "for_sale" field. +func (u *SubscriptionPlanUpsert) SetForSale(v bool) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldForSale, v) + return u +} + +// UpdateForSale sets the "for_sale" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateForSale() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldForSale) + return u +} + +// SetSortOrder sets the "sort_order" field. +func (u *SubscriptionPlanUpsert) SetSortOrder(v int) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldSortOrder, v) + return u +} + +// UpdateSortOrder sets the "sort_order" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateSortOrder() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldSortOrder) + return u +} + +// AddSortOrder adds v to the "sort_order" field. +func (u *SubscriptionPlanUpsert) AddSortOrder(v int) *SubscriptionPlanUpsert { + u.Add(subscriptionplan.FieldSortOrder, v) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *SubscriptionPlanUpsert) SetUpdatedAt(v time.Time) *SubscriptionPlanUpsert { + u.Set(subscriptionplan.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *SubscriptionPlanUpsert) UpdateUpdatedAt() *SubscriptionPlanUpsert { + u.SetExcluded(subscriptionplan.FieldUpdatedAt) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.SubscriptionPlan.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *SubscriptionPlanUpsertOne) UpdateNewValues() *SubscriptionPlanUpsertOne { + 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(subscriptionplan.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.SubscriptionPlan.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *SubscriptionPlanUpsertOne) Ignore() *SubscriptionPlanUpsertOne { + 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 *SubscriptionPlanUpsertOne) DoNothing() *SubscriptionPlanUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the SubscriptionPlanCreate.OnConflict +// documentation for more info. +func (u *SubscriptionPlanUpsertOne) Update(set func(*SubscriptionPlanUpsert)) *SubscriptionPlanUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&SubscriptionPlanUpsert{UpdateSet: update}) + })) + return u +} + +// SetGroupID sets the "group_id" field. +func (u *SubscriptionPlanUpsertOne) SetGroupID(v int64) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetGroupID(v) + }) +} + +// AddGroupID adds v to the "group_id" field. +func (u *SubscriptionPlanUpsertOne) AddGroupID(v int64) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddGroupID(v) + }) +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateGroupID() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateGroupID() + }) +} + +// SetName sets the "name" field. +func (u *SubscriptionPlanUpsertOne) SetName(v string) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateName() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateName() + }) +} + +// SetDescription sets the "description" field. +func (u *SubscriptionPlanUpsertOne) SetDescription(v string) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetDescription(v) + }) +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateDescription() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateDescription() + }) +} + +// SetPrice sets the "price" field. +func (u *SubscriptionPlanUpsertOne) SetPrice(v float64) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetPrice(v) + }) +} + +// AddPrice adds v to the "price" field. +func (u *SubscriptionPlanUpsertOne) AddPrice(v float64) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddPrice(v) + }) +} + +// UpdatePrice sets the "price" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdatePrice() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdatePrice() + }) +} + +// SetOriginalPrice sets the "original_price" field. +func (u *SubscriptionPlanUpsertOne) SetOriginalPrice(v float64) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetOriginalPrice(v) + }) +} + +// AddOriginalPrice adds v to the "original_price" field. +func (u *SubscriptionPlanUpsertOne) AddOriginalPrice(v float64) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddOriginalPrice(v) + }) +} + +// UpdateOriginalPrice sets the "original_price" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateOriginalPrice() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateOriginalPrice() + }) +} + +// ClearOriginalPrice clears the value of the "original_price" field. +func (u *SubscriptionPlanUpsertOne) ClearOriginalPrice() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.ClearOriginalPrice() + }) +} + +// SetValidityDays sets the "validity_days" field. +func (u *SubscriptionPlanUpsertOne) SetValidityDays(v int) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetValidityDays(v) + }) +} + +// AddValidityDays adds v to the "validity_days" field. +func (u *SubscriptionPlanUpsertOne) AddValidityDays(v int) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddValidityDays(v) + }) +} + +// UpdateValidityDays sets the "validity_days" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateValidityDays() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateValidityDays() + }) +} + +// SetValidityUnit sets the "validity_unit" field. +func (u *SubscriptionPlanUpsertOne) SetValidityUnit(v string) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetValidityUnit(v) + }) +} + +// UpdateValidityUnit sets the "validity_unit" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateValidityUnit() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateValidityUnit() + }) +} + +// SetFeatures sets the "features" field. +func (u *SubscriptionPlanUpsertOne) SetFeatures(v string) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetFeatures(v) + }) +} + +// UpdateFeatures sets the "features" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateFeatures() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateFeatures() + }) +} + +// SetProductName sets the "product_name" field. +func (u *SubscriptionPlanUpsertOne) SetProductName(v string) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetProductName(v) + }) +} + +// UpdateProductName sets the "product_name" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateProductName() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateProductName() + }) +} + +// SetForSale sets the "for_sale" field. +func (u *SubscriptionPlanUpsertOne) SetForSale(v bool) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetForSale(v) + }) +} + +// UpdateForSale sets the "for_sale" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateForSale() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateForSale() + }) +} + +// SetSortOrder sets the "sort_order" field. +func (u *SubscriptionPlanUpsertOne) SetSortOrder(v int) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetSortOrder(v) + }) +} + +// AddSortOrder adds v to the "sort_order" field. +func (u *SubscriptionPlanUpsertOne) AddSortOrder(v int) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddSortOrder(v) + }) +} + +// UpdateSortOrder sets the "sort_order" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateSortOrder() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateSortOrder() + }) +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *SubscriptionPlanUpsertOne) SetUpdatedAt(v time.Time) *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertOne) UpdateUpdatedAt() *SubscriptionPlanUpsertOne { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateUpdatedAt() + }) +} + +// Exec executes the query. +func (u *SubscriptionPlanUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for SubscriptionPlanCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *SubscriptionPlanUpsertOne) 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 *SubscriptionPlanUpsertOne) 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 *SubscriptionPlanUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// SubscriptionPlanCreateBulk is the builder for creating many SubscriptionPlan entities in bulk. +type SubscriptionPlanCreateBulk struct { + config + err error + builders []*SubscriptionPlanCreate + conflict []sql.ConflictOption +} + +// Save creates the SubscriptionPlan entities in the database. +func (_c *SubscriptionPlanCreateBulk) Save(ctx context.Context) ([]*SubscriptionPlan, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*SubscriptionPlan, 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.(*SubscriptionPlanMutation) + 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 *SubscriptionPlanCreateBulk) SaveX(ctx context.Context) []*SubscriptionPlan { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *SubscriptionPlanCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *SubscriptionPlanCreateBulk) 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.SubscriptionPlan.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.SubscriptionPlanUpsert) { +// SetGroupID(v+v). +// }). +// Exec(ctx) +func (_c *SubscriptionPlanCreateBulk) OnConflict(opts ...sql.ConflictOption) *SubscriptionPlanUpsertBulk { + _c.conflict = opts + return &SubscriptionPlanUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.SubscriptionPlan.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *SubscriptionPlanCreateBulk) OnConflictColumns(columns ...string) *SubscriptionPlanUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &SubscriptionPlanUpsertBulk{ + create: _c, + } +} + +// SubscriptionPlanUpsertBulk is the builder for "upsert"-ing +// a bulk of SubscriptionPlan nodes. +type SubscriptionPlanUpsertBulk struct { + create *SubscriptionPlanCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.SubscriptionPlan.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *SubscriptionPlanUpsertBulk) UpdateNewValues() *SubscriptionPlanUpsertBulk { + 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(subscriptionplan.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.SubscriptionPlan.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *SubscriptionPlanUpsertBulk) Ignore() *SubscriptionPlanUpsertBulk { + 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 *SubscriptionPlanUpsertBulk) DoNothing() *SubscriptionPlanUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the SubscriptionPlanCreateBulk.OnConflict +// documentation for more info. +func (u *SubscriptionPlanUpsertBulk) Update(set func(*SubscriptionPlanUpsert)) *SubscriptionPlanUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&SubscriptionPlanUpsert{UpdateSet: update}) + })) + return u +} + +// SetGroupID sets the "group_id" field. +func (u *SubscriptionPlanUpsertBulk) SetGroupID(v int64) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetGroupID(v) + }) +} + +// AddGroupID adds v to the "group_id" field. +func (u *SubscriptionPlanUpsertBulk) AddGroupID(v int64) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddGroupID(v) + }) +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateGroupID() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateGroupID() + }) +} + +// SetName sets the "name" field. +func (u *SubscriptionPlanUpsertBulk) SetName(v string) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateName() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateName() + }) +} + +// SetDescription sets the "description" field. +func (u *SubscriptionPlanUpsertBulk) SetDescription(v string) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetDescription(v) + }) +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateDescription() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateDescription() + }) +} + +// SetPrice sets the "price" field. +func (u *SubscriptionPlanUpsertBulk) SetPrice(v float64) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetPrice(v) + }) +} + +// AddPrice adds v to the "price" field. +func (u *SubscriptionPlanUpsertBulk) AddPrice(v float64) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddPrice(v) + }) +} + +// UpdatePrice sets the "price" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdatePrice() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdatePrice() + }) +} + +// SetOriginalPrice sets the "original_price" field. +func (u *SubscriptionPlanUpsertBulk) SetOriginalPrice(v float64) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetOriginalPrice(v) + }) +} + +// AddOriginalPrice adds v to the "original_price" field. +func (u *SubscriptionPlanUpsertBulk) AddOriginalPrice(v float64) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddOriginalPrice(v) + }) +} + +// UpdateOriginalPrice sets the "original_price" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateOriginalPrice() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateOriginalPrice() + }) +} + +// ClearOriginalPrice clears the value of the "original_price" field. +func (u *SubscriptionPlanUpsertBulk) ClearOriginalPrice() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.ClearOriginalPrice() + }) +} + +// SetValidityDays sets the "validity_days" field. +func (u *SubscriptionPlanUpsertBulk) SetValidityDays(v int) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetValidityDays(v) + }) +} + +// AddValidityDays adds v to the "validity_days" field. +func (u *SubscriptionPlanUpsertBulk) AddValidityDays(v int) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddValidityDays(v) + }) +} + +// UpdateValidityDays sets the "validity_days" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateValidityDays() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateValidityDays() + }) +} + +// SetValidityUnit sets the "validity_unit" field. +func (u *SubscriptionPlanUpsertBulk) SetValidityUnit(v string) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetValidityUnit(v) + }) +} + +// UpdateValidityUnit sets the "validity_unit" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateValidityUnit() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateValidityUnit() + }) +} + +// SetFeatures sets the "features" field. +func (u *SubscriptionPlanUpsertBulk) SetFeatures(v string) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetFeatures(v) + }) +} + +// UpdateFeatures sets the "features" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateFeatures() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateFeatures() + }) +} + +// SetProductName sets the "product_name" field. +func (u *SubscriptionPlanUpsertBulk) SetProductName(v string) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetProductName(v) + }) +} + +// UpdateProductName sets the "product_name" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateProductName() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateProductName() + }) +} + +// SetForSale sets the "for_sale" field. +func (u *SubscriptionPlanUpsertBulk) SetForSale(v bool) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetForSale(v) + }) +} + +// UpdateForSale sets the "for_sale" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateForSale() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateForSale() + }) +} + +// SetSortOrder sets the "sort_order" field. +func (u *SubscriptionPlanUpsertBulk) SetSortOrder(v int) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetSortOrder(v) + }) +} + +// AddSortOrder adds v to the "sort_order" field. +func (u *SubscriptionPlanUpsertBulk) AddSortOrder(v int) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.AddSortOrder(v) + }) +} + +// UpdateSortOrder sets the "sort_order" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateSortOrder() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateSortOrder() + }) +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *SubscriptionPlanUpsertBulk) SetUpdatedAt(v time.Time) *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *SubscriptionPlanUpsertBulk) UpdateUpdatedAt() *SubscriptionPlanUpsertBulk { + return u.Update(func(s *SubscriptionPlanUpsert) { + s.UpdateUpdatedAt() + }) +} + +// Exec executes the query. +func (u *SubscriptionPlanUpsertBulk) 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 SubscriptionPlanCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for SubscriptionPlanCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *SubscriptionPlanUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/subscriptionplan_delete.go b/backend/ent/subscriptionplan_delete.go new file mode 100644 index 00000000..90c71239 --- /dev/null +++ b/backend/ent/subscriptionplan_delete.go @@ -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) + } +} diff --git a/backend/ent/subscriptionplan_query.go b/backend/ent/subscriptionplan_query.go new file mode 100644 index 00000000..6c301dcd --- /dev/null +++ b/backend/ent/subscriptionplan_query.go @@ -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) +} diff --git a/backend/ent/subscriptionplan_update.go b/backend/ent/subscriptionplan_update.go new file mode 100644 index 00000000..c9225d0f --- /dev/null +++ b/backend/ent/subscriptionplan_update.go @@ -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 +} diff --git a/backend/ent/tx.go b/backend/ent/tx.go index b5aea447..bb3139d5 100644 --- a/backend/ent/tx.go +++ b/backend/ent/tx.go @@ -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) diff --git a/backend/ent/user.go b/backend/ent/user.go index 2435aa1b..a0eef2ba 100644 --- a/backend/ent/user.go +++ b/backend/ent/user.go @@ -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) diff --git a/backend/ent/user/user.go b/backend/ent/user/user.go index ae9418ff..338518a8 100644 --- a/backend/ent/user/user.go +++ b/backend/ent/user/user.go @@ -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), diff --git a/backend/ent/user/where.go b/backend/ent/user/where.go index 1de61037..b1d1000f 100644 --- a/backend/ent/user/where.go +++ b/backend/ent/user/where.go @@ -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) { diff --git a/backend/ent/user_create.go b/backend/ent/user_create.go index f862a580..7f1c5df1 100644 --- a/backend/ent/user_create.go +++ b/backend/ent/user_create.go @@ -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 } diff --git a/backend/ent/user_query.go b/backend/ent/user_query.go index 4b56e16f..113d87ac 100644 --- a/backend/ent/user_query.go +++ b/backend/ent/user_query.go @@ -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) diff --git a/backend/ent/user_update.go b/backend/ent/user_update.go index 80222c92..8107c980 100644 --- a/backend/ent/user_update.go +++ b/backend/ent/user_update.go @@ -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 diff --git a/backend/go.mod b/backend/go.mod index c4fc52f1..66b6cc25 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -27,12 +27,16 @@ require ( github.com/refraction-networking/utls v1.8.2 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil/v4 v4.25.6 + github.com/shopspring/decimal v1.4.0 + github.com/smartwalle/alipay/v3 v3.2.29 github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.11.1 + github.com/stripe/stripe-go/v85 v85.0.0 github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 github.com/testcontainers/testcontainers-go/modules/redis v0.40.0 github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 + github.com/wechatpay-apiv3/wechatpay-go v0.2.21 github.com/zeromicro/go-zero v1.9.4 go.uber.org/zap v1.24.0 golang.org/x/crypto v0.48.0 @@ -99,6 +103,7 @@ require ( github.com/goccy/go-json v0.10.2 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect + github.com/google/subcommands v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl/v2 v2.18.1 // indirect @@ -137,6 +142,9 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // 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 @@ -167,6 +175,7 @@ require ( golang.org/x/mod v0.32.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect + golang.org/x/tools v0.41.0 // indirect google.golang.org/grpc v1.75.1 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/backend/go.sum b/backend/go.sum index 996a4b6d..e4496f2c 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -14,6 +14,8 @@ 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 h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= +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= @@ -160,6 +162,8 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +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.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= @@ -288,8 +292,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= @@ -317,6 +331,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/v85 v85.0.0 h1:HMlFJXW6I/9WvkeSAtj8V7dI5pzeDu4gS1TaqR1ccI4= +github.com/stripe/stripe-go/v85 v85.0.0/go.mod h1:5P+HGFenpWgak27T5Is6JMsmDfUC1yJnjhhmquz7kXw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= @@ -342,6 +358,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= diff --git a/backend/internal/handler/admin/payment_handler.go b/backend/internal/handler/admin/payment_handler.go new file mode 100644 index 00000000..b0ed6aed --- /dev/null +++ b/backend/internal/handler/admin/payment_handler.go @@ -0,0 +1,323 @@ +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"), + Keyword: c.Query("keyword"), + }) + 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, ok := parseIDParam(c, "id") + if !ok { + 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, ok := parseIDParam(c, "id") + if !ok { + 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, ok := parseIDParam(c, "id") + if !ok { + 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:"deduct_balance"` +} + +// ProcessRefund processes a refund for an order (admin). +// POST /api/v1/admin/payment/orders/:id/refund +func (h *PaymentHandler) ProcessRefund(c *gin.Context) { + orderID, ok := parseIDParam(c, "id") + if !ok { + 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, ok := parseIDParam(c, "id") + if !ok { + 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, ok := parseIDParam(c, "id") + if !ok { + 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.ListProviderInstancesWithConfig(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 + } + h.paymentService.RefreshProviders(c.Request.Context()) + 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, ok := parseIDParam(c, "id") + if !ok { + 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 + } + h.paymentService.RefreshProviders(c.Request.Context()) + 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, ok := parseIDParam(c, "id") + if !ok { + return + } + if err := h.configService.DeleteProviderInstance(c.Request.Context(), id); err != nil { + response.ErrorFrom(c, err) + return + } + h.paymentService.RefreshProviders(c.Request.Context()) + response.Success(c, gin.H{"message": "deleted"}) +} + +// parseIDParam parses an int64 path parameter. +// Returns the parsed ID and true on success; on failure it writes a BadRequest response and returns false. +func parseIDParam(c *gin.Context, paramName string) (int64, bool) { + id, err := strconv.ParseInt(c.Param(paramName), 10, 64) + if err != nil { + response.BadRequest(c, "Invalid "+paramName) + return 0, false + } + return id, true +} + +// --- 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"}) +} diff --git a/backend/internal/handler/admin/setting_handler.go b/backend/internal/handler/admin/setting_handler.go index abae75d9..cbda151a 100644 --- a/backend/internal/handler/admin/setting_handler.go +++ b/backend/internal/handler/admin/setting_handler.go @@ -46,19 +46,23 @@ func scopesContainOpenID(scopes string) bool { // SettingHandler 系统设置处理器 type SettingHandler struct { - settingService *service.SettingService - emailService *service.EmailService - turnstileService *service.TurnstileService - opsService *service.OpsService + settingService *service.SettingService + emailService *service.EmailService + turnstileService *service.TurnstileService + opsService *service.OpsService + paymentConfigService *service.PaymentConfigService + paymentService *service.PaymentService } // NewSettingHandler 创建系统设置处理器 -func NewSettingHandler(settingService *service.SettingService, emailService *service.EmailService, turnstileService *service.TurnstileService, opsService *service.OpsService) *SettingHandler { +func NewSettingHandler(settingService *service.SettingService, emailService *service.EmailService, turnstileService *service.TurnstileService, opsService *service.OpsService, paymentConfigService *service.PaymentConfigService, paymentService *service.PaymentService) *SettingHandler { return &SettingHandler{ - settingService: settingService, - emailService: emailService, - turnstileService: turnstileService, - opsService: opsService, + settingService: settingService, + emailService: emailService, + turnstileService: turnstileService, + opsService: opsService, + paymentConfigService: paymentConfigService, + paymentService: paymentService, } } @@ -81,6 +85,15 @@ func (h *SettingHandler) GetSettings(c *gin.Context) { }) } + // Load payment config + var paymentCfg *service.PaymentConfig + if h.paymentConfigService != nil { + paymentCfg, _ = h.paymentConfigService.GetPaymentConfig(c.Request.Context()) + } + if paymentCfg == nil { + paymentCfg = &service.PaymentConfig{} + } + response.Success(c, dto.SystemSettings{ RegistrationEnabled: settings.RegistrationEnabled, EmailVerifyEnabled: settings.EmailVerifyEnabled, @@ -160,6 +173,24 @@ func (h *SettingHandler) GetSettings(c *gin.Context) { EnableFingerprintUnification: settings.EnableFingerprintUnification, EnableMetadataPassthrough: settings.EnableMetadataPassthrough, EnableCCHSigning: settings.EnableCCHSigning, + PaymentEnabled: paymentCfg.Enabled, + PaymentMinAmount: paymentCfg.MinAmount, + PaymentMaxAmount: paymentCfg.MaxAmount, + PaymentDailyLimit: paymentCfg.DailyLimit, + PaymentOrderTimeoutMin: paymentCfg.OrderTimeoutMin, + PaymentMaxPendingOrders: paymentCfg.MaxPendingOrders, + PaymentEnabledTypes: paymentCfg.EnabledTypes, + PaymentBalanceDisabled: paymentCfg.BalanceDisabled, + PaymentLoadBalanceStrat: paymentCfg.LoadBalanceStrategy, + PaymentProductNamePrefix: paymentCfg.ProductNamePrefix, + PaymentProductNameSuffix: paymentCfg.ProductNameSuffix, + PaymentHelpImageURL: paymentCfg.HelpImageURL, + PaymentHelpText: paymentCfg.HelpText, + PaymentCancelRateLimitEnabled: paymentCfg.CancelRateLimitEnabled, + PaymentCancelRateLimitMax: paymentCfg.CancelRateLimitMax, + PaymentCancelRateLimitWindow: paymentCfg.CancelRateLimitWindow, + PaymentCancelRateLimitUnit: paymentCfg.CancelRateLimitUnit, + PaymentCancelRateLimitMode: paymentCfg.CancelRateLimitMode, }) } @@ -268,6 +299,28 @@ type UpdateSettingsRequest struct { EnableFingerprintUnification *bool `json:"enable_fingerprint_unification"` EnableMetadataPassthrough *bool `json:"enable_metadata_passthrough"` EnableCCHSigning *bool `json:"enable_cch_signing"` + + // Payment configuration (integrated into settings, full replace) + PaymentEnabled *bool `json:"payment_enabled"` + PaymentMinAmount *float64 `json:"payment_min_amount"` + PaymentMaxAmount *float64 `json:"payment_max_amount"` + PaymentDailyLimit *float64 `json:"payment_daily_limit"` + PaymentOrderTimeoutMin *int `json:"payment_order_timeout_minutes"` + PaymentMaxPendingOrders *int `json:"payment_max_pending_orders"` + PaymentEnabledTypes []string `json:"payment_enabled_types"` + PaymentBalanceDisabled *bool `json:"payment_balance_disabled"` + PaymentLoadBalanceStrat *string `json:"payment_load_balance_strategy"` + PaymentProductNamePrefix *string `json:"payment_product_name_prefix"` + PaymentProductNameSuffix *string `json:"payment_product_name_suffix"` + PaymentHelpImageURL *string `json:"payment_help_image_url"` + PaymentHelpText *string `json:"payment_help_text"` + + // Cancel rate limit + PaymentCancelRateLimitEnabled *bool `json:"payment_cancel_rate_limit_enabled"` + PaymentCancelRateLimitMax *int `json:"payment_cancel_rate_limit_max"` + PaymentCancelRateLimitWindow *int `json:"payment_cancel_rate_limit_window"` + PaymentCancelRateLimitUnit *string `json:"payment_cancel_rate_limit_unit"` + PaymentCancelRateLimitMode *string `json:"payment_cancel_rate_limit_window_mode"` } // UpdateSettings 更新系统设置 @@ -822,6 +875,39 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { return } + // Update payment configuration (integrated into system settings). + // Skip if no payment fields were provided (prevents accidental wipe). + if h.paymentConfigService != nil && hasPaymentFields(req) { + paymentReq := service.UpdatePaymentConfigRequest{ + Enabled: req.PaymentEnabled, + MinAmount: req.PaymentMinAmount, + MaxAmount: req.PaymentMaxAmount, + DailyLimit: req.PaymentDailyLimit, + OrderTimeoutMin: req.PaymentOrderTimeoutMin, + MaxPendingOrders: req.PaymentMaxPendingOrders, + EnabledTypes: req.PaymentEnabledTypes, + BalanceDisabled: req.PaymentBalanceDisabled, + LoadBalanceStrategy: req.PaymentLoadBalanceStrat, + ProductNamePrefix: req.PaymentProductNamePrefix, + ProductNameSuffix: req.PaymentProductNameSuffix, + HelpImageURL: req.PaymentHelpImageURL, + HelpText: req.PaymentHelpText, + CancelRateLimitEnabled: req.PaymentCancelRateLimitEnabled, + CancelRateLimitMax: req.PaymentCancelRateLimitMax, + CancelRateLimitWindow: req.PaymentCancelRateLimitWindow, + CancelRateLimitUnit: req.PaymentCancelRateLimitUnit, + CancelRateLimitMode: req.PaymentCancelRateLimitMode, + } + if err := h.paymentConfigService.UpdatePaymentConfig(c.Request.Context(), paymentReq); err != nil { + response.ErrorFrom(c, err) + return + } + // Refresh in-memory provider registry so config changes take effect immediately + if h.paymentService != nil { + h.paymentService.RefreshProviders(c.Request.Context()) + } + } + h.auditSettingsUpdate(c, previousSettings, settings, req) // 重新获取设置返回 @@ -838,6 +924,15 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { }) } + // Reload payment config for response + var updatedPaymentCfg *service.PaymentConfig + if h.paymentConfigService != nil { + updatedPaymentCfg, _ = h.paymentConfigService.GetPaymentConfig(c.Request.Context()) + } + if updatedPaymentCfg == nil { + updatedPaymentCfg = &service.PaymentConfig{} + } + response.Success(c, dto.SystemSettings{ RegistrationEnabled: updatedSettings.RegistrationEnabled, EmailVerifyEnabled: updatedSettings.EmailVerifyEnabled, @@ -917,9 +1012,40 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { EnableFingerprintUnification: updatedSettings.EnableFingerprintUnification, EnableMetadataPassthrough: updatedSettings.EnableMetadataPassthrough, EnableCCHSigning: updatedSettings.EnableCCHSigning, + PaymentEnabled: updatedPaymentCfg.Enabled, + PaymentMinAmount: updatedPaymentCfg.MinAmount, + PaymentMaxAmount: updatedPaymentCfg.MaxAmount, + PaymentDailyLimit: updatedPaymentCfg.DailyLimit, + PaymentOrderTimeoutMin: updatedPaymentCfg.OrderTimeoutMin, + PaymentMaxPendingOrders: updatedPaymentCfg.MaxPendingOrders, + PaymentEnabledTypes: updatedPaymentCfg.EnabledTypes, + PaymentBalanceDisabled: updatedPaymentCfg.BalanceDisabled, + PaymentLoadBalanceStrat: updatedPaymentCfg.LoadBalanceStrategy, + PaymentProductNamePrefix: updatedPaymentCfg.ProductNamePrefix, + PaymentProductNameSuffix: updatedPaymentCfg.ProductNameSuffix, + PaymentHelpImageURL: updatedPaymentCfg.HelpImageURL, + PaymentHelpText: updatedPaymentCfg.HelpText, + PaymentCancelRateLimitEnabled: updatedPaymentCfg.CancelRateLimitEnabled, + PaymentCancelRateLimitMax: updatedPaymentCfg.CancelRateLimitMax, + PaymentCancelRateLimitWindow: updatedPaymentCfg.CancelRateLimitWindow, + PaymentCancelRateLimitUnit: updatedPaymentCfg.CancelRateLimitUnit, + PaymentCancelRateLimitMode: updatedPaymentCfg.CancelRateLimitMode, }) } +// hasPaymentFields returns true if any payment-related field was explicitly provided. +func hasPaymentFields(req UpdateSettingsRequest) bool { + return req.PaymentEnabled != nil || req.PaymentMinAmount != nil || + req.PaymentMaxAmount != nil || req.PaymentDailyLimit != nil || + req.PaymentOrderTimeoutMin != nil || req.PaymentMaxPendingOrders != nil || + req.PaymentEnabledTypes != nil || req.PaymentBalanceDisabled != nil || + req.PaymentLoadBalanceStrat != nil || req.PaymentProductNamePrefix != nil || + req.PaymentProductNameSuffix != nil || req.PaymentHelpImageURL != nil || + req.PaymentHelpText != nil || req.PaymentCancelRateLimitEnabled != nil || + req.PaymentCancelRateLimitMax != nil || req.PaymentCancelRateLimitWindow != nil || + req.PaymentCancelRateLimitUnit != nil || req.PaymentCancelRateLimitMode != nil +} + func (h *SettingHandler) auditSettingsUpdate(c *gin.Context, before *service.SystemSettings, after *service.SystemSettings, req UpdateSettingsRequest) { if before == nil || after == nil { return diff --git a/backend/internal/handler/dto/settings.go b/backend/internal/handler/dto/settings.go index c8fc3b5d..a791051d 100644 --- a/backend/internal/handler/dto/settings.go +++ b/backend/internal/handler/dto/settings.go @@ -121,6 +121,28 @@ type SystemSettings struct { EnableFingerprintUnification bool `json:"enable_fingerprint_unification"` EnableMetadataPassthrough bool `json:"enable_metadata_passthrough"` EnableCCHSigning bool `json:"enable_cch_signing"` + + // Payment configuration + PaymentEnabled bool `json:"payment_enabled"` + PaymentMinAmount float64 `json:"payment_min_amount"` + PaymentMaxAmount float64 `json:"payment_max_amount"` + PaymentDailyLimit float64 `json:"payment_daily_limit"` + PaymentOrderTimeoutMin int `json:"payment_order_timeout_minutes"` + PaymentMaxPendingOrders int `json:"payment_max_pending_orders"` + PaymentEnabledTypes []string `json:"payment_enabled_types"` + PaymentBalanceDisabled bool `json:"payment_balance_disabled"` + PaymentLoadBalanceStrat string `json:"payment_load_balance_strategy"` + PaymentProductNamePrefix string `json:"payment_product_name_prefix"` + PaymentProductNameSuffix string `json:"payment_product_name_suffix"` + PaymentHelpImageURL string `json:"payment_help_image_url"` + PaymentHelpText string `json:"payment_help_text"` + + // Cancel rate limit + PaymentCancelRateLimitEnabled bool `json:"payment_cancel_rate_limit_enabled"` + PaymentCancelRateLimitMax int `json:"payment_cancel_rate_limit_max"` + PaymentCancelRateLimitWindow int `json:"payment_cancel_rate_limit_window"` + PaymentCancelRateLimitUnit string `json:"payment_cancel_rate_limit_unit"` + PaymentCancelRateLimitMode string `json:"payment_cancel_rate_limit_window_mode"` } type DefaultSubscriptionSetting struct { @@ -155,6 +177,7 @@ type PublicSettings struct { OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"` SoraClientEnabled bool `json:"sora_client_enabled"` BackendModeEnabled bool `json:"backend_mode_enabled"` + PaymentEnabled bool `json:"payment_enabled"` Version string `json:"version"` } diff --git a/backend/internal/handler/handler.go b/backend/internal/handler/handler.go index d4c349fb..906a74f1 100644 --- a/backend/internal/handler/handler.go +++ b/backend/internal/handler/handler.go @@ -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 diff --git a/backend/internal/handler/payment_handler.go b/backend/internal/handler/payment_handler.go new file mode 100644 index 00000000..e0563a42 --- /dev/null +++ b/backend/internal/handler/payment_handler.go @@ -0,0 +1,416 @@ +package handler + +import ( + "strconv" + "strings" + + "github.com/Wei-Shaw/sub2api/internal/pkg/pagination" + "github.com/Wei-Shaw/sub2api/internal/pkg/response" + middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware" + "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 + } + // Enrich plans with group platform for frontend color coding + type planWithPlatform struct { + ID int64 `json:"id"` + GroupID int64 `json:"group_id"` + GroupPlatform string `json:"group_platform"` + Name string `json:"name"` + Description string `json:"description"` + Price float64 `json:"price"` + OriginalPrice *float64 `json:"original_price,omitempty"` + ValidityDays int `json:"validity_days"` + ValidityUnit string `json:"validity_unit"` + Features string `json:"features"` + ProductName string `json:"product_name"` + ForSale bool `json:"for_sale"` + SortOrder int `json:"sort_order"` + } + platformMap := h.configService.GetGroupPlatformMap(c.Request.Context(), plans) + result := make([]planWithPlatform, 0, len(plans)) + for _, p := range plans { + result = append(result, planWithPlatform{ + ID: int64(p.ID), GroupID: p.GroupID, GroupPlatform: platformMap[p.GroupID], + Name: p.Name, Description: p.Description, Price: p.Price, OriginalPrice: p.OriginalPrice, + ValidityDays: p.ValidityDays, ValidityUnit: p.ValidityUnit, Features: p.Features, + ProductName: p.ProductName, ForSale: p.ForSale, SortOrder: p.SortOrder, + }) + } + response.Success(c, result) +} + +// 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) +} + +// GetCheckoutInfo returns all data the payment page needs in a single call: +// payment methods with limits, subscription plans, and configuration. +// GET /api/v1/payment/checkout-info +func (h *PaymentHandler) GetCheckoutInfo(c *gin.Context) { + ctx := c.Request.Context() + + // Fetch limits (methods + global range) + limitsResp, err := h.configService.GetAvailableMethodLimits(ctx) + if err != nil { + response.ErrorFrom(c, err) + return + } + + // Fetch payment config + cfg, err := h.configService.GetPaymentConfig(ctx) + if err != nil { + response.ErrorFrom(c, err) + return + } + + // Fetch plans with group info + plans, _ := h.configService.ListPlansForSale(ctx) + groupInfo := h.configService.GetGroupInfoMap(ctx, plans) + planList := make([]checkoutPlan, 0, len(plans)) + for _, p := range plans { + gi := groupInfo[p.GroupID] + planList = append(planList, checkoutPlan{ + ID: int64(p.ID), GroupID: p.GroupID, + GroupPlatform: gi.Platform, GroupName: gi.Name, + RateMultiplier: gi.RateMultiplier, DailyLimitUSD: gi.DailyLimitUSD, + WeeklyLimitUSD: gi.WeeklyLimitUSD, MonthlyLimitUSD: gi.MonthlyLimitUSD, + ModelScopes: gi.ModelScopes, + Name: p.Name, Description: p.Description, Price: p.Price, OriginalPrice: p.OriginalPrice, + ValidityDays: p.ValidityDays, ValidityUnit: p.ValidityUnit, Features: parseFeatures(p.Features), + ProductName: p.ProductName, + }) + } + + response.Success(c, checkoutInfoResponse{ + Methods: limitsResp.Methods, + GlobalMin: limitsResp.GlobalMin, + GlobalMax: limitsResp.GlobalMax, + Plans: planList, + BalanceDisabled: cfg.BalanceDisabled, + HelpText: cfg.HelpText, + HelpImageURL: cfg.HelpImageURL, + StripePublishableKey: cfg.StripePublishableKey, + }) +} + +type checkoutInfoResponse struct { + Methods map[string]service.MethodLimits `json:"methods"` + GlobalMin float64 `json:"global_min"` + GlobalMax float64 `json:"global_max"` + Plans []checkoutPlan `json:"plans"` + BalanceDisabled bool `json:"balance_disabled"` + HelpText string `json:"help_text"` + HelpImageURL string `json:"help_image_url"` + StripePublishableKey string `json:"stripe_publishable_key"` +} + +type checkoutPlan struct { + ID int64 `json:"id"` + GroupID int64 `json:"group_id"` + GroupPlatform string `json:"group_platform"` + GroupName string `json:"group_name"` + RateMultiplier float64 `json:"rate_multiplier"` + DailyLimitUSD *float64 `json:"daily_limit_usd"` + WeeklyLimitUSD *float64 `json:"weekly_limit_usd"` + MonthlyLimitUSD *float64 `json:"monthly_limit_usd"` + ModelScopes []string `json:"supported_model_scopes"` + Name string `json:"name"` + Description string `json:"description"` + Price float64 `json:"price"` + OriginalPrice *float64 `json:"original_price,omitempty"` + ValidityDays int `json:"validity_days"` + ValidityUnit string `json:"validity_unit"` + Features []string `json:"features"` + ProductName string `json:"product_name"` +} + +// parseFeatures splits a newline-separated features string into a string slice. +func parseFeatures(raw string) []string { + if raw == "" { + return []string{} + } + var out []string + for _, line := range strings.Split(raw, "\n") { + if s := strings.TrimSpace(line); s != "" { + out = append(out, s) + } + } + if out == nil { + return []string{} + } + return out +} + +// GetLimits returns per-payment-type limits derived from enabled provider instances. +// GET /api/v1/payment/limits +func (h *PaymentHandler) GetLimits(c *gin.Context) { + resp, err := h.configService.GetAvailableMethodLimits(c.Request.Context()) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, resp) +} + +// CreateOrderRequest is the request body for creating a payment order. +type CreateOrderRequest struct { + Amount float64 `json:"amount"` + PaymentType string `json:"payment_type" binding:"required"` + OrderType string `json:"order_type"` + PlanID int64 `json:"plan_id"` +} + +// CreateOrder creates a new payment order. +// POST /api/v1/payment/orders +func (h *PaymentHandler) CreateOrder(c *gin.Context) { + subject, ok := requireAuth(c) + if !ok { + 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 := requireAuth(c) + if !ok { + 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 := requireAuth(c) + if !ok { + 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 := requireAuth(c) + if !ok { + 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 := requireAuth(c) + if !ok { + 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"}) +} + +// VerifyOrderRequest is the request body for verifying a payment order. +type VerifyOrderRequest struct { + OutTradeNo string `json:"out_trade_no" binding:"required"` +} + +// VerifyOrder actively queries the upstream payment provider to check +// if payment was made, and processes it if so. +// POST /api/v1/payment/orders/verify +func (h *PaymentHandler) VerifyOrder(c *gin.Context) { + subject, ok := requireAuth(c) + if !ok { + return + } + + var req VerifyOrderRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.BadRequest(c, "Invalid request: "+err.Error()) + return + } + + order, err := h.paymentService.VerifyOrderByOutTradeNo(c.Request.Context(), req.OutTradeNo, subject.UserID) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, order) +} + +// PublicOrderResult is the limited order info returned by the public verify endpoint. +// No user details are exposed — only payment status information. +type PublicOrderResult struct { + ID int64 `json:"id"` + OutTradeNo string `json:"out_trade_no"` + Amount float64 `json:"amount"` + PayAmount float64 `json:"pay_amount"` + PaymentType string `json:"payment_type"` + Status string `json:"status"` +} + +// VerifyOrderPublic verifies payment status without requiring authentication. +// Returns limited order info (no user details) to prevent information leakage. +// POST /api/v1/payment/public/orders/verify +func (h *PaymentHandler) VerifyOrderPublic(c *gin.Context) { + var req VerifyOrderRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.BadRequest(c, "Invalid request: "+err.Error()) + return + } + order, err := h.paymentService.VerifyOrderPublic(c.Request.Context(), req.OutTradeNo) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, PublicOrderResult{ + ID: order.ID, + OutTradeNo: order.OutTradeNo, + Amount: order.Amount, + PayAmount: order.PayAmount, + PaymentType: order.PaymentType, + Status: order.Status, + }) +} + +// requireAuth extracts the authenticated subject from the context. +// Returns the subject and true on success; on failure it writes an Unauthorized response and returns false. +func requireAuth(c *gin.Context) (middleware2.AuthSubject, bool) { + subject, ok := middleware2.GetAuthSubjectFromContext(c) + if !ok { + response.Unauthorized(c, "User not authenticated") + return middleware2.AuthSubject{}, false + } + return subject, true +} + +// 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") +} diff --git a/backend/internal/handler/payment_webhook_handler.go b/backend/internal/handler/payment_webhook_handler.go new file mode 100644 index 00000000..6d8540d8 --- /dev/null +++ b/backend/internal/handler/payment_webhook_handler.go @@ -0,0 +1,152 @@ +package handler + +import ( + "io" + "log/slog" + "net/http" + "net/url" + "strings" + + "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 +} + +// maxWebhookBodySize is the maximum allowed webhook request body size (1 MB). +const maxWebhookBodySize = 1 << 20 + +// webhookLogTruncateLen is the maximum length of raw body logged on verify failure. +const webhookLogTruncateLen = 200 + +// 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, payment.TypeEasyPay) +} + +// AlipayNotify handles Alipay payment notifications. +// POST /api/v1/payment/webhook/alipay +func (h *PaymentWebhookHandler) AlipayNotify(c *gin.Context) { + h.handleNotify(c, payment.TypeAlipay) +} + +// WxpayNotify handles WeChat Pay payment notifications. +// POST /api/v1/payment/webhook/wxpay +func (h *PaymentWebhookHandler) WxpayNotify(c *gin.Context) { + h.handleNotify(c, payment.TypeWxpay) +} + +// StripeWebhook handles Stripe webhook events. +// POST /api/v1/payment/webhook/stripe +func (h *PaymentWebhookHandler) StripeWebhook(c *gin.Context) { + h.handleNotify(c, payment.TypeStripe) +} + +// handleNotify is the shared logic for all provider webhook handlers. +func (h *PaymentWebhookHandler) handleNotify(c *gin.Context, providerKey string) { + var rawBody string + if c.Request.Method == http.MethodGet { + // GET callbacks (e.g. EasyPay) pass params as URL query string + rawBody = c.Request.URL.RawQuery + } else { + body, err := io.ReadAll(io.LimitReader(c.Request.Body, maxWebhookBodySize)) + if err != nil { + slog.Error("[Payment Webhook] failed to read body", "provider", providerKey, "error", err) + c.String(http.StatusBadRequest, "failed to read body") + return + } + rawBody = string(body) + } + + // Extract out_trade_no to look up the order's specific provider instance. + // This is needed when multiple instances of the same provider exist (e.g. multiple EasyPay accounts). + outTradeNo := extractOutTradeNo(rawBody, providerKey) + + provider, err := h.paymentService.GetWebhookProvider(c.Request.Context(), providerKey, outTradeNo) + if err != nil { + slog.Warn("[Payment Webhook] provider not found", "provider", providerKey, "outTradeNo", outTradeNo, "error", err) + writeSuccessResponse(c, providerKey) + return + } + + headers := make(map[string]string) + for k := range c.Request.Header { + headers[strings.ToLower(k)] = c.GetHeader(k) + } + + notification, err := provider.VerifyNotification(c.Request.Context(), rawBody, headers) + if err != nil { + truncatedBody := rawBody + if len(truncatedBody) > webhookLogTruncateLen { + truncatedBody = truncatedBody[:webhookLogTruncateLen] + "...(truncated)" + } + slog.Error("[Payment Webhook] verify failed", "provider", providerKey, "error", err, "method", c.Request.Method, "bodyLen", len(rawBody)) + slog.Debug("[Payment Webhook] verify failed body", "provider", providerKey, "rawBody", truncatedBody) + c.String(http.StatusBadRequest, "verify failed") + return + } + + // nil notification means irrelevant event (e.g. Stripe non-payment event); return success. + if notification == nil { + writeSuccessResponse(c, 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 + } + + writeSuccessResponse(c, providerKey) +} + +// extractOutTradeNo parses the webhook body to find the out_trade_no. +// This allows looking up the correct provider instance before verification. +func extractOutTradeNo(rawBody, providerKey string) string { + switch providerKey { + case payment.TypeEasyPay: + values, err := url.ParseQuery(rawBody) + if err == nil { + return values.Get("out_trade_no") + } + } + // For other providers (Stripe, Alipay direct, WxPay direct), the registry + // typically has only one instance, so no instance lookup is needed. + return "" +} + +// wxpaySuccessResponse is the JSON response expected by WeChat Pay webhook. +type wxpaySuccessResponse struct { + Code string `json:"code"` + Message string `json:"message"` +} + +// writeSuccessResponse sends the provider-specific success response. +// WeChat Pay requires JSON {"code":"SUCCESS","message":"成功"}; +// Stripe expects an empty 200; others accept plain text "success". +func writeSuccessResponse(c *gin.Context, providerKey string) { + switch providerKey { + case payment.TypeWxpay: + c.JSON(http.StatusOK, wxpaySuccessResponse{Code: "SUCCESS", Message: "成功"}) + case payment.TypeStripe: + c.String(http.StatusOK, "") + default: + c.String(http.StatusOK, "success") + } +} diff --git a/backend/internal/handler/payment_webhook_handler_test.go b/backend/internal/handler/payment_webhook_handler_test.go new file mode 100644 index 00000000..bdef1766 --- /dev/null +++ b/backend/internal/handler/payment_webhook_handler_test.go @@ -0,0 +1,99 @@ +//go:build unit + +package handler + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWriteSuccessResponse(t *testing.T) { + gin.SetMode(gin.TestMode) + + tests := []struct { + name string + providerKey string + wantCode int + wantContentType string + wantBody string + checkJSON bool + wantJSONCode string + wantJSONMessage string + }{ + { + name: "wxpay returns JSON with code SUCCESS", + providerKey: "wxpay", + wantCode: http.StatusOK, + wantContentType: "application/json", + checkJSON: true, + wantJSONCode: "SUCCESS", + wantJSONMessage: "成功", + }, + { + name: "stripe returns empty 200", + providerKey: "stripe", + wantCode: http.StatusOK, + wantContentType: "text/plain", + wantBody: "", + }, + { + name: "easypay returns plain text success", + providerKey: "easypay", + wantCode: http.StatusOK, + wantContentType: "text/plain", + wantBody: "success", + }, + { + name: "alipay returns plain text success", + providerKey: "alipay", + wantCode: http.StatusOK, + wantContentType: "text/plain", + wantBody: "success", + }, + { + name: "unknown provider returns plain text success", + providerKey: "unknown_provider", + wantCode: http.StatusOK, + wantContentType: "text/plain", + wantBody: "success", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w := httptest.NewRecorder() + c, _ := gin.CreateTestContext(w) + + writeSuccessResponse(c, tt.providerKey) + + assert.Equal(t, tt.wantCode, w.Code) + assert.Contains(t, w.Header().Get("Content-Type"), tt.wantContentType) + + if tt.checkJSON { + var resp wxpaySuccessResponse + err := json.Unmarshal(w.Body.Bytes(), &resp) + require.NoError(t, err, "response body should be valid JSON") + assert.Equal(t, tt.wantJSONCode, resp.Code) + assert.Equal(t, tt.wantJSONMessage, resp.Message) + } else { + assert.Equal(t, tt.wantBody, w.Body.String()) + } + }) + } +} + +func TestWebhookConstants(t *testing.T) { + t.Run("maxWebhookBodySize is 1MB", func(t *testing.T) { + assert.Equal(t, int64(1<<20), int64(maxWebhookBodySize)) + }) + + t.Run("webhookLogTruncateLen is 200", func(t *testing.T) { + assert.Equal(t, 200, webhookLogTruncateLen) + }) +} diff --git a/backend/internal/handler/wire.go b/backend/internal/handler/wire.go index d9622594..4b54d41a 100644 --- a/backend/internal/handler/wire.go +++ b/backend/internal/handler/wire.go @@ -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, diff --git a/backend/internal/payment/amount.go b/backend/internal/payment/amount.go new file mode 100644 index 00000000..8489ffa3 --- /dev/null +++ b/backend/internal/payment/amount.go @@ -0,0 +1,24 @@ +package payment + +import ( + "fmt" + + "github.com/shopspring/decimal" +) + +const centsPerYuan = 100 + +// YuanToFen converts a CNY yuan string (e.g. "10.50") to fen (int64). +// Uses shopspring/decimal for precision. +func YuanToFen(yuanStr string) (int64, error) { + d, err := decimal.NewFromString(yuanStr) + if err != nil { + return 0, fmt.Errorf("invalid amount: %s", yuanStr) + } + return d.Mul(decimal.NewFromInt(centsPerYuan)).IntPart(), nil +} + +// FenToYuan converts fen (int64) to yuan as a float64 for interface compatibility. +func FenToYuan(fen int64) float64 { + return decimal.NewFromInt(fen).Div(decimal.NewFromInt(centsPerYuan)).InexactFloat64() +} diff --git a/backend/internal/payment/amount_test.go b/backend/internal/payment/amount_test.go new file mode 100644 index 00000000..6120b189 --- /dev/null +++ b/backend/internal/payment/amount_test.go @@ -0,0 +1,128 @@ +//go:build unit + +package payment + +import ( + "math" + "testing" +) + +func TestYuanToFen(t *testing.T) { + tests := []struct { + name string + input string + want int64 + wantErr bool + }{ + // Normal values + {name: "one yuan", input: "1.00", want: 100}, + {name: "ten yuan fifty fen", input: "10.50", want: 1050}, + {name: "one fen", input: "0.01", want: 1}, + {name: "large amount", input: "99999.99", want: 9999999}, + + // Edge: zero + {name: "zero no decimal", input: "0", want: 0}, + {name: "zero with decimal", input: "0.00", want: 0}, + + // IEEE 754 precision edge case: 1.15 * 100 = 114.99999... in float64 + {name: "ieee754 precision 1.15", input: "1.15", want: 115}, + + // More precision edge cases + {name: "ieee754 precision 0.1", input: "0.1", want: 10}, + {name: "ieee754 precision 0.2", input: "0.2", want: 20}, + {name: "ieee754 precision 33.33", input: "33.33", want: 3333}, + + // Large value + {name: "hundred thousand", input: "100000.00", want: 10000000}, + + // Integer without decimal + {name: "integer 5", input: "5", want: 500}, + {name: "integer 100", input: "100", want: 10000}, + + // Single decimal place + {name: "single decimal 1.5", input: "1.5", want: 150}, + + // Negative values + {name: "negative one yuan", input: "-1.00", want: -100}, + {name: "negative with fen", input: "-10.50", want: -1050}, + + // Invalid inputs + {name: "empty string", input: "", wantErr: true}, + {name: "alphabetic", input: "abc", wantErr: true}, + {name: "double dot", input: "1.2.3", wantErr: true}, + {name: "spaces", input: " ", wantErr: true}, + {name: "special chars", input: "$10.00", wantErr: true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := YuanToFen(tt.input) + if tt.wantErr { + if err == nil { + t.Errorf("YuanToFen(%q) expected error, got %d", tt.input, got) + } + return + } + if err != nil { + t.Fatalf("YuanToFen(%q) unexpected error: %v", tt.input, err) + } + if got != tt.want { + t.Errorf("YuanToFen(%q) = %d, want %d", tt.input, got, tt.want) + } + }) + } +} + +func TestFenToYuan(t *testing.T) { + tests := []struct { + name string + fen int64 + want float64 + }{ + {name: "one yuan", fen: 100, want: 1.0}, + {name: "ten yuan fifty fen", fen: 1050, want: 10.5}, + {name: "one fen", fen: 1, want: 0.01}, + {name: "zero", fen: 0, want: 0.0}, + {name: "large amount", fen: 9999999, want: 99999.99}, + {name: "negative", fen: -100, want: -1.0}, + {name: "negative with fen", fen: -1050, want: -10.5}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := FenToYuan(tt.fen) + if math.Abs(got-tt.want) > 1e-9 { + t.Errorf("FenToYuan(%d) = %f, want %f", tt.fen, got, tt.want) + } + }) + } +} + +func TestYuanToFenRoundTrip(t *testing.T) { + // Verify that converting yuan->fen->yuan preserves the value. + cases := []struct { + yuan string + fen int64 + }{ + {"0.01", 1}, + {"1.00", 100}, + {"10.50", 1050}, + {"99999.99", 9999999}, + } + + for _, tc := range cases { + fen, err := YuanToFen(tc.yuan) + if err != nil { + t.Fatalf("YuanToFen(%q) unexpected error: %v", tc.yuan, err) + } + if fen != tc.fen { + t.Errorf("YuanToFen(%q) = %d, want %d", tc.yuan, fen, tc.fen) + } + yuan := FenToYuan(fen) + // Parse expected yuan back for comparison + expectedYuan := FenToYuan(tc.fen) + if math.Abs(yuan-expectedYuan) > 1e-9 { + t.Errorf("round-trip: FenToYuan(%d) = %f, want %f", fen, yuan, expectedYuan) + } + } +} diff --git a/backend/internal/payment/crypto.go b/backend/internal/payment/crypto.go new file mode 100644 index 00000000..e39e957f --- /dev/null +++ b/backend/internal/payment/crypto.go @@ -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 +} diff --git a/backend/internal/payment/crypto_test.go b/backend/internal/payment/crypto_test.go new file mode 100644 index 00000000..da8b6006 --- /dev/null +++ b/backend/internal/payment/crypto_test.go @@ -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) + } + } +} diff --git a/backend/internal/payment/fee.go b/backend/internal/payment/fee.go new file mode 100644 index 00000000..e2128e5e --- /dev/null +++ b/backend/internal/payment/fee.go @@ -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) +} diff --git a/backend/internal/payment/fee_test.go b/backend/internal/payment/fee_test.go new file mode 100644 index 00000000..c58d1082 --- /dev/null +++ b/backend/internal/payment/fee_test.go @@ -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) + } + }) + } +} diff --git a/backend/internal/payment/load_balancer.go b/backend/internal/payment/load_balancer.go new file mode 100644 index 00000000..afe607e0 --- /dev/null +++ b/backend/internal/payment/load_balancer.go @@ -0,0 +1,328 @@ +package payment + +import ( + "context" + "encoding/json" + "fmt" + "log/slog" + "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" +) + +// ChannelLimits holds limits for a single payment channel within a provider instance. +type ChannelLimits struct { + DailyLimit float64 `json:"dailyLimit,omitempty"` + SingleMin float64 `json:"singleMin,omitempty"` + SingleMax float64 `json:"singleMax,omitempty"` +} + +// InstanceLimits holds per-channel limits for a provider instance (JSON). +type InstanceLimits map[string]ChannelLimits + +// 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, strategy Strategy, orderAmount float64) (*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} +} + +// instanceCandidate pairs an instance with its pre-fetched daily usage. +type instanceCandidate struct { + inst *dbent.PaymentProviderInstance + dailyUsed float64 // includes PENDING orders +} + +// SelectInstance picks an enabled instance for the given provider key and payment type. +// +// Flow: +// 1. Query all enabled instances for providerKey, filter by supported paymentType +// 2. Batch-query daily usage (PENDING + PAID + COMPLETED + RECHARGING) for all candidates +// 3. Filter out instances where: single-min/max violated OR daily remaining < orderAmount +// 4. Pick from survivors using the configured strategy (round-robin / least-amount) +// 5. If all filtered out, fall back to full list (let the provider itself reject) +func (lb *DefaultLoadBalancer) SelectInstance( + ctx context.Context, + providerKey string, + paymentType PaymentType, + strategy Strategy, + orderAmount float64, +) (*InstanceSelection, error) { + // Step 1: query enabled instances matching payment type. + instances, err := lb.queryEnabledInstances(ctx, providerKey, paymentType) + if err != nil { + return nil, err + } + + // Step 2: batch-fetch daily usage for all candidates. + candidates := lb.attachDailyUsage(ctx, instances) + + // Step 3: filter by limits. + available := filterByLimits(candidates, paymentType, orderAmount) + if len(available) == 0 { + slog.Warn("all instances exceeded limits, using full candidate list", + "provider", providerKey, "payment_type", paymentType, + "order_amount", orderAmount, "count", len(candidates)) + available = candidates + } + + // Step 4: pick by strategy. + selected := lb.pickByStrategy(available, strategy) + return lb.buildSelection(selected.inst) +} + +// queryEnabledInstances returns enabled instances for providerKey that support paymentType. +func (lb *DefaultLoadBalancer) queryEnabledInstances( + ctx context.Context, + providerKey string, + paymentType PaymentType, +) ([]*dbent.PaymentProviderInstance, 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) + } + + var matched []*dbent.PaymentProviderInstance + for _, inst := range instances { + if paymentType == providerKey || InstanceSupportsType(inst.SupportedTypes, paymentType) { + matched = append(matched, inst) + } + } + if len(matched) == 0 { + return nil, fmt.Errorf("no enabled instance for provider %s type %s", providerKey, paymentType) + } + return matched, nil +} + +// attachDailyUsage queries daily usage for each instance in a single pass. +// Usage includes PENDING orders to avoid over-committing capacity. +func (lb *DefaultLoadBalancer) attachDailyUsage( + ctx context.Context, + instances []*dbent.PaymentProviderInstance, +) []instanceCandidate { + todayStart := startOfDay(time.Now()) + + // Collect instance IDs. + ids := make([]string, len(instances)) + for i, inst := range instances { + ids[i] = fmt.Sprintf("%d", inst.ID) + } + + // Batch query: sum pay_amount grouped by provider_instance_id. + type row struct { + InstanceID string `json:"provider_instance_id"` + Sum float64 `json:"sum"` + } + var rows []row + err := lb.db.PaymentOrder.Query(). + Where( + paymentorder.ProviderInstanceIDIn(ids...), + paymentorder.StatusIn( + OrderStatusPending, OrderStatusPaid, + OrderStatusCompleted, OrderStatusRecharging, + ), + paymentorder.CreatedAtGTE(todayStart), + ). + GroupBy(paymentorder.FieldProviderInstanceID). + Aggregate(dbent.Sum(paymentorder.FieldPayAmount)). + Scan(ctx, &rows) + if err != nil { + slog.Warn("batch daily usage query failed, treating all as zero", "error", err) + } + + usageMap := make(map[string]float64, len(rows)) + for _, r := range rows { + usageMap[r.InstanceID] = r.Sum + } + + candidates := make([]instanceCandidate, len(instances)) + for i, inst := range instances { + candidates[i] = instanceCandidate{ + inst: inst, + dailyUsed: usageMap[fmt.Sprintf("%d", inst.ID)], + } + } + return candidates +} + +// filterByLimits removes instances that cannot accommodate the order: +// - orderAmount outside single-transaction [min, max] +// - daily remaining capacity (limit - used) < orderAmount +func filterByLimits(candidates []instanceCandidate, paymentType PaymentType, orderAmount float64) []instanceCandidate { + var result []instanceCandidate + for _, c := range candidates { + cl := getInstanceChannelLimits(c.inst, paymentType) + + if cl.SingleMin > 0 && orderAmount < cl.SingleMin { + slog.Info("order below instance single min, skipping", + "instance_id", c.inst.ID, "order", orderAmount, "min", cl.SingleMin) + continue + } + if cl.SingleMax > 0 && orderAmount > cl.SingleMax { + slog.Info("order above instance single max, skipping", + "instance_id", c.inst.ID, "order", orderAmount, "max", cl.SingleMax) + continue + } + if cl.DailyLimit > 0 && c.dailyUsed+orderAmount > cl.DailyLimit { + slog.Info("instance daily remaining insufficient, skipping", + "instance_id", c.inst.ID, "used", c.dailyUsed, + "order", orderAmount, "limit", cl.DailyLimit) + continue + } + + result = append(result, c) + } + return result +} + +// getInstanceChannelLimits returns the channel limits for a specific payment type. +func getInstanceChannelLimits(inst *dbent.PaymentProviderInstance, paymentType PaymentType) ChannelLimits { + if inst.Limits == "" { + return ChannelLimits{} + } + var limits InstanceLimits + if err := json.Unmarshal([]byte(inst.Limits), &limits); err != nil { + return ChannelLimits{} + } + // For Stripe, limits are stored under the provider key "stripe". + lookupKey := paymentType + if inst.ProviderKey == "stripe" { + lookupKey = "stripe" + } + if cl, ok := limits[lookupKey]; ok { + return cl + } + return ChannelLimits{} +} + +// pickByStrategy selects one instance from the available candidates. +func (lb *DefaultLoadBalancer) pickByStrategy(candidates []instanceCandidate, strategy Strategy) instanceCandidate { + if strategy == StrategyLeastAmount && len(candidates) > 1 { + return pickLeastAmount(candidates) + } + // Default: round-robin. + idx := lb.counter.Add(1) % uint64(len(candidates)) + return candidates[idx] +} + +// pickLeastAmount selects the instance with the lowest daily usage. +// No extra DB queries — usage was pre-fetched in attachDailyUsage. +func pickLeastAmount(candidates []instanceCandidate) instanceCandidate { + best := candidates[0] + for _, c := range candidates[1:] { + if c.dailyUsed < best.dailyUsed { + best = c + } + } + return best +} + +func (lb *DefaultLoadBalancer) buildSelection(selected *dbent.PaymentProviderInstance) (*InstanceSelection, error) { + config, err := lb.decryptConfig(selected.Config) + if err != nil { + return nil, fmt.Errorf("decrypt instance %d config: %w", selected.ID, err) + } + + if selected.PaymentMode != "" { + config["paymentMode"] = selected.PaymentMode + } + + return &InstanceSelection{ + InstanceID: fmt.Sprintf("%d", selected.ID), + Config: config, + SupportedTypes: selected.SupportedTypes, + PaymentMode: selected.PaymentMode, + }, 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) { + todayStart := startOfDay(time.Now()) + + var result []struct { + Sum float64 `json:"sum"` + } + err := lb.db.PaymentOrder.Query(). + Where( + paymentorder.ProviderInstanceID(instanceID), + paymentorder.StatusIn(OrderStatusCompleted, OrderStatusPaid, OrderStatusRecharging), + 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 +} + +func startOfDay(t time.Time) time.Time { + return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) +} + +// InstanceSupportsType checks if the given supported types string includes the target type. +// An empty supportedTypes string means all types are supported. +func InstanceSupportsType(supportedTypes string, target PaymentType) bool { + if supportedTypes == "" { + return true + } + 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) +} diff --git a/backend/internal/payment/load_balancer_test.go b/backend/internal/payment/load_balancer_test.go new file mode 100644 index 00000000..568b56a3 --- /dev/null +++ b/backend/internal/payment/load_balancer_test.go @@ -0,0 +1,474 @@ +//go:build unit + +package payment + +import ( + "encoding/json" + "testing" + "time" + + dbent "github.com/Wei-Shaw/sub2api/ent" +) + +func TestInstanceSupportsType(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 means all supported", + supportedTypes: "", + target: "alipay", + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := InstanceSupportsType(tt.supportedTypes, tt.target) + if got != tt.expected { + t.Fatalf("InstanceSupportsType(%q, %q) = %v, want %v", tt.supportedTypes, tt.target, got, tt.expected) + } + }) + } +} + +// --------------------------------------------------------------------------- +// Helper to build test PaymentProviderInstance values +// --------------------------------------------------------------------------- + +func testInstance(id int64, providerKey, limits string) *dbent.PaymentProviderInstance { + return &dbent.PaymentProviderInstance{ + ID: id, + ProviderKey: providerKey, + Limits: limits, + Enabled: true, + } +} + +// makeLimitsJSON builds a limits JSON string for a single payment type. +func makeLimitsJSON(paymentType string, cl ChannelLimits) string { + m := map[string]ChannelLimits{paymentType: cl} + b, _ := json.Marshal(m) + return string(b) +} + +// --------------------------------------------------------------------------- +// filterByLimits +// --------------------------------------------------------------------------- + +func TestFilterByLimits(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + candidates []instanceCandidate + paymentType PaymentType + orderAmount float64 + wantIDs []int64 // expected surviving instance IDs + }{ + { + name: "order below SingleMin is filtered out", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMin: 10})), dailyUsed: 0}, + }, + paymentType: "alipay", + orderAmount: 5, + wantIDs: nil, + }, + { + name: "order at exact SingleMin boundary passes", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMin: 10})), dailyUsed: 0}, + }, + paymentType: "alipay", + orderAmount: 10, + wantIDs: []int64{1}, + }, + { + name: "order above SingleMax is filtered out", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMax: 100})), dailyUsed: 0}, + }, + paymentType: "alipay", + orderAmount: 150, + wantIDs: nil, + }, + { + name: "order at exact SingleMax boundary passes", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMax: 100})), dailyUsed: 0}, + }, + paymentType: "alipay", + orderAmount: 100, + wantIDs: []int64{1}, + }, + { + name: "daily used + orderAmount exceeding dailyLimit is filtered out", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{DailyLimit: 500})), dailyUsed: 480}, + }, + paymentType: "alipay", + orderAmount: 30, + wantIDs: nil, // 480+30=510 > 500 + }, + { + name: "daily used + orderAmount equal to dailyLimit passes (strict greater-than)", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{DailyLimit: 500})), dailyUsed: 480}, + }, + paymentType: "alipay", + orderAmount: 20, + wantIDs: []int64{1}, // 480+20=500, 500 > 500 is false → passes + }, + { + name: "daily used + orderAmount below dailyLimit passes", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{DailyLimit: 500})), dailyUsed: 400}, + }, + paymentType: "alipay", + orderAmount: 50, + wantIDs: []int64{1}, + }, + { + name: "no limits configured passes through", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", ""), dailyUsed: 99999}, + }, + paymentType: "alipay", + orderAmount: 100, + wantIDs: []int64{1}, + }, + { + name: "multiple candidates with partial filtering", + candidates: []instanceCandidate{ + // singleMax=50, order=80 → filtered out + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMax: 50})), dailyUsed: 0}, + // no limits → passes + {inst: testInstance(2, "easypay", ""), dailyUsed: 0}, + // singleMin=100, order=80 → filtered out + {inst: testInstance(3, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMin: 100})), dailyUsed: 0}, + // daily limit ok → passes (500+80=580 < 1000) + {inst: testInstance(4, "easypay", makeLimitsJSON("alipay", ChannelLimits{DailyLimit: 1000})), dailyUsed: 500}, + }, + paymentType: "alipay", + orderAmount: 80, + wantIDs: []int64{2, 4}, + }, + { + name: "zero SingleMin and SingleMax means no single-transaction limit", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMin: 0, SingleMax: 0, DailyLimit: 0})), dailyUsed: 0}, + }, + paymentType: "alipay", + orderAmount: 99999, + wantIDs: []int64{1}, + }, + { + name: "all limits combined - order passes all checks", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMin: 10, SingleMax: 200, DailyLimit: 1000})), dailyUsed: 500}, + }, + paymentType: "alipay", + orderAmount: 50, + wantIDs: []int64{1}, + }, + { + name: "all limits combined - order fails SingleMin", + candidates: []instanceCandidate{ + {inst: testInstance(1, "easypay", makeLimitsJSON("alipay", ChannelLimits{SingleMin: 10, SingleMax: 200, DailyLimit: 1000})), dailyUsed: 500}, + }, + paymentType: "alipay", + orderAmount: 5, + wantIDs: nil, + }, + { + name: "empty candidates returns empty", + candidates: nil, + paymentType: "alipay", + orderAmount: 10, + wantIDs: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := filterByLimits(tt.candidates, tt.paymentType, tt.orderAmount) + gotIDs := make([]int64, len(got)) + for i, c := range got { + gotIDs[i] = c.inst.ID + } + if !int64SliceEqual(gotIDs, tt.wantIDs) { + t.Fatalf("filterByLimits() returned IDs %v, want %v", gotIDs, tt.wantIDs) + } + }) + } +} + +// --------------------------------------------------------------------------- +// pickLeastAmount +// --------------------------------------------------------------------------- + +func TestPickLeastAmount(t *testing.T) { + t.Parallel() + + t.Run("picks candidate with lowest dailyUsed", func(t *testing.T) { + t.Parallel() + candidates := []instanceCandidate{ + {inst: testInstance(1, "easypay", ""), dailyUsed: 300}, + {inst: testInstance(2, "easypay", ""), dailyUsed: 100}, + {inst: testInstance(3, "easypay", ""), dailyUsed: 200}, + } + got := pickLeastAmount(candidates) + if got.inst.ID != 2 { + t.Fatalf("pickLeastAmount() picked instance %d, want 2", got.inst.ID) + } + }) + + t.Run("with equal dailyUsed picks the first one", func(t *testing.T) { + t.Parallel() + candidates := []instanceCandidate{ + {inst: testInstance(1, "easypay", ""), dailyUsed: 100}, + {inst: testInstance(2, "easypay", ""), dailyUsed: 100}, + {inst: testInstance(3, "easypay", ""), dailyUsed: 200}, + } + got := pickLeastAmount(candidates) + if got.inst.ID != 1 { + t.Fatalf("pickLeastAmount() picked instance %d, want 1 (first with lowest)", got.inst.ID) + } + }) + + t.Run("single candidate returns that candidate", func(t *testing.T) { + t.Parallel() + candidates := []instanceCandidate{ + {inst: testInstance(42, "easypay", ""), dailyUsed: 999}, + } + got := pickLeastAmount(candidates) + if got.inst.ID != 42 { + t.Fatalf("pickLeastAmount() picked instance %d, want 42", got.inst.ID) + } + }) + + t.Run("zero usage among non-zero picks zero", func(t *testing.T) { + t.Parallel() + candidates := []instanceCandidate{ + {inst: testInstance(1, "easypay", ""), dailyUsed: 500}, + {inst: testInstance(2, "easypay", ""), dailyUsed: 0}, + {inst: testInstance(3, "easypay", ""), dailyUsed: 300}, + } + got := pickLeastAmount(candidates) + if got.inst.ID != 2 { + t.Fatalf("pickLeastAmount() picked instance %d, want 2", got.inst.ID) + } + }) +} + +// --------------------------------------------------------------------------- +// getInstanceChannelLimits +// --------------------------------------------------------------------------- + +func TestGetInstanceChannelLimits(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + inst *dbent.PaymentProviderInstance + paymentType PaymentType + want ChannelLimits + }{ + { + name: "empty limits string returns zero ChannelLimits", + inst: testInstance(1, "easypay", ""), + paymentType: "alipay", + want: ChannelLimits{}, + }, + { + name: "invalid JSON returns zero ChannelLimits", + inst: testInstance(1, "easypay", "not-json{"), + paymentType: "alipay", + want: ChannelLimits{}, + }, + { + name: "valid JSON with matching payment type", + inst: testInstance(1, "easypay", + `{"alipay":{"singleMin":5,"singleMax":200,"dailyLimit":1000}}`), + paymentType: "alipay", + want: ChannelLimits{SingleMin: 5, SingleMax: 200, DailyLimit: 1000}, + }, + { + name: "payment type not in limits returns zero ChannelLimits", + inst: testInstance(1, "easypay", + `{"alipay":{"singleMin":5,"singleMax":200}}`), + paymentType: "wxpay", + want: ChannelLimits{}, + }, + { + name: "stripe provider uses stripe lookup key regardless of payment type", + inst: testInstance(1, "stripe", + `{"stripe":{"singleMin":10,"singleMax":500,"dailyLimit":5000}}`), + paymentType: "alipay", + want: ChannelLimits{SingleMin: 10, SingleMax: 500, DailyLimit: 5000}, + }, + { + name: "stripe provider ignores payment type key even if present", + inst: testInstance(1, "stripe", + `{"stripe":{"singleMin":10,"singleMax":500},"alipay":{"singleMin":1,"singleMax":100}}`), + paymentType: "alipay", + want: ChannelLimits{SingleMin: 10, SingleMax: 500}, + }, + { + name: "non-stripe provider uses payment type as lookup key", + inst: testInstance(1, "easypay", + `{"alipay":{"singleMin":5},"wxpay":{"singleMin":10}}`), + paymentType: "wxpay", + want: ChannelLimits{SingleMin: 10}, + }, + { + name: "valid JSON with partial limits (only dailyLimit)", + inst: testInstance(1, "easypay", + `{"alipay":{"dailyLimit":800}}`), + paymentType: "alipay", + want: ChannelLimits{DailyLimit: 800}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := getInstanceChannelLimits(tt.inst, tt.paymentType) + if got != tt.want { + t.Fatalf("getInstanceChannelLimits() = %+v, want %+v", got, tt.want) + } + }) + } +} + +// --------------------------------------------------------------------------- +// startOfDay +// --------------------------------------------------------------------------- + +func TestStartOfDay(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + in time.Time + want time.Time + }{ + { + name: "midday returns midnight of same day", + in: time.Date(2025, 6, 15, 14, 30, 45, 123456789, time.UTC), + want: time.Date(2025, 6, 15, 0, 0, 0, 0, time.UTC), + }, + { + name: "midnight returns same time", + in: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC), + want: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC), + }, + { + name: "last second of day returns midnight of same day", + in: time.Date(2025, 12, 31, 23, 59, 59, 999999999, time.UTC), + want: time.Date(2025, 12, 31, 0, 0, 0, 0, time.UTC), + }, + { + name: "preserves timezone location", + in: time.Date(2025, 3, 10, 15, 0, 0, 0, time.FixedZone("CST", 8*3600)), + want: time.Date(2025, 3, 10, 0, 0, 0, 0, time.FixedZone("CST", 8*3600)), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := startOfDay(tt.in) + if !got.Equal(tt.want) { + t.Fatalf("startOfDay(%v) = %v, want %v", tt.in, got, tt.want) + } + // Also verify location is preserved. + if got.Location().String() != tt.want.Location().String() { + t.Fatalf("startOfDay() location = %v, want %v", got.Location(), tt.want.Location()) + } + }) + } +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +// int64SliceEqual compares two int64 slices for equality. +// Both nil and empty slices are treated as equal. +func int64SliceEqual(a, b []int64) bool { + if len(a) == 0 && len(b) == 0 { + return true + } + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} diff --git a/backend/internal/payment/provider/alipay.go b/backend/internal/payment/provider/alipay.go new file mode 100644 index 00000000..3eca0b2c --- /dev/null +++ b/backend/internal/payment/provider/alipay.go @@ -0,0 +1,279 @@ +package provider + +import ( + "context" + "fmt" + "net/url" + "strconv" + "strings" + "sync" + "time" + + "github.com/Wei-Shaw/sub2api/internal/payment" + "github.com/smartwalle/alipay/v3" +) + +// Alipay product codes. +const ( + alipayProductCodePagePay = "FAST_INSTANT_TRADE_PAY" + alipayProductCodeWapPay = "QUICK_WAP_WAY" +) + +// Alipay response constants. +const ( + alipayFundChangeYes = "Y" + alipayErrTradeNotExist = "ACQ.TRADE_NOT_EXIST" + alipayRefundSuffix = "-refund" +) + +// 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 == "" { + return nil, fmt.Errorf("alipay config missing required key: publicKey (or alipayPublicKey)") + } + 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 payment.TypeAlipay } +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.createTrade(client, req, notifyURL, returnURL, true) + } + return a.createTrade(client, req, notifyURL, returnURL, false) +} + +func (a *Alipay) createTrade(client *alipay.Client, req payment.CreatePaymentRequest, notifyURL, returnURL string, isMobile bool) (*payment.CreatePaymentResponse, error) { + if isMobile { + param := alipay.TradeWapPay{} + param.OutTradeNo = req.OrderID + param.TotalAmount = req.Amount + param.Subject = req.Subject + param.ProductCode = alipayProductCodeWapPay + 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 + } + + param := alipay.TradePagePay{} + param.OutTradeNo = req.OrderID + param.TotalAmount = req.Amount + param.Subject = req.Subject + param.ProductCode = alipayProductCodePagePay + 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 +} + +// 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: payment.ProviderStatusPending, + }, nil + } + return nil, fmt.Errorf("alipay TradeQuery: %w", err) + } + + status := payment.ProviderStatusPending + switch result.TradeStatus { + case alipay.TradeStatusSuccess, alipay.TradeStatusFinished: + status = payment.ProviderStatusPaid + case alipay.TradeStatusClosed: + status = payment.ProviderStatusFailed + } + + amount, err := strconv.ParseFloat(result.TotalAmount, 64) + if err != nil { + return nil, fmt.Errorf("alipay parse amount %q: %w", result.TotalAmount, err) + } + + 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 := payment.ProviderStatusFailed + if notification.TradeStatus == alipay.TradeStatusSuccess || notification.TradeStatus == alipay.TradeStatusFinished { + status = payment.ProviderStatusSuccess + } + + amount, err := strconv.ParseFloat(notification.TotalAmount, 64) + if err != nil { + return nil, fmt.Errorf("alipay parse notification amount %q: %w", notification.TotalAmount, err) + } + + 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 := payment.ProviderStatusPending + if result.FundChange == alipayFundChangeYes { + refundStatus = payment.ProviderStatusSuccess + } + + refundID := result.TradeNo + if refundID == "" { + refundID = req.OrderID + alipayRefundSuffix + } + + 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(), alipayErrTradeNotExist) +} + +// Ensure interface compliance. +var ( + _ payment.Provider = (*Alipay)(nil) + _ payment.CancelableProvider = (*Alipay)(nil) +) diff --git a/backend/internal/payment/provider/alipay_test.go b/backend/internal/payment/provider/alipay_test.go new file mode 100644 index 00000000..1b9d66ba --- /dev/null +++ b/backend/internal/payment/provider/alipay_test.go @@ -0,0 +1,132 @@ +//go:build unit + +package provider + +import ( + "errors" + "strings" + "testing" +) + +func TestIsTradeNotExist(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + err error + want bool + }{ + { + name: "nil error returns false", + err: nil, + want: false, + }, + { + name: "error containing ACQ.TRADE_NOT_EXIST returns true", + err: errors.New("alipay: sub_code=ACQ.TRADE_NOT_EXIST, sub_msg=交易不存在"), + want: true, + }, + { + name: "error not containing the code returns false", + err: errors.New("alipay: sub_code=ACQ.SYSTEM_ERROR, sub_msg=系统错误"), + want: false, + }, + { + name: "error with only partial match returns false", + err: errors.New("ACQ.TRADE_NOT"), + want: false, + }, + { + name: "error with exact constant value returns true", + err: errors.New(alipayErrTradeNotExist), + want: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := isTradeNotExist(tt.err) + if got != tt.want { + t.Errorf("isTradeNotExist(%v) = %v, want %v", tt.err, got, tt.want) + } + }) + } +} + +func TestNewAlipay(t *testing.T) { + t.Parallel() + + validConfig := map[string]string{ + "appId": "2021001234567890", + "privateKey": "MIIEvQIBADANBgkqhkiG9w0BAQEFAASC...", + } + + // helper to clone and override config fields + withOverride := func(overrides map[string]string) map[string]string { + cfg := make(map[string]string, len(validConfig)) + for k, v := range validConfig { + cfg[k] = v + } + for k, v := range overrides { + cfg[k] = v + } + return cfg + } + + tests := []struct { + name string + config map[string]string + wantErr bool + errSubstr string + }{ + { + name: "valid config succeeds", + config: validConfig, + wantErr: false, + }, + { + name: "missing appId", + config: withOverride(map[string]string{"appId": ""}), + wantErr: true, + errSubstr: "appId", + }, + { + name: "missing privateKey", + config: withOverride(map[string]string{"privateKey": ""}), + wantErr: true, + errSubstr: "privateKey", + }, + { + name: "nil config map returns error for appId", + config: map[string]string{}, + wantErr: true, + errSubstr: "appId", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := NewAlipay("test-instance", tt.config) + if tt.wantErr { + if err == nil { + t.Fatal("expected error, got nil") + } + if tt.errSubstr != "" && !strings.Contains(err.Error(), tt.errSubstr) { + t.Errorf("error %q should contain %q", err.Error(), tt.errSubstr) + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got == nil { + t.Fatal("expected non-nil Alipay instance") + } + if got.instanceID != "test-instance" { + t.Errorf("instanceID = %q, want %q", got.instanceID, "test-instance") + } + }) + } +} diff --git a/backend/internal/payment/provider/easypay.go b/backend/internal/payment/provider/easypay.go new file mode 100644 index 00000000..b48a38fe --- /dev/null +++ b/backend/internal/payment/provider/easypay.go @@ -0,0 +1,278 @@ +// 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" + "strconv" + "strings" + "time" + + "github.com/Wei-Shaw/sub2api/internal/payment" +) + +// EasyPay constants. +const ( + easypayCodeSuccess = 1 + easypayStatusPaid = 1 + easypayHTTPTimeout = 10 * time.Second + maxEasypayResponseSize = 1 << 20 // 1MB + tradeStatusSuccess = "TRADE_SUCCESS" + signTypeMD5 = "MD5" +) + +// 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: easypayHTTPTimeout}, + }, nil +} + +func (e *EasyPay) Name() string { return "EasyPay" } +func (e *EasyPay) ProviderKey() string { return payment.TypeEasyPay } +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) { + // Payment mode determined by instance config, not payment type. + // "popup" → hosted page (submit.php); "qrcode"/default → API call (mapi.php). + mode := e.config["paymentMode"] + if mode == "popup" { + return e.createRedirectPayment(req) + } + return e.createAPIPayment(ctx, req) +} + +// createRedirectPayment builds a submit.php URL for browser redirect. +// No server-side API call — the user is redirected to EasyPay's hosted page. +// TradeNo is empty; it arrives via the notify callback after payment. +func (e *EasyPay) createRedirectPayment(req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) { + notifyURL, returnURL := e.resolveURLs(req) + params := map[string]string{ + "pid": e.config["pid"], "type": req.PaymentType, + "out_trade_no": req.OrderID, "notify_url": notifyURL, + "return_url": returnURL, "name": req.Subject, + "money": req.Amount, + } + if cid := e.resolveCID(req.PaymentType); cid != "" { + params["cid"] = cid + } + params["sign"] = easyPaySign(params, e.config["pkey"]) + params["sign_type"] = signTypeMD5 + + q := url.Values{} + for k, v := range params { + q.Set(k, v) + } + base := strings.TrimRight(e.config["apiBase"], "/") + payURL := base + "/submit.php?" + q.Encode() + return &payment.CreatePaymentResponse{PayURL: payURL}, nil +} + +// createAPIPayment calls mapi.php to get payurl/qrcode (existing behavior). +func (e *EasyPay) createAPIPayment(ctx context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) { + notifyURL, returnURL := e.resolveURLs(req) + params := map[string]string{ + "pid": e.config["pid"], "type": req.PaymentType, + "out_trade_no": req.OrderID, "notify_url": notifyURL, + "return_url": 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"] = signTypeMD5 + + body, err := e.post(ctx, strings.TrimRight(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 != easypayCodeSuccess { + return nil, fmt.Errorf("easypay error: %s", resp.Msg) + } + return &payment.CreatePaymentResponse{TradeNo: resp.TradeNo, PayURL: resp.PayURL, QRCode: resp.QRCode}, nil +} + +// resolveURLs returns (notifyURL, returnURL) preferring request values, +// falling back to instance config. +func (e *EasyPay) resolveURLs(req payment.CreatePaymentRequest) (string, string) { + notifyURL := req.NotifyURL + if notifyURL == "" { + notifyURL = e.config["notifyUrl"] + } + returnURL := req.ReturnURL + if returnURL == "" { + returnURL = e.config["returnUrl"] + } + return notifyURL, returnURL +} + +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"` + Money string `json:"money"` + } + if err := json.Unmarshal(body, &resp); err != nil { + return nil, fmt.Errorf("easypay parse query: %w", err) + } + status := payment.ProviderStatusPending + if resp.Status == easypayStatusPaid { + status = payment.ProviderStatusPaid + } + amount, _ := strconv.ParseFloat(resp.Money, 64) + return &payment.QueryOrderResponse{TradeNo: tradeNo, Status: status, Amount: amount}, 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) + } + // url.ParseQuery already decodes values — no additional decode needed. + 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 := payment.ProviderStatusFailed + if params["trade_status"] == tradeStatusSuccess { + status = payment.ProviderStatusSuccess + } + amount, _ := strconv.ParseFloat(params["money"], 64) + return &payment.PaymentNotification{ + TradeNo: params["trade_no"], OrderID: params["out_trade_no"], + Amount: amount, 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 != easypayCodeSuccess { + return nil, fmt.Errorf("easypay refund failed: %s", resp.Msg) + } + return &payment.RefundResponse{RefundID: req.TradeNo, Status: payment.ProviderStatusSuccess}, 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 func() { _ = resp.Body.Close() }() + return io.ReadAll(io.LimitReader(resp.Body, maxEasypayResponseSize)) +} + +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)) +} diff --git a/backend/internal/payment/provider/easypay_sign_test.go b/backend/internal/payment/provider/easypay_sign_test.go new file mode 100644 index 00000000..146a6fa1 --- /dev/null +++ b/backend/internal/payment/provider/easypay_sign_test.go @@ -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") + } +} diff --git a/backend/internal/payment/provider/factory.go b/backend/internal/payment/provider/factory.go new file mode 100644 index 00000000..397ca064 --- /dev/null +++ b/backend/internal/payment/provider/factory.go @@ -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) + } +} diff --git a/backend/internal/payment/provider/stripe.go b/backend/internal/payment/provider/stripe.go new file mode 100644 index 00000000..15359d45 --- /dev/null +++ b/backend/internal/payment/provider/stripe.go @@ -0,0 +1,262 @@ +package provider + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "sync" + + "github.com/Wei-Shaw/sub2api/internal/payment" + stripe "github.com/stripe/stripe-go/v85" + "github.com/stripe/stripe-go/v85/webhook" +) + +// Stripe constants. +const ( + stripeCurrency = "cny" + stripeEventPaymentSuccess = "payment_intent.succeeded" + stripeEventPaymentFailed = "payment_intent.payment_failed" +) + +// Stripe implements the payment.CancelableProvider interface for Stripe payments. +type Stripe struct { + instanceID string + config map[string]string + + mu sync.Mutex + initialized bool + sc *stripe.Client +} + +// 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.sc = stripe.NewClient(s.config["secretKey"]) + 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 payment.TypeStripe } +func (s *Stripe) SupportedTypes() []payment.PaymentType { + return []payment.PaymentType{payment.TypeStripe} +} + +// stripePaymentMethodTypes maps our PaymentType to Stripe payment_method_types. +var stripePaymentMethodTypes = map[string][]string{ + payment.TypeCard: {"card"}, + payment.TypeAlipay: {"alipay"}, + payment.TypeWxpay: {"wechat_pay"}, + payment.TypeLink: {"link"}, +} + +// CreatePayment creates a Stripe PaymentIntent. +func (s *Stripe) CreatePayment(ctx context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) { + s.ensureInit() + + amountInCents, err := payment.YuanToFen(req.Amount) + if err != nil { + return nil, fmt.Errorf("stripe create payment: %w", err) + } + + // Collect all Stripe payment_method_types from the instance's configured sub-methods + methods := resolveStripeMethodTypes(req.InstanceSubMethods) + + pmTypes := make([]*string, len(methods)) + for i, m := range methods { + pmTypes[i] = stripe.String(m) + } + + params := &stripe.PaymentIntentCreateParams{ + Amount: stripe.Int64(amountInCents), + Currency: stripe.String(stripeCurrency), + PaymentMethodTypes: pmTypes, + Description: stripe.String(req.Subject), + Metadata: map[string]string{"orderId": req.OrderID}, + } + + // WeChat Pay requires payment_method_options with client type + if hasStripeMethod(methods, "wechat_pay") { + params.PaymentMethodOptions = &stripe.PaymentIntentCreatePaymentMethodOptionsParams{ + WeChatPay: &stripe.PaymentIntentCreatePaymentMethodOptionsWeChatPayParams{ + Client: stripe.String("web"), + }, + } + } + + params.SetIdempotencyKey(fmt.Sprintf("pi-%s", req.OrderID)) + params.Context = ctx + + pi, err := s.sc.V1PaymentIntents.Create(ctx, 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() + + pi, err := s.sc.V1PaymentIntents.Retrieve(ctx, tradeNo, nil) + if err != nil { + return nil, fmt.Errorf("stripe query order: %w", err) + } + + status := payment.ProviderStatusPending + switch pi.Status { + case stripe.PaymentIntentStatusSucceeded: + status = payment.ProviderStatusPaid + case stripe.PaymentIntentStatusCanceled: + status = payment.ProviderStatusFailed + } + + return &payment.QueryOrderResponse{ + TradeNo: pi.ID, + Status: status, + Amount: payment.FenToYuan(pi.Amount), + }, 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 stripeEventPaymentSuccess: + return parseStripePaymentIntent(&event, payment.ProviderStatusSuccess, rawBody) + case stripeEventPaymentFailed: + return parseStripePaymentIntent(&event, payment.ProviderStatusFailed, 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: payment.FenToYuan(pi.Amount), + 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 := payment.YuanToFen(req.Amount) + if err != nil { + return nil, fmt.Errorf("stripe refund: %w", err) + } + + params := &stripe.RefundCreateParams{ + PaymentIntent: stripe.String(req.TradeNo), + Amount: stripe.Int64(amountInCents), + Reason: stripe.String(string(stripe.RefundReasonRequestedByCustomer)), + } + params.Context = ctx + + r, err := s.sc.V1Refunds.Create(ctx, params) + if err != nil { + return nil, fmt.Errorf("stripe refund: %w", err) + } + + refundStatus := payment.ProviderStatusPending + if r.Status == stripe.RefundStatusSucceeded { + refundStatus = payment.ProviderStatusSuccess + } + + return &payment.RefundResponse{ + RefundID: r.ID, + Status: refundStatus, + }, nil +} + +// resolveStripeMethodTypes converts instance supported_types (comma-separated) +// into Stripe API payment_method_types. Falls back to ["card"] if empty. +func resolveStripeMethodTypes(instanceSubMethods string) []string { + if instanceSubMethods == "" { + return []string{"card"} + } + var methods []string + for _, t := range strings.Split(instanceSubMethods, ",") { + t = strings.TrimSpace(t) + if mapped, ok := stripePaymentMethodTypes[t]; ok { + methods = append(methods, mapped...) + } + } + if len(methods) == 0 { + return []string{"card"} + } + return methods +} + +// hasStripeMethod checks if the given Stripe method list contains the target method. +func hasStripeMethod(methods []string, target string) bool { + for _, m := range methods { + if m == target { + return true + } + } + return false +} + +// CancelPayment cancels a pending PaymentIntent. +func (s *Stripe) CancelPayment(ctx context.Context, tradeNo string) error { + s.ensureInit() + + _, err := s.sc.V1PaymentIntents.Cancel(ctx, tradeNo, nil) + 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) +) diff --git a/backend/internal/payment/provider/wxpay.go b/backend/internal/payment/provider/wxpay.go new file mode 100644 index 00000000..14e51cd2 --- /dev/null +++ b/backend/internal/payment/provider/wxpay.go @@ -0,0 +1,350 @@ +package provider + +import ( + "bytes" + "context" + "crypto/rsa" + "fmt" + "io" + "log/slog" + "net/http" + "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" +) + +// WeChat Pay constants. +const ( + wxpayCurrency = "CNY" + wxpayH5Type = "Wap" +) + +// WeChat Pay trade states. +const ( + wxpayTradeStateSuccess = "SUCCESS" + wxpayTradeStateRefund = "REFUND" + wxpayTradeStateClosed = "CLOSED" + wxpayTradeStatePayError = "PAYERROR" +) + +// WeChat Pay notification event types. +const ( + wxpayEventTransactionSuccess = "TRANSACTION.SUCCESS" +) + +// WeChat Pay error codes. +const ( + wxpayErrNoAuth = "NO_AUTH" +) + +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", "certSerial"} + 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 payment.TypeWxpay } +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, publicKey, err := w.loadKeyPair() + if err != nil { + return nil, err + } + certSerial := w.config["certSerial"] + 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 (w *Wxpay) loadKeyPair() (*rsa.PrivateKey, *rsa.PublicKey, error) { + privateKey, err := utils.LoadPrivateKey(formatPEM(w.config["privateKey"], "PRIVATE KEY")) + if err != nil { + return nil, nil, fmt.Errorf("wxpay load private key: %w", err) + } + publicKey, err := utils.LoadPublicKey(formatPEM(w.config["publicKey"], "PUBLIC KEY")) + if err != nil { + return nil, nil, fmt.Errorf("wxpay load public key: %w", err) + } + return privateKey, publicKey, nil +} + +func (w *Wxpay) CreatePayment(ctx context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) { + client, err := w.ensureClient() + if err != nil { + return nil, err + } + // Request-first, config-fallback (consistent with EasyPay/Alipay) + notifyURL := req.NotifyURL + if notifyURL == "" { + notifyURL = w.config["notifyUrl"] + } + if notifyURL == "" { + return nil, fmt.Errorf("wxpay notifyUrl is required") + } + totalFen, err := payment.YuanToFen(req.Amount) + if err != nil { + return nil, fmt.Errorf("wxpay create payment: %w", err) + } + if req.IsMobile && req.ClientIP != "" { + resp, err := w.createOrder(ctx, client, req, notifyURL, totalFen, true) + if err == nil { + return resp, nil + } + if !strings.Contains(err.Error(), wxpayErrNoAuth) { + return nil, err + } + slog.Warn("wxpay H5 payment not authorized, falling back to native", "order", req.OrderID) + } + return w.createOrder(ctx, client, req, notifyURL, totalFen, false) +} + +func (w *Wxpay) createOrder(ctx context.Context, c *core.Client, req payment.CreatePaymentRequest, notifyURL string, totalFen int64, useH5 bool) (*payment.CreatePaymentResponse, error) { + if useH5 { + return w.prepayH5(ctx, c, req, notifyURL, totalFen) + } + return w.prepayNative(ctx, c, req, notifyURL, totalFen) +} + +func (w *Wxpay) prepayNative(ctx context.Context, c *core.Client, req payment.CreatePaymentRequest, notifyURL string, totalFen int64) (*payment.CreatePaymentResponse, error) { + svc := native.NativeApiService{Client: c} + cur := wxpayCurrency + 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) prepayH5(ctx context.Context, c *core.Client, req payment.CreatePaymentRequest, notifyURL string, totalFen int64) (*payment.CreatePaymentResponse, error) { + svc := h5.H5ApiService{Client: c} + cur := wxpayCurrency + tp := wxpayH5Type + 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 wxpayTradeStateSuccess: + return payment.ProviderStatusPaid + case wxpayTradeStateRefund: + return payment.ProviderStatusRefunded + case wxpayTradeStateClosed, wxpayTradeStatePayError: + return payment.ProviderStatusFailed + default: + return payment.ProviderStatusPending + } +} + +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 = payment.FenToYuan(*tx.Amount.Total) + } + 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 != wxpayEventTransactionSuccess { + return nil, nil + } + var amt float64 + if tx.Amount != nil && tx.Amount.Total != nil { + amt = payment.FenToYuan(*tx.Amount.Total) + } + st := payment.ProviderStatusFailed + if wxSV(tx.TradeState) == wxpayTradeStateSuccess { + st = payment.ProviderStatusSuccess + } + 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 := payment.YuanToFen(req.Amount) + if err != nil { + return nil, fmt.Errorf("wxpay refund amount: %w", err) + } + tf, err := w.queryOrderTotalFen(ctx, c, req.OrderID) + if err != nil { + return nil, err + } + rs := refunddomestic.RefundsApiService{Client: c} + cur := wxpayCurrency + 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 := payment.ProviderStatusPending + if res.Status != nil && *res.Status == refunddomestic.STATUS_SUCCESS { + st = payment.ProviderStatusSuccess + } + return &payment.RefundResponse{RefundID: rid, Status: st}, nil +} + +func (w *Wxpay) queryOrderTotalFen(ctx context.Context, c *core.Client, orderID string) (int64, error) { + svc := native.NativeApiService{Client: c} + tx, _, err := svc.QueryOrderByOutTradeNo(ctx, native.QueryOrderByOutTradeNoRequest{ + OutTradeNo: core.String(orderID), Mchid: core.String(w.config["mchId"]), + }) + if err != nil { + return 0, fmt.Errorf("wxpay refund query order: %w", err) + } + var tf int64 + if tx.Amount != nil && tx.Amount.Total != nil { + tf = *tx.Amount.Total + } + return tf, 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) +) diff --git a/backend/internal/payment/provider/wxpay_test.go b/backend/internal/payment/provider/wxpay_test.go new file mode 100644 index 00000000..b8b99537 --- /dev/null +++ b/backend/internal/payment/provider/wxpay_test.go @@ -0,0 +1,259 @@ +//go:build unit + +package provider + +import ( + "strings" + "testing" + + "github.com/Wei-Shaw/sub2api/internal/payment" +) + +func TestMapWxState(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input string + want string + }{ + { + name: "SUCCESS maps to paid", + input: wxpayTradeStateSuccess, + want: payment.ProviderStatusPaid, + }, + { + name: "REFUND maps to refunded", + input: wxpayTradeStateRefund, + want: payment.ProviderStatusRefunded, + }, + { + name: "CLOSED maps to failed", + input: wxpayTradeStateClosed, + want: payment.ProviderStatusFailed, + }, + { + name: "PAYERROR maps to failed", + input: wxpayTradeStatePayError, + want: payment.ProviderStatusFailed, + }, + { + name: "unknown state maps to pending", + input: "NOTPAY", + want: payment.ProviderStatusPending, + }, + { + name: "empty string maps to pending", + input: "", + want: payment.ProviderStatusPending, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := mapWxState(tt.input) + if got != tt.want { + t.Errorf("mapWxState(%q) = %q, want %q", tt.input, got, tt.want) + } + }) + } +} + +func TestWxSV(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input *string + want string + }{ + { + name: "nil pointer returns empty string", + input: nil, + want: "", + }, + { + name: "non-nil pointer returns value", + input: strPtr("hello"), + want: "hello", + }, + { + name: "pointer to empty string returns empty string", + input: strPtr(""), + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := wxSV(tt.input) + if got != tt.want { + t.Errorf("wxSV() = %q, want %q", got, tt.want) + } + }) + } +} + +func strPtr(s string) *string { + return &s +} + +func TestFormatPEM(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + key string + keyType string + want string + }{ + { + name: "raw key gets wrapped with headers", + key: "MIIBIjANBgkqhki...", + keyType: "PUBLIC KEY", + want: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki...\n-----END PUBLIC KEY-----", + }, + { + name: "already formatted key is returned as-is", + key: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBg...\n-----END PRIVATE KEY-----", + keyType: "PRIVATE KEY", + want: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBg...\n-----END PRIVATE KEY-----", + }, + { + name: "key with leading/trailing whitespace is trimmed before check", + key: " \n MIIBIjANBgkqhki... \n ", + keyType: "PUBLIC KEY", + want: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki...\n-----END PUBLIC KEY-----", + }, + { + name: "already formatted key with whitespace is trimmed and returned", + key: " -----BEGIN RSA PRIVATE KEY-----\ndata\n-----END RSA PRIVATE KEY----- ", + keyType: "RSA PRIVATE KEY", + want: "-----BEGIN RSA PRIVATE KEY-----\ndata\n-----END RSA PRIVATE KEY-----", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := formatPEM(tt.key, tt.keyType) + if got != tt.want { + t.Errorf("formatPEM(%q, %q) =\n%s\nwant:\n%s", tt.key, tt.keyType, got, tt.want) + } + }) + } +} + +func TestNewWxpay(t *testing.T) { + t.Parallel() + + validConfig := map[string]string{ + "appId": "wx1234567890", + "mchId": "1234567890", + "privateKey": "fake-private-key", + "apiV3Key": "12345678901234567890123456789012", // exactly 32 bytes + "publicKey": "fake-public-key", + "publicKeyId": "key-id-001", + "certSerial": "SERIAL001", + } + + // helper to clone and override config fields + withOverride := func(overrides map[string]string) map[string]string { + cfg := make(map[string]string, len(validConfig)) + for k, v := range validConfig { + cfg[k] = v + } + for k, v := range overrides { + cfg[k] = v + } + return cfg + } + + tests := []struct { + name string + config map[string]string + wantErr bool + errSubstr string + }{ + { + name: "valid config succeeds", + config: validConfig, + wantErr: false, + }, + { + name: "missing appId", + config: withOverride(map[string]string{"appId": ""}), + wantErr: true, + errSubstr: "appId", + }, + { + name: "missing mchId", + config: withOverride(map[string]string{"mchId": ""}), + wantErr: true, + errSubstr: "mchId", + }, + { + name: "missing privateKey", + config: withOverride(map[string]string{"privateKey": ""}), + wantErr: true, + errSubstr: "privateKey", + }, + { + name: "missing apiV3Key", + config: withOverride(map[string]string{"apiV3Key": ""}), + wantErr: true, + errSubstr: "apiV3Key", + }, + { + name: "missing publicKey", + config: withOverride(map[string]string{"publicKey": ""}), + wantErr: true, + errSubstr: "publicKey", + }, + { + name: "missing publicKeyId", + config: withOverride(map[string]string{"publicKeyId": ""}), + wantErr: true, + errSubstr: "publicKeyId", + }, + { + name: "apiV3Key too short", + config: withOverride(map[string]string{"apiV3Key": "short"}), + wantErr: true, + errSubstr: "exactly 32 bytes", + }, + { + name: "apiV3Key too long", + config: withOverride(map[string]string{"apiV3Key": "123456789012345678901234567890123"}), // 33 bytes + wantErr: true, + errSubstr: "exactly 32 bytes", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := NewWxpay("test-instance", tt.config) + if tt.wantErr { + if err == nil { + t.Fatal("expected error, got nil") + } + if tt.errSubstr != "" && !strings.Contains(err.Error(), tt.errSubstr) { + t.Errorf("error %q should contain %q", err.Error(), tt.errSubstr) + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got == nil { + t.Fatal("expected non-nil Wxpay instance") + } + if got.instanceID != "test-instance" { + t.Errorf("instanceID = %q, want %q", got.instanceID, "test-instance") + } + }) + } +} diff --git a/backend/internal/payment/registry.go b/backend/internal/payment/registry.go new file mode 100644 index 00000000..259eb4bb --- /dev/null +++ b/backend/internal/payment/registry.go @@ -0,0 +1,85 @@ +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() + for _, p := range r.providers { + if p.ProviderKey() == key { + return p, nil + } + } + 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) +} diff --git a/backend/internal/payment/registry_test.go b/backend/internal/payment/registry_test.go new file mode 100644 index 00000000..9684945c --- /dev/null +++ b/backend/internal/payment/registry_test.go @@ -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)) + } +} diff --git a/backend/internal/payment/types.go b/backend/internal/payment/types.go new file mode 100644 index 00000000..c413d8f3 --- /dev/null +++ b/backend/internal/payment/types.go @@ -0,0 +1,180 @@ +// 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" + TypeCard PaymentType = "card" + TypeLink PaymentType = "link" + TypeEasyPay PaymentType = "easypay" +) + +// Order status constants shared across payment and service layers. +const ( + OrderStatusPending = "PENDING" + OrderStatusPaid = "PAID" + OrderStatusRecharging = "RECHARGING" + OrderStatusCompleted = "COMPLETED" + OrderStatusExpired = "EXPIRED" + OrderStatusCancelled = "CANCELLED" + OrderStatusFailed = "FAILED" + OrderStatusRefundRequested = "REFUND_REQUESTED" + OrderStatusRefunding = "REFUNDING" + OrderStatusPartiallyRefunded = "PARTIALLY_REFUNDED" + OrderStatusRefunded = "REFUNDED" + OrderStatusRefundFailed = "REFUND_FAILED" +) + +// Order types distinguish balance recharges from subscription purchases. +const ( + OrderTypeBalance = "balance" + OrderTypeSubscription = "subscription" +) + +// Entity statuses shared across users, groups, etc. +const ( + EntityStatusActive = "active" +) + +// Deduction types for refund flow. +const ( + DeductionTypeBalance = "balance" + DeductionTypeSubscription = "subscription" + DeductionTypeNone = "none" +) + +// Payment notification status values. +const ( + NotificationStatusSuccess = "success" + NotificationStatusPaid = "paid" +) + +// Provider-level status constants returned by provider implementations +// to the service layer (lowercase, distinct from OrderStatus uppercase constants). +const ( + ProviderStatusPending = "pending" + ProviderStatusPaid = "paid" + ProviderStatusSuccess = "success" + ProviderStatusFailed = "failed" + ProviderStatusRefunded = "refunded" +) + +// DefaultLoadBalanceStrategy is the default load-balancing strategy +// used when no strategy is configured. +const DefaultLoadBalanceStrategy = "round-robin" + +// ConfigKeyPublishableKey is the config map key for Stripe's publishable key. +const ConfigKeyPublishableKey = "publishableKey" + +// GetBasePaymentType extracts the base payment method from a composite key. +// For example, "alipay_direct" -> "alipay". +func GetBasePaymentType(t string) string { + switch { + case t == TypeEasyPay: + return TypeEasyPay + case t == TypeStripe || t == TypeCard || t == TypeLink: + return TypeStripe + case len(t) >= len(TypeAlipay) && t[:len(TypeAlipay)] == TypeAlipay: + return TypeAlipay + case len(t) >= len(TypeWxpay) && t[:len(TypeWxpay)] == TypeWxpay: + return TypeWxpay + 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", "stripe" + 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 + InstanceSubMethods string // Comma-separated sub-methods from instance supported_types (for Stripe) +} + +// 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 + SupportedTypes string // Comma-separated list of supported payment types from the instance + PaymentMode string // Payment display mode: "qrcode", "redirect", "popup" +} + +// 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 +} diff --git a/backend/internal/payment/wire.go b/backend/internal/payment/wire.go new file mode 100644 index 00000000..9717465d --- /dev/null +++ b/backend/internal/payment/wire.go @@ -0,0 +1,53 @@ +package payment + +import ( + "encoding/hex" + "fmt" + "log/slog" + + 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. +// When the key is empty, nil is returned (payment features that need encryption will be disabled). +// When the key is non-empty but invalid (bad hex or wrong length), an error is returned +// to prevent startup with a misconfigured encryption key. +func ProvideEncryptionKey(cfg *config.Config) (EncryptionKey, error) { + if cfg.Totp.EncryptionKey == "" { + slog.Warn("payment encryption key not configured — encrypted payment config will be unavailable") + return nil, nil + } + key, err := hex.DecodeString(cfg.Totp.EncryptionKey) + if err != nil { + return nil, fmt.Errorf("invalid payment encryption key (hex decode): %w", err) + } + if len(key) != 32 { + return nil, fmt.Errorf("payment encryption key must be 32 bytes, got %d", len(key)) + } + return EncryptionKey(key), nil +} + +// 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)), +) diff --git a/backend/internal/server/api_contract_test.go b/backend/internal/server/api_contract_test.go index fee879a4..be2fef38 100644 --- a/backend/internal/server/api_contract_test.go +++ b/backend/internal/server/api_contract_test.go @@ -583,6 +583,24 @@ func TestAPIContracts(t *testing.T) { "enable_cch_signing": false, "enable_fingerprint_unification": true, "enable_metadata_passthrough": false, + "payment_enabled": false, + "payment_min_amount": 0, + "payment_max_amount": 0, + "payment_daily_limit": 0, + "payment_order_timeout_minutes": 0, + "payment_max_pending_orders": 0, + "payment_enabled_types": null, + "payment_balance_disabled": false, + "payment_load_balance_strategy": "", + "payment_product_name_prefix": "", + "payment_product_name_suffix": "", + "payment_help_image_url": "", + "payment_help_text": "", + "payment_cancel_rate_limit_enabled": false, + "payment_cancel_rate_limit_max": 0, + "payment_cancel_rate_limit_window": 0, + "payment_cancel_rate_limit_unit": "", + "payment_cancel_rate_limit_window_mode": "", "custom_menu_items": [], "custom_endpoints": [] } @@ -696,7 +714,7 @@ func newContractDeps(t *testing.T) *contractDeps { authHandler := handler.NewAuthHandler(cfg, nil, userService, settingService, nil, redeemService, nil) apiKeyHandler := handler.NewAPIKeyHandler(apiKeyService) usageHandler := handler.NewUsageHandler(usageService, apiKeyService) - adminSettingHandler := adminhandler.NewSettingHandler(settingService, nil, nil, nil) + adminSettingHandler := adminhandler.NewSettingHandler(settingService, nil, nil, nil, nil, nil) adminAccountHandler := adminhandler.NewAccountHandler(adminService, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) jwtAuth := func(c *gin.Context) { diff --git a/backend/internal/server/router.go b/backend/internal/server/router.go index d60a142c..a507b6f8 100644 --- a/backend/internal/server/router.go +++ b/backend/internal/server/router.go @@ -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) } diff --git a/backend/internal/server/routes/payment.go b/backend/internal/server/routes/payment.go new file mode 100644 index 00000000..6bf04679 --- /dev/null +++ b/backend/internal/server/routes/payment.go @@ -0,0 +1,103 @@ +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("/checkout-info", paymentHandler.GetCheckoutInfo) + authenticated.GET("/plans", paymentHandler.GetPlans) + authenticated.GET("/channels", paymentHandler.GetChannels) + authenticated.GET("/limits", paymentHandler.GetLimits) + + orders := authenticated.Group("/orders") + { + orders.POST("", paymentHandler.CreateOrder) + orders.POST("/verify", paymentHandler.VerifyOrder) + orders.GET("/my", paymentHandler.GetMyOrders) + orders.GET("/:id", paymentHandler.GetOrder) + orders.POST("/:id/cancel", paymentHandler.CancelOrder) + orders.POST("/:id/refund-request", paymentHandler.RequestRefund) + } + } + + // --- Public payment endpoints (no auth) --- + // Payment result page needs to verify order status without login + // (user session may have expired during provider redirect). + public := v1.Group("/payment/public") + { + public.POST("/orders/verify", paymentHandler.VerifyOrderPublic) + } + + // --- Webhook endpoints (no auth) --- + webhook := v1.Group("/payment/webhook") + { + // EasyPay sends GET callbacks with query params + webhook.GET("/easypay", webhookHandler.EasyPayNotify) + 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) + } + } +} diff --git a/backend/internal/service/payment_config_limits.go b/backend/internal/service/payment_config_limits.go new file mode 100644 index 00000000..56905278 --- /dev/null +++ b/backend/internal/service/payment_config_limits.go @@ -0,0 +1,172 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance" + "github.com/Wei-Shaw/sub2api/internal/payment" +) + +// GetAvailableMethodLimits collects all payment types from enabled provider +// instances and returns limits for each, plus the global widest range. +// Stripe sub-types (card, link) are aggregated under "stripe". +func (s *PaymentConfigService) GetAvailableMethodLimits(ctx context.Context) (*MethodLimitsResponse, 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) + } + typeInstances := pcGroupByPaymentType(instances) + resp := &MethodLimitsResponse{ + Methods: make(map[string]MethodLimits, len(typeInstances)), + } + for pt, insts := range typeInstances { + ml := pcAggregateMethodLimits(pt, insts) + resp.Methods[ml.PaymentType] = ml + } + resp.GlobalMin, resp.GlobalMax = pcComputeGlobalRange(resp.Methods) + return resp, 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 { + var matching []*dbent.PaymentProviderInstance + for _, inst := range instances { + if payment.InstanceSupportsType(inst.SupportedTypes, pt) { + matching = append(matching, inst) + } + } + result = append(result, pcAggregateMethodLimits(pt, matching)) + } + return result, nil +} + +// pcGroupByPaymentType groups instances by user-facing payment type. +// For Stripe providers, ALL sub-types (card, link, alipay, wxpay) map to "stripe" +// because the user sees a single "Stripe" button, not individual sub-methods. +// Uses a seen set to avoid counting one instance twice. +func pcGroupByPaymentType(instances []*dbent.PaymentProviderInstance) map[string][]*dbent.PaymentProviderInstance { + typeInstances := make(map[string][]*dbent.PaymentProviderInstance) + seen := make(map[string]map[int64]bool) + add := func(key string, inst *dbent.PaymentProviderInstance) { + if seen[key] == nil { + seen[key] = make(map[int64]bool) + } + if !seen[key][int64(inst.ID)] { + seen[key][int64(inst.ID)] = true + typeInstances[key] = append(typeInstances[key], inst) + } + } + for _, inst := range instances { + // Stripe provider: all sub-types → single "stripe" group + if inst.ProviderKey == payment.TypeStripe { + add(payment.TypeStripe, inst) + continue + } + for _, t := range splitTypes(inst.SupportedTypes) { + add(t, inst) + } + } + return typeInstances +} + +// pcInstanceTypeLimits extracts per-type limits from a provider instance. +// Returns (limits, true) if configured; (zero, false) if unlimited. +// For Stripe instances, limits are stored under "stripe" key regardless of sub-types. +func pcInstanceTypeLimits(inst *dbent.PaymentProviderInstance, pt string) (payment.ChannelLimits, bool) { + if inst.Limits == "" { + return payment.ChannelLimits{}, false + } + var limits payment.InstanceLimits + if err := json.Unmarshal([]byte(inst.Limits), &limits); err != nil { + return payment.ChannelLimits{}, false + } + cl, ok := limits[pt] + return cl, ok +} + +// unionFloat merges a single limit value into the aggregate using UNION semantics. +// - For "min" fields (wantMin=true): keeps the lowest non-zero value +// - For "max"/"cap" fields (wantMin=false): keeps the highest non-zero value +// - If any value is 0 (unlimited), the result is unlimited. +// +// Returns (aggregated value, still limited). +func unionFloat(agg float64, limited bool, val float64, wantMin bool) (float64, bool) { + if val == 0 { + return agg, false + } + if !limited { + return agg, false + } + if agg == 0 { + return val, true + } + if wantMin && val < agg { + return val, true + } + if !wantMin && val > agg { + return val, true + } + return agg, true +} + +// pcAggregateMethodLimits computes the UNION (least restrictive) of limits +// across all provider instances for a given payment type. +// +// Since the load balancer can route an order to any available instance, +// the user should see the widest possible range: +// - SingleMin: lowest floor across instances; 0 if any is unlimited +// - SingleMax: highest ceiling across instances; 0 if any is unlimited +// - DailyLimit: highest cap across instances; 0 if any is unlimited +func pcAggregateMethodLimits(pt string, instances []*dbent.PaymentProviderInstance) MethodLimits { + ml := MethodLimits{PaymentType: pt} + minLimited, maxLimited, dailyLimited := true, true, true + + for _, inst := range instances { + cl, hasLimits := pcInstanceTypeLimits(inst, pt) + if !hasLimits { + return MethodLimits{PaymentType: pt} // any unlimited instance → all zeros + } + ml.SingleMin, minLimited = unionFloat(ml.SingleMin, minLimited, cl.SingleMin, true) + ml.SingleMax, maxLimited = unionFloat(ml.SingleMax, maxLimited, cl.SingleMax, false) + ml.DailyLimit, dailyLimited = unionFloat(ml.DailyLimit, dailyLimited, cl.DailyLimit, false) + } + + if !minLimited { + ml.SingleMin = 0 + } + if !maxLimited { + ml.SingleMax = 0 + } + if !dailyLimited { + ml.DailyLimit = 0 + } + return ml +} + +// pcComputeGlobalRange computes the widest [min, max] across all methods. +// Uses the same union logic: lowest min, highest max, 0 if any is unlimited. +func pcComputeGlobalRange(methods map[string]MethodLimits) (globalMin, globalMax float64) { + minLimited, maxLimited := true, true + for _, ml := range methods { + globalMin, minLimited = unionFloat(globalMin, minLimited, ml.SingleMin, true) + globalMax, maxLimited = unionFloat(globalMax, maxLimited, ml.SingleMax, false) + } + if !minLimited { + globalMin = 0 + } + if !maxLimited { + globalMax = 0 + } + return globalMin, globalMax +} diff --git a/backend/internal/service/payment_config_limits_test.go b/backend/internal/service/payment_config_limits_test.go new file mode 100644 index 00000000..73ad66ef --- /dev/null +++ b/backend/internal/service/payment_config_limits_test.go @@ -0,0 +1,301 @@ +package service + +import ( + "testing" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/internal/payment" +) + +func TestUnionFloat(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + agg float64 + limited bool + val float64 + wantMin bool + wantAgg float64 + wantLimited bool + }{ + {"first non-zero value", 0, true, 5, true, 5, true}, + {"lower min replaces", 10, true, 3, true, 3, true}, + {"higher min does not replace", 3, true, 10, true, 3, true}, + {"higher max replaces", 10, true, 20, false, 20, true}, + {"lower max does not replace", 20, true, 10, false, 20, true}, + {"zero value makes unlimited", 5, true, 0, true, 5, false}, + {"already unlimited stays unlimited", 5, false, 10, true, 5, false}, + {"zero on first call", 0, true, 0, true, 0, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + gotAgg, gotLimited := unionFloat(tt.agg, tt.limited, tt.val, tt.wantMin) + if gotAgg != tt.wantAgg || gotLimited != tt.wantLimited { + t.Fatalf("unionFloat(%v, %v, %v, %v) = (%v, %v), want (%v, %v)", + tt.agg, tt.limited, tt.val, tt.wantMin, + gotAgg, gotLimited, tt.wantAgg, tt.wantLimited) + } + }) + } +} + +func makeInstance(id int64, providerKey, supportedTypes, limits string) *dbent.PaymentProviderInstance { + return &dbent.PaymentProviderInstance{ + ID: id, + ProviderKey: providerKey, + SupportedTypes: supportedTypes, + Limits: limits, + Enabled: true, + } +} + +func TestPcAggregateMethodLimits(t *testing.T) { + t.Parallel() + + t.Run("single instance with limits", func(t *testing.T) { + t.Parallel() + inst := makeInstance(1, "easypay", "alipay,wxpay", + `{"alipay":{"singleMin":2,"singleMax":14},"wxpay":{"singleMin":1,"singleMax":12}}`) + ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst}) + if ml.SingleMin != 2 || ml.SingleMax != 14 { + t.Fatalf("alipay limits = min:%v max:%v, want min:2 max:14", ml.SingleMin, ml.SingleMax) + } + }) + + t.Run("two instances union takes widest range", func(t *testing.T) { + t.Parallel() + inst1 := makeInstance(1, "easypay", "alipay,wxpay", + `{"alipay":{"singleMin":5,"singleMax":100}}`) + inst2 := makeInstance(2, "easypay", "alipay,wxpay", + `{"alipay":{"singleMin":2,"singleMax":200}}`) + ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst1, inst2}) + if ml.SingleMin != 2 { + t.Fatalf("SingleMin = %v, want 2 (lowest floor)", ml.SingleMin) + } + if ml.SingleMax != 200 { + t.Fatalf("SingleMax = %v, want 200 (highest ceiling)", ml.SingleMax) + } + }) + + t.Run("one instance unlimited makes aggregate unlimited", func(t *testing.T) { + t.Parallel() + inst1 := makeInstance(1, "easypay", "wxpay", + `{"wxpay":{"singleMin":3,"singleMax":10}}`) + inst2 := makeInstance(2, "easypay", "wxpay", "") // no limits = unlimited + ml := pcAggregateMethodLimits("wxpay", []*dbent.PaymentProviderInstance{inst1, inst2}) + if ml.SingleMin != 0 || ml.SingleMax != 0 { + t.Fatalf("limits = min:%v max:%v, want min:0 max:0 (unlimited)", ml.SingleMin, ml.SingleMax) + } + }) + + t.Run("one field unlimited others limited", func(t *testing.T) { + t.Parallel() + inst1 := makeInstance(1, "easypay", "alipay", + `{"alipay":{"singleMin":5,"singleMax":100}}`) + inst2 := makeInstance(2, "easypay", "alipay", + `{"alipay":{"singleMin":3,"singleMax":0}}`) // singleMax=0 = unlimited + ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst1, inst2}) + if ml.SingleMin != 3 { + t.Fatalf("SingleMin = %v, want 3 (lowest floor)", ml.SingleMin) + } + if ml.SingleMax != 0 { + t.Fatalf("SingleMax = %v, want 0 (unlimited)", ml.SingleMax) + } + }) + + t.Run("empty instances returns zeros", func(t *testing.T) { + t.Parallel() + ml := pcAggregateMethodLimits("alipay", nil) + if ml.SingleMin != 0 || ml.SingleMax != 0 || ml.DailyLimit != 0 { + t.Fatalf("empty instances should return all zeros, got %+v", ml) + } + }) + + t.Run("invalid JSON treated as unlimited", func(t *testing.T) { + t.Parallel() + inst := makeInstance(1, "easypay", "alipay", `{invalid json}`) + ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst}) + if ml.SingleMin != 0 || ml.SingleMax != 0 { + t.Fatalf("invalid JSON should be treated as unlimited, got %+v", ml) + } + }) + + t.Run("type not in limits JSON treated as unlimited", func(t *testing.T) { + t.Parallel() + inst := makeInstance(1, "easypay", "alipay,wxpay", + `{"wxpay":{"singleMin":1,"singleMax":10}}`) // only wxpay, no alipay + ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst}) + if ml.SingleMin != 0 || ml.SingleMax != 0 { + t.Fatalf("missing type should be treated as unlimited, got %+v", ml) + } + }) + + t.Run("daily limit aggregation", func(t *testing.T) { + t.Parallel() + inst1 := makeInstance(1, "easypay", "alipay", + `{"alipay":{"singleMin":1,"singleMax":100,"dailyLimit":500}}`) + inst2 := makeInstance(2, "easypay", "alipay", + `{"alipay":{"singleMin":2,"singleMax":200,"dailyLimit":1000}}`) + ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst1, inst2}) + if ml.DailyLimit != 1000 { + t.Fatalf("DailyLimit = %v, want 1000 (highest cap)", ml.DailyLimit) + } + }) +} + +func TestPcGroupByPaymentType(t *testing.T) { + t.Parallel() + + t.Run("stripe instance maps all types to stripe group", func(t *testing.T) { + t.Parallel() + stripe := makeInstance(1, payment.TypeStripe, "card,alipay,link,wxpay", "") + easypay := makeInstance(2, payment.TypeEasyPay, "alipay,wxpay", "") + + groups := pcGroupByPaymentType([]*dbent.PaymentProviderInstance{stripe, easypay}) + + // Stripe instance should only be in "stripe" group + if len(groups[payment.TypeStripe]) != 1 || groups[payment.TypeStripe][0].ID != 1 { + t.Fatalf("stripe group should contain only stripe instance, got %v", groups[payment.TypeStripe]) + } + // alipay group should only contain easypay, NOT stripe + if len(groups[payment.TypeAlipay]) != 1 || groups[payment.TypeAlipay][0].ID != 2 { + t.Fatalf("alipay group should contain only easypay instance, got %v", groups[payment.TypeAlipay]) + } + // wxpay group should only contain easypay, NOT stripe + if len(groups[payment.TypeWxpay]) != 1 || groups[payment.TypeWxpay][0].ID != 2 { + t.Fatalf("wxpay group should contain only easypay instance, got %v", groups[payment.TypeWxpay]) + } + }) + + t.Run("multiple easypay instances in same groups", func(t *testing.T) { + t.Parallel() + ep1 := makeInstance(1, payment.TypeEasyPay, "alipay,wxpay", "") + ep2 := makeInstance(2, payment.TypeEasyPay, "alipay,wxpay", "") + + groups := pcGroupByPaymentType([]*dbent.PaymentProviderInstance{ep1, ep2}) + + if len(groups[payment.TypeAlipay]) != 2 { + t.Fatalf("alipay group should have 2 instances, got %d", len(groups[payment.TypeAlipay])) + } + if len(groups[payment.TypeWxpay]) != 2 { + t.Fatalf("wxpay group should have 2 instances, got %d", len(groups[payment.TypeWxpay])) + } + }) + + t.Run("stripe with no supported types still in stripe group", func(t *testing.T) { + t.Parallel() + stripe := makeInstance(1, payment.TypeStripe, "", "") + + groups := pcGroupByPaymentType([]*dbent.PaymentProviderInstance{stripe}) + + if len(groups[payment.TypeStripe]) != 1 { + t.Fatalf("stripe with empty types should still be in stripe group, got %v", groups) + } + }) +} + +func TestPcComputeGlobalRange(t *testing.T) { + t.Parallel() + + t.Run("all methods have limits", func(t *testing.T) { + t.Parallel() + methods := map[string]MethodLimits{ + "alipay": {SingleMin: 2, SingleMax: 14}, + "wxpay": {SingleMin: 1, SingleMax: 12}, + "stripe": {SingleMin: 5, SingleMax: 100}, + } + gMin, gMax := pcComputeGlobalRange(methods) + if gMin != 1 { + t.Fatalf("global min = %v, want 1 (lowest floor)", gMin) + } + if gMax != 100 { + t.Fatalf("global max = %v, want 100 (highest ceiling)", gMax) + } + }) + + t.Run("one method unlimited makes global unlimited", func(t *testing.T) { + t.Parallel() + methods := map[string]MethodLimits{ + "alipay": {SingleMin: 2, SingleMax: 14}, + "stripe": {SingleMin: 0, SingleMax: 0}, // unlimited + } + gMin, gMax := pcComputeGlobalRange(methods) + if gMin != 0 { + t.Fatalf("global min = %v, want 0 (unlimited)", gMin) + } + if gMax != 0 { + t.Fatalf("global max = %v, want 0 (unlimited)", gMax) + } + }) + + t.Run("empty methods returns zeros", func(t *testing.T) { + t.Parallel() + gMin, gMax := pcComputeGlobalRange(map[string]MethodLimits{}) + if gMin != 0 || gMax != 0 { + t.Fatalf("empty methods should return (0, 0), got (%v, %v)", gMin, gMax) + } + }) + + t.Run("only min unlimited", func(t *testing.T) { + t.Parallel() + methods := map[string]MethodLimits{ + "alipay": {SingleMin: 0, SingleMax: 100}, + "wxpay": {SingleMin: 5, SingleMax: 50}, + } + gMin, gMax := pcComputeGlobalRange(methods) + if gMin != 0 { + t.Fatalf("global min = %v, want 0 (unlimited)", gMin) + } + if gMax != 100 { + t.Fatalf("global max = %v, want 100", gMax) + } + }) +} + +func TestPcInstanceTypeLimits(t *testing.T) { + t.Parallel() + + t.Run("empty limits string returns false", func(t *testing.T) { + t.Parallel() + inst := makeInstance(1, "easypay", "alipay", "") + _, ok := pcInstanceTypeLimits(inst, "alipay") + if ok { + t.Fatal("expected ok=false for empty limits") + } + }) + + t.Run("type found returns correct values", func(t *testing.T) { + t.Parallel() + inst := makeInstance(1, "easypay", "alipay", + `{"alipay":{"singleMin":2,"singleMax":14,"dailyLimit":500}}`) + cl, ok := pcInstanceTypeLimits(inst, "alipay") + if !ok { + t.Fatal("expected ok=true") + } + if cl.SingleMin != 2 || cl.SingleMax != 14 || cl.DailyLimit != 500 { + t.Fatalf("limits = %+v, want min:2 max:14 daily:500", cl) + } + }) + + t.Run("type not found returns false", func(t *testing.T) { + t.Parallel() + inst := makeInstance(1, "easypay", "alipay", + `{"wxpay":{"singleMin":1}}`) + _, ok := pcInstanceTypeLimits(inst, "alipay") + if ok { + t.Fatal("expected ok=false for missing type") + } + }) + + t.Run("invalid JSON returns false", func(t *testing.T) { + t.Parallel() + inst := makeInstance(1, "easypay", "alipay", `{bad json}`) + _, ok := pcInstanceTypeLimits(inst, "alipay") + if ok { + t.Fatal("expected ok=false for invalid JSON") + } + }) +} diff --git a/backend/internal/service/payment_config_plans.go b/backend/internal/service/payment_config_plans.go new file mode 100644 index 00000000..8a3e2950 --- /dev/null +++ b/backend/internal/service/payment_config_plans.go @@ -0,0 +1,147 @@ +package service + +import ( + "context" + "fmt" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/group" + "github.com/Wei-Shaw/sub2api/ent/subscriptionplan" + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" +) + +// --- Plan CRUD --- + +// PlanGroupInfo holds the group details needed for subscription plan display. +type PlanGroupInfo struct { + Platform string `json:"platform"` + Name string `json:"name"` + RateMultiplier float64 `json:"rate_multiplier"` + DailyLimitUSD *float64 `json:"daily_limit_usd"` + WeeklyLimitUSD *float64 `json:"weekly_limit_usd"` + MonthlyLimitUSD *float64 `json:"monthly_limit_usd"` + ModelScopes []string `json:"supported_model_scopes"` +} + +// GetGroupPlatformMap returns a map of group_id → platform for the given plans. +func (s *PaymentConfigService) GetGroupPlatformMap(ctx context.Context, plans []*dbent.SubscriptionPlan) map[int64]string { + info := s.GetGroupInfoMap(ctx, plans) + m := make(map[int64]string, len(info)) + for id, gi := range info { + m[id] = gi.Platform + } + return m +} + +// GetGroupInfoMap returns a map of group_id → PlanGroupInfo for the given plans. +func (s *PaymentConfigService) GetGroupInfoMap(ctx context.Context, plans []*dbent.SubscriptionPlan) map[int64]PlanGroupInfo { + ids := make([]int64, 0, len(plans)) + seen := make(map[int64]bool) + for _, p := range plans { + if !seen[p.GroupID] { + seen[p.GroupID] = true + ids = append(ids, p.GroupID) + } + } + if len(ids) == 0 { + return nil + } + groups, err := s.entClient.Group.Query().Where(group.IDIn(ids...)).All(ctx) + if err != nil { + return nil + } + m := make(map[int64]PlanGroupInfo, len(groups)) + for _, g := range groups { + m[int64(g.ID)] = PlanGroupInfo{ + Platform: g.Platform, + Name: g.Name, + RateMultiplier: g.RateMultiplier, + DailyLimitUSD: g.DailyLimitUsd, + WeeklyLimitUSD: g.WeeklyLimitUsd, + MonthlyLimitUSD: g.MonthlyLimitUsd, + ModelScopes: g.SupportedModelScopes, + } + } + return m +} + +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) +} + +// UpdatePlan updates a subscription plan by ID (patch semantics). +// NOTE: This function exceeds 30 lines due to per-field nil-check patch update boilerplate. +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 { + count, err := s.countPendingOrdersByPlan(ctx, id) + if err != nil { + return fmt.Errorf("check pending orders: %w", err) + } + if count > 0 { + return infraerrors.Conflict("PENDING_ORDERS", + fmt.Sprintf("this plan has %d in-progress orders and cannot be deleted — wait for orders to complete first", count)) + } + 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 +} diff --git a/backend/internal/service/payment_config_providers.go b/backend/internal/service/payment_config_providers.go new file mode 100644 index 00000000..10181914 --- /dev/null +++ b/backend/internal/service/payment_config_providers.go @@ -0,0 +1,286 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + "strings" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/paymentorder" + "github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance" + "github.com/Wei-Shaw/sub2api/internal/payment" + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" +) + +// --- Provider Instance CRUD --- + +func (s *PaymentConfigService) ListProviderInstances(ctx context.Context) ([]*dbent.PaymentProviderInstance, error) { + return s.entClient.PaymentProviderInstance.Query().Order(paymentproviderinstance.BySortOrder()).All(ctx) +} + +// ProviderInstanceResponse is the API response for a provider instance. +type ProviderInstanceResponse struct { + ID int64 `json:"id"` + ProviderKey string `json:"provider_key"` + Name string `json:"name"` + Config map[string]string `json:"config"` + SupportedTypes []string `json:"supported_types"` + Limits string `json:"limits"` + Enabled bool `json:"enabled"` + RefundEnabled bool `json:"refund_enabled"` + SortOrder int `json:"sort_order"` + PaymentMode string `json:"payment_mode"` +} + +// ListProviderInstancesWithConfig returns provider instances with decrypted config. +func (s *PaymentConfigService) ListProviderInstancesWithConfig(ctx context.Context) ([]ProviderInstanceResponse, error) { + instances, err := s.entClient.PaymentProviderInstance.Query(). + Order(paymentproviderinstance.BySortOrder()).All(ctx) + if err != nil { + return nil, err + } + result := make([]ProviderInstanceResponse, 0, len(instances)) + for _, inst := range instances { + resp := ProviderInstanceResponse{ + ID: int64(inst.ID), ProviderKey: inst.ProviderKey, Name: inst.Name, + SupportedTypes: splitTypes(inst.SupportedTypes), Limits: inst.Limits, + Enabled: inst.Enabled, RefundEnabled: inst.RefundEnabled, SortOrder: inst.SortOrder, + PaymentMode: inst.PaymentMode, + } + resp.Config, err = s.decryptAndMaskConfig(inst.Config) + if err != nil { + return nil, fmt.Errorf("decrypt config for instance %d: %w", inst.ID, err) + } + result = append(result, resp) + } + return result, nil +} + +func (s *PaymentConfigService) decryptAndMaskConfig(encrypted string) (map[string]string, error) { + return s.decryptConfig(encrypted) +} + +// pendingOrderStatuses are order statuses considered "in progress". +var pendingOrderStatuses = []string{ + payment.OrderStatusPending, + payment.OrderStatusPaid, + payment.OrderStatusRecharging, +} + +var sensitiveConfigPatterns = []string{"key", "pkey", "secret", "private", "password"} + +func isSensitiveConfigField(fieldName string) bool { + lower := strings.ToLower(fieldName) + for _, p := range sensitiveConfigPatterns { + if strings.Contains(lower, p) { + return true + } + } + return false +} + +func (s *PaymentConfigService) countPendingOrders(ctx context.Context, providerInstanceID int64) (int, error) { + return s.entClient.PaymentOrder.Query(). + Where( + paymentorder.ProviderInstanceIDEQ(strconv.FormatInt(providerInstanceID, 10)), + paymentorder.StatusIn(pendingOrderStatuses...), + ).Count(ctx) +} + +func (s *PaymentConfigService) countPendingOrdersByPlan(ctx context.Context, planID int64) (int, error) { + return s.entClient.PaymentOrder.Query(). + Where( + paymentorder.PlanIDEQ(planID), + paymentorder.StatusIn(pendingOrderStatuses...), + ).Count(ctx) +} + +var validProviderKeys = map[string]bool{ + payment.TypeEasyPay: true, payment.TypeAlipay: true, payment.TypeWxpay: true, payment.TypeStripe: true, +} + +func (s *PaymentConfigService) CreateProviderInstance(ctx context.Context, req CreateProviderInstanceRequest) (*dbent.PaymentProviderInstance, error) { + typesStr := joinTypes(req.SupportedTypes) + if err := validateProviderRequest(req.ProviderKey, req.Name, typesStr); err != nil { + return nil, err + } + 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(typesStr).SetEnabled(req.Enabled).SetPaymentMode(req.PaymentMode). + SetSortOrder(req.SortOrder).SetLimits(req.Limits).SetRefundEnabled(req.RefundEnabled). + Save(ctx) +} + +func validateProviderRequest(providerKey, name, supportedTypes string) error { + if strings.TrimSpace(name) == "" { + return infraerrors.BadRequest("VALIDATION_ERROR", "provider name is required") + } + if !validProviderKeys[providerKey] { + return infraerrors.BadRequest("VALIDATION_ERROR", fmt.Sprintf("invalid provider key: %s", providerKey)) + } + // supported_types can be empty (provider accepts no payment types until configured) + return nil +} + +// UpdateProviderInstance updates a provider instance by ID (patch semantics). +// NOTE: This function exceeds 30 lines due to per-field nil-check patch update +// boilerplate and pending-order safety checks. +func (s *PaymentConfigService) UpdateProviderInstance(ctx context.Context, id int64, req UpdateProviderInstanceRequest) (*dbent.PaymentProviderInstance, error) { + if req.Config != nil { + hasSensitive := false + for k := range req.Config { + if isSensitiveConfigField(k) && req.Config[k] != "" { + hasSensitive = true + break + } + } + if hasSensitive { + count, err := s.countPendingOrders(ctx, id) + if err != nil { + return nil, fmt.Errorf("check pending orders: %w", err) + } + if count > 0 { + return nil, infraerrors.Conflict("PENDING_ORDERS", "instance has pending orders"). + WithMetadata(map[string]string{"count": strconv.Itoa(count)}) + } + } + } + if req.Enabled != nil && !*req.Enabled { + count, err := s.countPendingOrders(ctx, id) + if err != nil { + return nil, fmt.Errorf("check pending orders: %w", err) + } + if count > 0 { + return nil, infraerrors.Conflict("PENDING_ORDERS", "instance has pending orders"). + WithMetadata(map[string]string{"count": strconv.Itoa(count)}) + } + } + u := s.entClient.PaymentProviderInstance.UpdateOneID(id) + if req.Name != nil { + u.SetName(*req.Name) + } + if req.Config != nil { + merged, err := s.mergeConfig(ctx, id, req.Config) + if err != nil { + return nil, err + } + enc, err := s.encryptConfig(merged) + if err != nil { + return nil, err + } + u.SetConfig(enc) + } + if req.SupportedTypes != nil { + // Check pending orders before removing payment types + count, err := s.countPendingOrders(ctx, id) + if err != nil { + return nil, fmt.Errorf("check pending orders: %w", err) + } + if count > 0 { + // Load current instance to compare types + inst, err := s.entClient.PaymentProviderInstance.Get(ctx, id) + if err != nil { + return nil, fmt.Errorf("load provider instance: %w", err) + } + oldTypes := strings.Split(inst.SupportedTypes, ",") + newTypes := req.SupportedTypes + for _, ot := range oldTypes { + ot = strings.TrimSpace(ot) + if ot == "" { + continue + } + found := false + for _, nt := range newTypes { + if strings.TrimSpace(nt) == ot { + found = true + break + } + } + if !found { + return nil, infraerrors.Conflict("PENDING_ORDERS", "cannot remove payment types while instance has pending orders"). + WithMetadata(map[string]string{"count": strconv.Itoa(count)}) + } + } + } + u.SetSupportedTypes(joinTypes(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) + } + if req.PaymentMode != nil { + u.SetPaymentMode(*req.PaymentMode) + } + return u.Save(ctx) +} + +func (s *PaymentConfigService) mergeConfig(ctx context.Context, id int64, newConfig map[string]string) (map[string]string, error) { + inst, err := s.entClient.PaymentProviderInstance.Get(ctx, id) + if err != nil { + return nil, fmt.Errorf("load existing provider: %w", err) + } + existing, err := s.decryptConfig(inst.Config) + if err != nil { + return nil, fmt.Errorf("decrypt existing config for instance %d: %w", id, err) + } + if existing == nil { + return newConfig, nil + } + for k, v := range newConfig { + existing[k] = v + } + return existing, nil +} + +func (s *PaymentConfigService) decryptConfig(encrypted string) (map[string]string, error) { + if encrypted == "" { + return nil, nil + } + decrypted, err := payment.Decrypt(encrypted, s.encryptionKey) + if err != nil { + return nil, fmt.Errorf("decrypt config: %w", err) + } + var raw map[string]string + if err := json.Unmarshal([]byte(decrypted), &raw); err != nil { + return nil, fmt.Errorf("unmarshal decrypted config: %w", err) + } + return raw, nil +} + +func (s *PaymentConfigService) DeleteProviderInstance(ctx context.Context, id int64) error { + count, err := s.countPendingOrders(ctx, id) + if err != nil { + return fmt.Errorf("check pending orders: %w", err) + } + if count > 0 { + return infraerrors.Conflict("PENDING_ORDERS", + fmt.Sprintf("this instance has %d in-progress orders and cannot be deleted — wait for orders to complete or disable the instance first", count)) + } + 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 +} diff --git a/backend/internal/service/payment_config_providers_test.go b/backend/internal/service/payment_config_providers_test.go new file mode 100644 index 00000000..e71eb9f5 --- /dev/null +++ b/backend/internal/service/payment_config_providers_test.go @@ -0,0 +1,187 @@ +//go:build unit + +package service + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidateProviderRequest(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + providerKey string + providerName string + supportedTypes string + wantErr bool + errContains string + }{ + { + name: "valid easypay with types", + providerKey: "easypay", + providerName: "MyProvider", + supportedTypes: "alipay,wxpay", + wantErr: false, + }, + { + name: "valid stripe with empty types", + providerKey: "stripe", + providerName: "Stripe Provider", + supportedTypes: "", + wantErr: false, + }, + { + name: "valid alipay provider", + providerKey: "alipay", + providerName: "Alipay Direct", + supportedTypes: "alipay", + wantErr: false, + }, + { + name: "valid wxpay provider", + providerKey: "wxpay", + providerName: "WeChat Pay", + supportedTypes: "wxpay", + wantErr: false, + }, + { + name: "invalid provider key", + providerKey: "invalid", + providerName: "Name", + supportedTypes: "alipay", + wantErr: true, + errContains: "invalid provider key", + }, + { + name: "empty name", + providerKey: "easypay", + providerName: "", + supportedTypes: "alipay", + wantErr: true, + errContains: "provider name is required", + }, + { + name: "whitespace-only name", + providerKey: "easypay", + providerName: " ", + supportedTypes: "alipay", + wantErr: true, + errContains: "provider name is required", + }, + { + name: "tab-only name", + providerKey: "easypay", + providerName: "\t", + supportedTypes: "alipay", + wantErr: true, + errContains: "provider name is required", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + err := validateProviderRequest(tc.providerKey, tc.providerName, tc.supportedTypes) + if tc.wantErr { + require.Error(t, err) + assert.Contains(t, err.Error(), tc.errContains) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestIsSensitiveConfigField(t *testing.T) { + t.Parallel() + + tests := []struct { + field string + wantSen bool + }{ + // Sensitive fields (contain key/secret/private/password/pkey patterns) + {"secretKey", true}, + {"apiSecret", true}, + {"pkey", true}, + {"privateKey", true}, + {"apiPassword", true}, + {"appKey", true}, + {"SECRET_TOKEN", true}, + {"PrivateData", true}, + {"PASSWORD", true}, + {"mySecretValue", true}, + + // Non-sensitive fields + {"appId", false}, + {"mchId", false}, + {"apiBase", false}, + {"endpoint", false}, + {"merchantNo", false}, + {"paymentMode", false}, + {"notifyUrl", false}, + } + + for _, tc := range tests { + t.Run(tc.field, func(t *testing.T) { + t.Parallel() + + got := isSensitiveConfigField(tc.field) + assert.Equal(t, tc.wantSen, got, "isSensitiveConfigField(%q)", tc.field) + }) + } +} + +func TestJoinTypes(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input []string + want string + }{ + { + name: "multiple types", + input: []string{"alipay", "wxpay"}, + want: "alipay,wxpay", + }, + { + name: "single type", + input: []string{"stripe"}, + want: "stripe", + }, + { + name: "empty slice", + input: []string{}, + want: "", + }, + { + name: "nil slice", + input: nil, + want: "", + }, + { + name: "three types", + input: []string{"alipay", "wxpay", "stripe"}, + want: "alipay,wxpay,stripe", + }, + { + name: "types with spaces are not trimmed", + input: []string{" alipay ", " wxpay "}, + want: " alipay , wxpay ", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + got := joinTypes(tc.input) + assert.Equal(t, tc.want, got) + }) + } +} diff --git a/backend/internal/service/payment_config_service.go b/backend/internal/service/payment_config_service.go new file mode 100644 index 00000000..9042c3ab --- /dev/null +++ b/backend/internal/service/payment_config_service.go @@ -0,0 +1,351 @@ +package service + +import ( + "context" + "fmt" + "strconv" + "strings" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance" + "github.com/Wei-Shaw/sub2api/internal/payment" +) + +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" + SettingHelpImageURL = "PAYMENT_HELP_IMAGE_URL" + SettingHelpText = "PAYMENT_HELP_TEXT" + 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" +) + +// Default values for payment configuration settings. +const ( + defaultOrderTimeoutMin = 30 + defaultMaxPendingOrders = 3 +) + +// 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"` + HelpImageURL string `json:"help_image_url"` + HelpText string `json:"help_text"` + StripePublishableKey string `json:"stripe_publishable_key,omitempty"` + + // Cancel rate limit settings + CancelRateLimitEnabled bool `json:"cancel_rate_limit_enabled"` + CancelRateLimitMax int `json:"cancel_rate_limit_max"` + CancelRateLimitWindow int `json:"cancel_rate_limit_window"` + CancelRateLimitUnit string `json:"cancel_rate_limit_unit"` + CancelRateLimitMode string `json:"cancel_rate_limit_window_mode"` +} + +// 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"` + HelpImageURL *string `json:"help_image_url"` + HelpText *string `json:"help_text"` + + // Cancel rate limit settings + CancelRateLimitEnabled *bool `json:"cancel_rate_limit_enabled"` + CancelRateLimitMax *int `json:"cancel_rate_limit_max"` + CancelRateLimitWindow *int `json:"cancel_rate_limit_window"` + CancelRateLimitUnit *string `json:"cancel_rate_limit_unit"` + CancelRateLimitMode *string `json:"cancel_rate_limit_window_mode"` +} + +// MethodLimits holds per-payment-type limits. +type MethodLimits struct { + PaymentType string `json:"payment_type"` + FeeRate float64 `json:"fee_rate"` + DailyLimit float64 `json:"daily_limit"` + SingleMin float64 `json:"single_min"` + SingleMax float64 `json:"single_max"` +} + +// MethodLimitsResponse is the full response for the user-facing /limits API. +// It includes per-method limits and the global widest range (union of all methods). +type MethodLimitsResponse struct { + Methods map[string]MethodLimits `json:"methods"` + GlobalMin float64 `json:"global_min"` // 0 = no minimum + GlobalMax float64 `json:"global_max"` // 0 = no maximum +} + +type CreateProviderInstanceRequest struct { + ProviderKey string `json:"provider_key"` + Name string `json:"name"` + Config map[string]string `json:"config"` + SupportedTypes []string `json:"supported_types"` + Enabled bool `json:"enabled"` + PaymentMode string `json:"payment_mode"` + SortOrder int `json:"sort_order"` + Limits string `json:"limits"` + RefundEnabled bool `json:"refund_enabled"` +} + +type UpdateProviderInstanceRequest struct { + Name *string `json:"name"` + Config map[string]string `json:"config"` + SupportedTypes []string `json:"supported_types"` + Enabled *bool `json:"enabled"` + PaymentMode *string `json:"payment_mode"` + SortOrder *int `json:"sort_order"` + Limits *string `json:"limits"` + RefundEnabled *bool `json:"refund_enabled"` +} +type CreatePlanRequest struct { + GroupID int64 `json:"group_id"` + Name string `json:"name"` + Description string `json:"description"` + Price float64 `json:"price"` + OriginalPrice *float64 `json:"original_price"` + ValidityDays int `json:"validity_days"` + ValidityUnit string `json:"validity_unit"` + Features string `json:"features"` + ProductName string `json:"product_name"` + ForSale bool `json:"for_sale"` + SortOrder int `json:"sort_order"` +} + +type UpdatePlanRequest struct { + GroupID *int64 `json:"group_id"` + Name *string `json:"name"` + Description *string `json:"description"` + Price *float64 `json:"price"` + OriginalPrice *float64 `json:"original_price"` + ValidityDays *int `json:"validity_days"` + ValidityUnit *string `json:"validity_unit"` + Features *string `json:"features"` + ProductName *string `json:"product_name"` + ForSale *bool `json:"for_sale"` + SortOrder *int `json:"sort_order"` +} + +// 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, + SettingHelpImageURL, SettingHelpText, + SettingCancelRateLimitOn, SettingCancelRateLimitMax, + SettingCancelWindowSize, SettingCancelWindowUnit, SettingCancelWindowMode, + } + vals, err := s.settingRepo.GetMultiple(ctx, keys) + if err != nil { + return nil, fmt.Errorf("get payment config settings: %w", err) + } + cfg := s.parsePaymentConfig(vals) + // Load Stripe publishable key from the first enabled Stripe provider instance + cfg.StripePublishableKey = s.getStripePublishableKey(ctx) + return cfg, 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], 0), + DailyLimit: pcParseFloat(vals[SettingDailyRechargeLimit], 0), + OrderTimeoutMin: pcParseInt(vals[SettingOrderTimeoutMinutes], defaultOrderTimeoutMin), + MaxPendingOrders: pcParseInt(vals[SettingMaxPendingOrders], defaultMaxPendingOrders), + BalanceDisabled: vals[SettingBalancePayDisabled] == "true", + LoadBalanceStrategy: vals[SettingLoadBalanceStrategy], + ProductNamePrefix: vals[SettingProductNamePrefix], + ProductNameSuffix: vals[SettingProductNameSuffix], + HelpImageURL: vals[SettingHelpImageURL], + HelpText: vals[SettingHelpText], + + CancelRateLimitEnabled: vals[SettingCancelRateLimitOn] == "true", + CancelRateLimitMax: pcParseInt(vals[SettingCancelRateLimitMax], 10), + CancelRateLimitWindow: pcParseInt(vals[SettingCancelWindowSize], 1), + CancelRateLimitUnit: vals[SettingCancelWindowUnit], + CancelRateLimitMode: vals[SettingCancelWindowMode], + } + if cfg.LoadBalanceStrategy == "" { + cfg.LoadBalanceStrategy = payment.DefaultLoadBalanceStrategy + } + 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 +} + +// getStripePublishableKey finds the publishable key from the first enabled Stripe provider instance. +func (s *PaymentConfigService) getStripePublishableKey(ctx context.Context) string { + instances, err := s.entClient.PaymentProviderInstance.Query(). + Where( + paymentproviderinstance.EnabledEQ(true), + paymentproviderinstance.ProviderKeyEQ(payment.TypeStripe), + ).Limit(1).All(ctx) + if err != nil || len(instances) == 0 { + return "" + } + cfg, err := s.decryptConfig(instances[0].Config) + if err != nil || cfg == nil { + return "" + } + return cfg[payment.ConfigKeyPublishableKey] +} + +// UpdatePaymentConfig updates the payment configuration settings. +// NOTE: This function exceeds 30 lines because each field requires an independent +// nil-check before serialisation — this is inherent to patch-style update patterns +// and cannot be meaningfully decomposed without introducing unnecessary abstraction. +func (s *PaymentConfigService) UpdatePaymentConfig(ctx context.Context, req UpdatePaymentConfigRequest) error { + m := map[string]string{ + SettingPaymentEnabled: formatBoolOrEmpty(req.Enabled), + SettingMinRechargeAmount: formatPositiveFloat(req.MinAmount), + SettingMaxRechargeAmount: formatPositiveFloat(req.MaxAmount), + SettingDailyRechargeLimit: formatPositiveFloat(req.DailyLimit), + SettingOrderTimeoutMinutes: formatPositiveInt(req.OrderTimeoutMin), + SettingMaxPendingOrders: formatPositiveInt(req.MaxPendingOrders), + SettingBalancePayDisabled: formatBoolOrEmpty(req.BalanceDisabled), + SettingLoadBalanceStrategy: derefStr(req.LoadBalanceStrategy), + SettingProductNamePrefix: derefStr(req.ProductNamePrefix), + SettingProductNameSuffix: derefStr(req.ProductNameSuffix), + SettingHelpImageURL: derefStr(req.HelpImageURL), + SettingHelpText: derefStr(req.HelpText), + SettingCancelRateLimitOn: formatBoolOrEmpty(req.CancelRateLimitEnabled), + SettingCancelRateLimitMax: formatPositiveInt(req.CancelRateLimitMax), + SettingCancelWindowSize: formatPositiveInt(req.CancelRateLimitWindow), + SettingCancelWindowUnit: derefStr(req.CancelRateLimitUnit), + SettingCancelWindowMode: derefStr(req.CancelRateLimitMode), + } + if req.EnabledTypes != nil { + m[SettingEnabledPaymentTypes] = strings.Join(req.EnabledTypes, ",") + } else { + m[SettingEnabledPaymentTypes] = "" + } + return s.settingRepo.SetMultiple(ctx, m) +} + +func formatBoolOrEmpty(v *bool) string { + if v == nil { + return "" + } + return strconv.FormatBool(*v) +} + +func formatPositiveFloat(v *float64) string { + if v == nil || *v <= 0 { + return "" // empty → parsePaymentConfig uses default + } + return strconv.FormatFloat(*v, 'f', 2, 64) +} + +func formatPositiveInt(v *int) string { + if v == nil || *v <= 0 { + return "" + } + return strconv.Itoa(*v) +} + +func derefStr(v *string) string { + if v == nil { + return "" + } + return *v +} + +func splitTypes(s string) []string { + if s == "" { + return nil + } + parts := strings.Split(s, ",") + result := make([]string, 0, len(parts)) + for _, p := range parts { + p = strings.TrimSpace(p) + if p != "" { + result = append(result, p) + } + } + return result +} + +func joinTypes(types []string) string { + return strings.Join(types, ",") +} + +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 +} diff --git a/backend/internal/service/payment_config_service_test.go b/backend/internal/service/payment_config_service_test.go new file mode 100644 index 00000000..027bb796 --- /dev/null +++ b/backend/internal/service/payment_config_service_test.go @@ -0,0 +1,206 @@ +package service + +import ( + "testing" + + "github.com/Wei-Shaw/sub2api/internal/payment" +) + +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 != 0 { + t.Fatalf("expected MaxAmount=0 (no limit), 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 != payment.DefaultLoadBalanceStrategy { + t.Fatalf("expected LoadBalanceStrategy=%s, got %q", payment.DefaultLoadBalanceStrategy, 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() + + tests := []struct { + input string + expected string + }{ + {payment.TypeEasyPay, payment.TypeEasyPay}, + {payment.TypeStripe, payment.TypeStripe}, + {payment.TypeCard, payment.TypeStripe}, + {payment.TypeLink, payment.TypeStripe}, + {payment.TypeAlipay, payment.TypeAlipay}, + {payment.TypeAlipayDirect, payment.TypeAlipay}, + {payment.TypeWxpay, payment.TypeWxpay}, + {payment.TypeWxpayDirect, payment.TypeWxpay}, + {"unknown", "unknown"}, + {"", ""}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + t.Parallel() + got := payment.GetBasePaymentType(tt.input) + if got != tt.expected { + t.Fatalf("GetBasePaymentType(%q) = %q, want %q", tt.input, got, tt.expected) + } + }) + } +} diff --git a/backend/internal/service/payment_fulfillment.go b/backend/internal/service/payment_fulfillment.go new file mode 100644 index 00000000..de41d742 --- /dev/null +++ b/backend/internal/service/payment_fulfillment.go @@ -0,0 +1,325 @@ +package service + +import ( + "context" + "fmt" + "log/slog" + "math" + "strconv" + "strings" + "time" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/paymentauditlog" + "github.com/Wei-Shaw/sub2api/ent/paymentorder" + "github.com/Wei-Shaw/sub2api/internal/payment" + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" +) + +// --- Payment Notification & Fulfillment --- + +func (s *PaymentService) HandlePaymentNotification(ctx context.Context, n *payment.PaymentNotification, pk string) error { + if n.Status != payment.NotificationStatusSuccess { + return nil + } + // Look up order by out_trade_no (the external order ID we sent to the provider) + order, err := s.entClient.PaymentOrder.Query().Where(paymentorder.OutTradeNo(n.OrderID)).Only(ctx) + if err != nil { + // Fallback: try legacy format (sub2_N where N is DB ID) + trimmed := strings.TrimPrefix(n.OrderID, orderIDPrefix) + if oid, parseErr := strconv.ParseInt(trimmed, 10, 64); parseErr == nil { + return s.confirmPayment(ctx, oid, n.TradeNo, n.Amount, pk) + } + return fmt.Errorf("order not found for out_trade_no: %s", n.OrderID) + } + return s.confirmPayment(ctx, order.ID, n.TradeNo, n.Amount, pk) +} + +func (s *PaymentService) confirmPayment(ctx context.Context, oid int64, tradeNo string, paid float64, pk string) error { + o, err := s.entClient.PaymentOrder.Get(ctx, oid) + if err != nil { + slog.Error("order not found", "orderID", oid) + return nil + } + // Skip amount check when paid=0 (e.g. QueryOrder doesn't return amount). + // Also skip if paid is NaN/Inf (malformed provider data). + if paid > 0 && !math.IsNaN(paid) && !math.IsInf(paid, 0) { + if math.Abs(paid-o.PayAmount) > amountToleranceCNY { + s.writeAuditLog(ctx, o.ID, "PAYMENT_AMOUNT_MISMATCH", pk, map[string]any{"expected": o.PayAmount, "paid": paid, "tradeNo": tradeNo}) + return fmt.Errorf("amount mismatch: expected %.2f, got %.2f", o.PayAmount, paid) + } + } + // Use order's expected amount when provider didn't report one + if paid <= 0 || math.IsNaN(paid) || math.IsInf(paid, 0) { + paid = o.PayAmount + } + return s.toPaid(ctx, o, tradeNo, paid, pk) +} + +func (s *PaymentService) toPaid(ctx context.Context, o *dbent.PaymentOrder, tradeNo string, paid float64, pk string) error { + previousStatus := o.Status + now := time.Now() + grace := now.Add(-paymentGraceMinutes * time.Minute) + c, err := s.entClient.PaymentOrder.Update().Where( + paymentorder.IDEQ(o.ID), + paymentorder.Or( + paymentorder.StatusEQ(OrderStatusPending), + paymentorder.StatusEQ(OrderStatusCancelled), + paymentorder.And( + paymentorder.StatusEQ(OrderStatusExpired), + paymentorder.UpdatedAtGTE(grace), + ), + ), + ).SetStatus(OrderStatusPaid).SetPayAmount(paid).SetPaymentTradeNo(tradeNo).SetPaidAt(now).ClearFailedAt().ClearFailedReason().Save(ctx) + if err != nil { + return fmt.Errorf("update to PAID: %w", err) + } + if c == 0 { + return s.alreadyProcessed(ctx, o) + } + if previousStatus == OrderStatusCancelled || previousStatus == OrderStatusExpired { + slog.Info("order recovered from webhook payment success", + "orderID", o.ID, + "previousStatus", previousStatus, + "tradeNo", tradeNo, + "provider", pk, + ) + s.writeAuditLog(ctx, o.ID, "ORDER_RECOVERED", pk, map[string]any{ + "previous_status": previousStatus, + "tradeNo": tradeNo, + "paidAmount": paid, + "reason": "webhook payment success received after order " + previousStatus, + }) + } + s.writeAuditLog(ctx, o.ID, "ORDER_PAID", pk, map[string]any{"tradeNo": tradeNo, "paidAmount": paid}) + return s.executeFulfillment(ctx, o.ID) +} + +func (s *PaymentService) alreadyProcessed(ctx context.Context, o *dbent.PaymentOrder) error { + cur, err := s.entClient.PaymentOrder.Get(ctx, o.ID) + if err != nil { + return nil + } + switch cur.Status { + case OrderStatusCompleted, OrderStatusRefunded: + return nil + case OrderStatusFailed: + return s.executeFulfillment(ctx, o.ID) + case OrderStatusPaid, OrderStatusRecharging: + return fmt.Errorf("order %d is being processed", o.ID) + case OrderStatusExpired: + slog.Warn("webhook payment success for expired order beyond grace period", + "orderID", o.ID, + "status", cur.Status, + "updatedAt", cur.UpdatedAt, + ) + s.writeAuditLog(ctx, o.ID, "PAYMENT_AFTER_EXPIRY", "system", map[string]any{ + "status": cur.Status, + "updatedAt": cur.UpdatedAt, + "reason": "payment arrived after expiry grace period", + }) + return nil + default: + return nil + } +} + +func (s *PaymentService) executeFulfillment(ctx context.Context, oid int64) error { + o, err := s.entClient.PaymentOrder.Get(ctx, oid) + if err != nil { + return fmt.Errorf("get order: %w", err) + } + if o.OrderType == payment.OrderTypeSubscription { + return s.ExecuteSubscriptionFulfillment(ctx, oid) + } + return s.ExecuteBalanceFulfillment(ctx, oid) +} + +func (s *PaymentService) ExecuteBalanceFulfillment(ctx context.Context, oid int64) error { + o, err := s.entClient.PaymentOrder.Get(ctx, oid) + if err != nil { + return infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.Status == OrderStatusCompleted { + return nil + } + if psIsRefundStatus(o.Status) { + return infraerrors.BadRequest("INVALID_STATUS", "refund-related order cannot fulfill") + } + if o.Status != OrderStatusPaid && o.Status != OrderStatusFailed { + return infraerrors.BadRequest("INVALID_STATUS", "order cannot fulfill in status "+o.Status) + } + c, err := s.entClient.PaymentOrder.Update().Where(paymentorder.IDEQ(oid), paymentorder.StatusIn(OrderStatusPaid, OrderStatusFailed)).SetStatus(OrderStatusRecharging).Save(ctx) + if err != nil { + return fmt.Errorf("lock: %w", err) + } + if c == 0 { + return nil + } + if err := s.doBalance(ctx, o); err != nil { + s.markFailed(ctx, oid, err) + return err + } + return nil +} + +// redeemAction represents the idempotency decision for balance fulfillment. +type redeemAction int + +const ( + // redeemActionCreate: code does not exist — create it, then redeem. + redeemActionCreate redeemAction = iota + // redeemActionRedeem: code exists but is unused — skip creation, redeem only. + redeemActionRedeem + // redeemActionSkipCompleted: code exists and is already used — skip to mark completed. + redeemActionSkipCompleted +) + +// resolveRedeemAction decides the idempotency action based on an existing redeem code lookup. +// existing is the result of GetByCode; lookupErr is the error from that call. +func resolveRedeemAction(existing *RedeemCode, lookupErr error) redeemAction { + if existing == nil || lookupErr != nil { + return redeemActionCreate + } + if existing.IsUsed() { + return redeemActionSkipCompleted + } + return redeemActionRedeem +} + +func (s *PaymentService) doBalance(ctx context.Context, o *dbent.PaymentOrder) error { + // Idempotency: check if redeem code already exists (from a previous partial run) + existing, lookupErr := s.redeemService.GetByCode(ctx, o.RechargeCode) + action := resolveRedeemAction(existing, lookupErr) + + switch action { + case redeemActionSkipCompleted: + // Code already created and redeemed — just mark completed + return s.markCompleted(ctx, o, "RECHARGE_SUCCESS") + case redeemActionCreate: + rc := &RedeemCode{Code: o.RechargeCode, Type: RedeemTypeBalance, Value: o.Amount, Status: StatusUnused} + if err := s.redeemService.CreateCode(ctx, rc); err != nil { + return fmt.Errorf("create redeem code: %w", err) + } + case redeemActionRedeem: + // Code exists but unused — skip creation, proceed to redeem + } + if _, err := s.redeemService.Redeem(ctx, o.UserID, o.RechargeCode); err != nil { + return fmt.Errorf("redeem balance: %w", err) + } + return s.markCompleted(ctx, o, "RECHARGE_SUCCESS") +} + +func (s *PaymentService) markCompleted(ctx context.Context, o *dbent.PaymentOrder, auditAction string) error { + now := time.Now() + _, err := s.entClient.PaymentOrder.Update().Where(paymentorder.IDEQ(o.ID), paymentorder.StatusEQ(OrderStatusRecharging)).SetStatus(OrderStatusCompleted).SetCompletedAt(now).Save(ctx) + if err != nil { + return fmt.Errorf("mark completed: %w", err) + } + s.writeAuditLog(ctx, o.ID, auditAction, "system", map[string]any{"rechargeCode": o.RechargeCode, "amount": o.Amount}) + return nil +} + +func (s *PaymentService) ExecuteSubscriptionFulfillment(ctx context.Context, oid int64) error { + o, err := s.entClient.PaymentOrder.Get(ctx, oid) + if err != nil { + return infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.Status == OrderStatusCompleted { + return nil + } + if psIsRefundStatus(o.Status) { + return infraerrors.BadRequest("INVALID_STATUS", "refund-related order cannot fulfill") + } + if o.Status != OrderStatusPaid && o.Status != OrderStatusFailed { + return infraerrors.BadRequest("INVALID_STATUS", "order cannot fulfill in status "+o.Status) + } + if o.SubscriptionGroupID == nil || o.SubscriptionDays == nil { + return infraerrors.BadRequest("INVALID_STATUS", "missing subscription info") + } + c, err := s.entClient.PaymentOrder.Update().Where(paymentorder.IDEQ(oid), paymentorder.StatusIn(OrderStatusPaid, OrderStatusFailed)).SetStatus(OrderStatusRecharging).Save(ctx) + if err != nil { + return fmt.Errorf("lock: %w", err) + } + if c == 0 { + return nil + } + if err := s.doSub(ctx, o); err != nil { + s.markFailed(ctx, oid, err) + return err + } + return nil +} + +func (s *PaymentService) doSub(ctx context.Context, o *dbent.PaymentOrder) error { + gid := *o.SubscriptionGroupID + days := *o.SubscriptionDays + g, err := s.groupRepo.GetByID(ctx, gid) + if err != nil || g.Status != payment.EntityStatusActive { + return fmt.Errorf("group %d no longer exists or inactive", gid) + } + // Idempotency: check audit log to see if subscription was already assigned. + // Prevents double-extension on retry after markCompleted fails. + if s.hasAuditLog(ctx, o.ID, "SUBSCRIPTION_SUCCESS") { + slog.Info("subscription already assigned for order, skipping", "orderID", o.ID, "groupID", gid) + return s.markCompleted(ctx, o, "SUBSCRIPTION_SUCCESS") + } + orderNote := fmt.Sprintf("payment order %d", o.ID) + _, _, err = s.subscriptionSvc.AssignOrExtendSubscription(ctx, &AssignSubscriptionInput{UserID: o.UserID, GroupID: gid, ValidityDays: days, AssignedBy: 0, Notes: orderNote}) + if err != nil { + return fmt.Errorf("assign subscription: %w", err) + } + return s.markCompleted(ctx, o, "SUBSCRIPTION_SUCCESS") +} + +func (s *PaymentService) hasAuditLog(ctx context.Context, orderID int64, action string) bool { + oid := strconv.FormatInt(orderID, 10) + c, _ := s.entClient.PaymentAuditLog.Query(). + Where(paymentauditlog.OrderIDEQ(oid), paymentauditlog.ActionEQ(action)). + Limit(1).Count(ctx) + return c > 0 +} + +func (s *PaymentService) markFailed(ctx context.Context, oid int64, cause error) { + now := time.Now() + r := psErrMsg(cause) + // Only mark FAILED if still in RECHARGING state — prevents overwriting + // a COMPLETED order when markCompleted failed but fulfillment succeeded. + c, e := s.entClient.PaymentOrder.Update(). + Where(paymentorder.IDEQ(oid), paymentorder.StatusEQ(OrderStatusRecharging)). + SetStatus(OrderStatusFailed).SetFailedAt(now).SetFailedReason(r).Save(ctx) + if e != nil { + slog.Error("mark FAILED", "orderID", oid, "error", e) + } + if c > 0 { + s.writeAuditLog(ctx, oid, "FULFILLMENT_FAILED", "system", map[string]any{"reason": r}) + } +} + +func (s *PaymentService) RetryFulfillment(ctx context.Context, oid int64) error { + o, err := s.entClient.PaymentOrder.Get(ctx, oid) + if err != nil { + return infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.PaidAt == nil { + return infraerrors.BadRequest("INVALID_STATUS", "order is not paid") + } + if psIsRefundStatus(o.Status) { + return infraerrors.BadRequest("INVALID_STATUS", "refund-related order cannot retry") + } + if o.Status == OrderStatusRecharging { + return infraerrors.Conflict("CONFLICT", "order is being processed") + } + if o.Status == OrderStatusCompleted { + return infraerrors.BadRequest("INVALID_STATUS", "order already completed") + } + if o.Status != OrderStatusFailed && o.Status != OrderStatusPaid { + return infraerrors.BadRequest("INVALID_STATUS", "only paid and failed orders can retry") + } + _, err = s.entClient.PaymentOrder.Update().Where(paymentorder.IDEQ(oid), paymentorder.StatusIn(OrderStatusFailed, OrderStatusPaid)).SetStatus(OrderStatusPaid).ClearFailedAt().ClearFailedReason().Save(ctx) + if err != nil { + return fmt.Errorf("reset for retry: %w", err) + } + s.writeAuditLog(ctx, oid, "RECHARGE_RETRY", "admin", map[string]any{"detail": "admin manual retry"}) + return s.executeFulfillment(ctx, oid) +} diff --git a/backend/internal/service/payment_fulfillment_test.go b/backend/internal/service/payment_fulfillment_test.go new file mode 100644 index 00000000..625b0d9f --- /dev/null +++ b/backend/internal/service/payment_fulfillment_test.go @@ -0,0 +1,163 @@ +//go:build unit + +package service + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +// --------------------------------------------------------------------------- +// resolveRedeemAction — pure idempotency decision logic +// --------------------------------------------------------------------------- + +func TestResolveRedeemAction_CodeNotFound(t *testing.T) { + t.Parallel() + action := resolveRedeemAction(nil, nil) + assert.Equal(t, redeemActionCreate, action, "nil code with nil error should create") +} + +func TestResolveRedeemAction_LookupError(t *testing.T) { + t.Parallel() + action := resolveRedeemAction(nil, errors.New("db connection lost")) + assert.Equal(t, redeemActionCreate, action, "lookup error should fall back to create") +} + +func TestResolveRedeemAction_LookupErrorWithNonNilCode(t *testing.T) { + t.Parallel() + // Edge case: both code and error are non-nil (shouldn't happen in practice, + // but the function should still treat error as authoritative) + code := &RedeemCode{Status: StatusUnused} + action := resolveRedeemAction(code, errors.New("partial error")) + assert.Equal(t, redeemActionCreate, action, "non-nil error should always result in create regardless of code") +} + +func TestResolveRedeemAction_CodeExistsAndUsed(t *testing.T) { + t.Parallel() + code := &RedeemCode{ + Code: "test-code-123", + Status: StatusUsed, + Type: RedeemTypeBalance, + Value: 10.0, + } + action := resolveRedeemAction(code, nil) + assert.Equal(t, redeemActionSkipCompleted, action, "used code should skip to completed") +} + +func TestResolveRedeemAction_CodeExistsAndUnused(t *testing.T) { + t.Parallel() + code := &RedeemCode{ + Code: "test-code-456", + Status: StatusUnused, + Type: RedeemTypeBalance, + Value: 25.0, + } + action := resolveRedeemAction(code, nil) + assert.Equal(t, redeemActionRedeem, action, "unused code should skip creation and proceed to redeem") +} + +func TestResolveRedeemAction_CodeExistsWithExpiredStatus(t *testing.T) { + t.Parallel() + // A code with a non-standard status (neither "unused" nor "used") + // should NOT be treated as used, so it falls through to redeemActionRedeem. + code := &RedeemCode{ + Code: "expired-code", + Status: StatusExpired, + } + action := resolveRedeemAction(code, nil) + assert.Equal(t, redeemActionRedeem, action, "expired-status code is not IsUsed(), should redeem") +} + +// --------------------------------------------------------------------------- +// Table-driven comprehensive test +// --------------------------------------------------------------------------- + +func TestResolveRedeemAction_Table(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + code *RedeemCode + err error + expected redeemAction + }{ + { + name: "nil code, nil error — first run", + code: nil, + err: nil, + expected: redeemActionCreate, + }, + { + name: "nil code, lookup error — treat as not found", + code: nil, + err: ErrRedeemCodeNotFound, + expected: redeemActionCreate, + }, + { + name: "nil code, generic DB error — treat as not found", + code: nil, + err: errors.New("connection refused"), + expected: redeemActionCreate, + }, + { + name: "code exists, used — previous run completed redeem", + code: &RedeemCode{Status: StatusUsed}, + err: nil, + expected: redeemActionSkipCompleted, + }, + { + name: "code exists, unused — previous run created code but crashed before redeem", + code: &RedeemCode{Status: StatusUnused}, + err: nil, + expected: redeemActionRedeem, + }, + { + name: "code exists but error also set — error takes precedence", + code: &RedeemCode{Status: StatusUsed}, + err: errors.New("unexpected"), + expected: redeemActionCreate, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := resolveRedeemAction(tt.code, tt.err) + assert.Equal(t, tt.expected, got) + }) + } +} + +// --------------------------------------------------------------------------- +// redeemAction enum value sanity +// --------------------------------------------------------------------------- + +func TestRedeemAction_DistinctValues(t *testing.T) { + t.Parallel() + // Ensure the three actions have distinct values (iota correctness) + assert.NotEqual(t, redeemActionCreate, redeemActionRedeem) + assert.NotEqual(t, redeemActionCreate, redeemActionSkipCompleted) + assert.NotEqual(t, redeemActionRedeem, redeemActionSkipCompleted) +} + +// --------------------------------------------------------------------------- +// RedeemCode.IsUsed / CanUse interaction with resolveRedeemAction +// --------------------------------------------------------------------------- + +func TestResolveRedeemAction_IsUsedCanUseConsistency(t *testing.T) { + t.Parallel() + + usedCode := &RedeemCode{Status: StatusUsed} + unusedCode := &RedeemCode{Status: StatusUnused} + + // Verify our decision function is consistent with the domain model methods + assert.True(t, usedCode.IsUsed()) + assert.False(t, usedCode.CanUse()) + assert.Equal(t, redeemActionSkipCompleted, resolveRedeemAction(usedCode, nil)) + + assert.False(t, unusedCode.IsUsed()) + assert.True(t, unusedCode.CanUse()) + assert.Equal(t, redeemActionRedeem, resolveRedeemAction(unusedCode, nil)) +} diff --git a/backend/internal/service/payment_order.go b/backend/internal/service/payment_order.go new file mode 100644 index 00000000..9de029e6 --- /dev/null +++ b/backend/internal/service/payment_order.go @@ -0,0 +1,546 @@ +package service + +import ( + "context" + "fmt" + "log/slog" + "math" + "strconv" + "strings" + "time" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/paymentauditlog" + "github.com/Wei-Shaw/sub2api/ent/paymentorder" + "github.com/Wei-Shaw/sub2api/internal/payment" + "github.com/Wei-Shaw/sub2api/internal/payment/provider" + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" +) + +// --- Order Creation --- + +func (s *PaymentService) CreateOrder(ctx context.Context, req CreateOrderRequest) (*CreateOrderResponse, error) { + if req.OrderType == "" { + req.OrderType = payment.OrderTypeBalance + } + cfg, err := s.configService.GetPaymentConfig(ctx) + if err != nil { + return nil, fmt.Errorf("get payment config: %w", err) + } + if !cfg.Enabled { + return nil, infraerrors.Forbidden("PAYMENT_DISABLED", "payment system is disabled") + } + plan, err := s.validateOrderInput(ctx, req, cfg) + if err != nil { + return nil, err + } + if err := s.checkCancelRateLimit(ctx, req.UserID, cfg); err != nil { + return nil, err + } + user, err := s.userRepo.GetByID(ctx, req.UserID) + if err != nil { + return nil, fmt.Errorf("get user: %w", err) + } + if user.Status != payment.EntityStatusActive { + return nil, infraerrors.Forbidden("USER_INACTIVE", "user account is disabled") + } + amount := req.Amount + if plan != nil { + amount = plan.Price + } + feeRate := s.getFeeRate(req.PaymentType) + payAmountStr := payment.CalculatePayAmount(amount, feeRate) + payAmount, _ := strconv.ParseFloat(payAmountStr, 64) + order, err := s.createOrderInTx(ctx, req, user, plan, cfg, amount, feeRate, payAmount) + if err != nil { + return nil, err + } + resp, err := s.invokeProvider(ctx, order, req, cfg, payAmountStr, payAmount, plan) + if err != nil { + _, _ = s.entClient.PaymentOrder.UpdateOneID(order.ID). + SetStatus(OrderStatusFailed). + Save(ctx) + return nil, err + } + return resp, nil +} + +func (s *PaymentService) validateOrderInput(ctx context.Context, req CreateOrderRequest, cfg *PaymentConfig) (*dbent.SubscriptionPlan, error) { + if req.OrderType == payment.OrderTypeBalance && cfg.BalanceDisabled { + return nil, infraerrors.Forbidden("BALANCE_PAYMENT_DISABLED", "balance recharge has been disabled") + } + if req.OrderType == payment.OrderTypeSubscription { + return s.validateSubOrder(ctx, req) + } + if math.IsNaN(req.Amount) || math.IsInf(req.Amount, 0) || req.Amount <= 0 { + return nil, infraerrors.BadRequest("INVALID_AMOUNT", "amount must be a positive number") + } + if (cfg.MinAmount > 0 && req.Amount < cfg.MinAmount) || (cfg.MaxAmount > 0 && req.Amount > cfg.MaxAmount) { + return nil, infraerrors.BadRequest("INVALID_AMOUNT", "amount out of range"). + WithMetadata(map[string]string{"min": fmt.Sprintf("%.2f", cfg.MinAmount), "max": fmt.Sprintf("%.2f", cfg.MaxAmount)}) + } + return nil, nil +} + +func (s *PaymentService) validateSubOrder(ctx context.Context, req CreateOrderRequest) (*dbent.SubscriptionPlan, error) { + if req.PlanID == 0 { + return nil, infraerrors.BadRequest("INVALID_INPUT", "subscription order requires a plan") + } + plan, err := s.configService.GetPlan(ctx, req.PlanID) + if err != nil || !plan.ForSale { + return nil, infraerrors.NotFound("PLAN_NOT_AVAILABLE", "plan not found or not for sale") + } + group, err := s.groupRepo.GetByID(ctx, plan.GroupID) + if err != nil || group.Status != payment.EntityStatusActive { + return nil, infraerrors.NotFound("GROUP_NOT_FOUND", "subscription group is no longer available") + } + if !group.IsSubscriptionType() { + return nil, infraerrors.BadRequest("GROUP_TYPE_MISMATCH", "group is not a subscription type") + } + return plan, nil +} + +func (s *PaymentService) createOrderInTx(ctx context.Context, req CreateOrderRequest, user *User, plan *dbent.SubscriptionPlan, cfg *PaymentConfig, amount, feeRate, payAmount float64) (*dbent.PaymentOrder, error) { + tx, err := s.entClient.Tx(ctx) + if err != nil { + return nil, fmt.Errorf("begin transaction: %w", err) + } + defer func() { _ = tx.Rollback() }() + if err := s.checkPendingLimit(ctx, tx, req.UserID, cfg.MaxPendingOrders); err != nil { + return nil, err + } + if err := s.checkDailyLimit(ctx, tx, req.UserID, amount, cfg.DailyLimit); err != nil { + return nil, err + } + tm := cfg.OrderTimeoutMin + if tm <= 0 { + tm = defaultOrderTimeoutMin + } + exp := time.Now().Add(time.Duration(tm) * time.Minute) + b := tx.PaymentOrder.Create(). + SetUserID(req.UserID). + SetUserEmail(user.Email). + SetUserName(user.Username). + SetNillableUserNotes(psNilIfEmpty(user.Notes)). + SetAmount(amount). + SetPayAmount(payAmount). + SetFeeRate(feeRate). + SetRechargeCode(""). + SetOutTradeNo(generateOutTradeNo()). + SetPaymentType(req.PaymentType). + SetPaymentTradeNo(""). + SetOrderType(req.OrderType). + SetStatus(OrderStatusPending). + SetExpiresAt(exp). + SetClientIP(req.ClientIP). + SetSrcHost(req.SrcHost) + if req.SrcURL != "" { + b.SetSrcURL(req.SrcURL) + } + if plan != nil { + b.SetPlanID(plan.ID).SetSubscriptionGroupID(plan.GroupID).SetSubscriptionDays(psComputeValidityDays(plan.ValidityDays, plan.ValidityUnit)) + } + order, err := b.Save(ctx) + if err != nil { + return nil, fmt.Errorf("create order: %w", err) + } + code := fmt.Sprintf("PAY-%d-%d", order.ID, time.Now().UnixNano()%100000) + order, err = tx.PaymentOrder.UpdateOneID(order.ID).SetRechargeCode(code).Save(ctx) + if err != nil { + return nil, fmt.Errorf("set recharge code: %w", err) + } + if err := tx.Commit(); err != nil { + return nil, fmt.Errorf("commit order transaction: %w", err) + } + return order, nil +} + +func (s *PaymentService) checkPendingLimit(ctx context.Context, tx *dbent.Tx, userID int64, max int) error { + if max <= 0 { + max = defaultMaxPendingOrders + } + c, err := tx.PaymentOrder.Query().Where(paymentorder.UserIDEQ(userID), paymentorder.StatusEQ(OrderStatusPending)).Count(ctx) + if err != nil { + return fmt.Errorf("count pending orders: %w", err) + } + if c >= max { + return infraerrors.TooManyRequests("TOO_MANY_PENDING", fmt.Sprintf("too many pending orders (max %d)", max)). + WithMetadata(map[string]string{"max": strconv.Itoa(max)}) + } + return nil +} + +func (s *PaymentService) checkCancelRateLimit(ctx context.Context, userID int64, cfg *PaymentConfig) error { + if !cfg.CancelRateLimitEnabled || cfg.CancelRateLimitMax <= 0 { + return nil + } + windowStart := cancelRateLimitWindowStart(cfg) + operator := fmt.Sprintf("user:%d", userID) + count, err := s.entClient.PaymentAuditLog.Query(). + Where( + paymentauditlog.ActionEQ("ORDER_CANCELLED"), + paymentauditlog.OperatorEQ(operator), + paymentauditlog.CreatedAtGTE(windowStart), + ).Count(ctx) + if err != nil { + slog.Error("check cancel rate limit failed", "userID", userID, "error", err) + return nil // fail open + } + if count >= cfg.CancelRateLimitMax { + return infraerrors.TooManyRequests("CANCEL_RATE_LIMITED", "cancel rate limited"). + WithMetadata(map[string]string{ + "max": strconv.Itoa(cfg.CancelRateLimitMax), + "window": strconv.Itoa(cfg.CancelRateLimitWindow), + "unit": cfg.CancelRateLimitUnit, + }) + } + return nil +} + +func cancelRateLimitWindowStart(cfg *PaymentConfig) time.Time { + now := time.Now() + w := cfg.CancelRateLimitWindow + if w <= 0 { + w = 1 + } + unit := cfg.CancelRateLimitUnit + if unit == "" { + unit = "day" + } + if cfg.CancelRateLimitMode == "fixed" { + switch unit { + case "minute": + t := now.Truncate(time.Minute) + return t.Add(-time.Duration(w-1) * time.Minute) + case "day": + y, m, d := now.Date() + t := time.Date(y, m, d, 0, 0, 0, 0, now.Location()) + return t.AddDate(0, 0, -(w - 1)) + default: // hour + t := now.Truncate(time.Hour) + return t.Add(-time.Duration(w-1) * time.Hour) + } + } + // rolling window + switch unit { + case "minute": + return now.Add(-time.Duration(w) * time.Minute) + case "day": + return now.AddDate(0, 0, -w) + default: // hour + return now.Add(-time.Duration(w) * time.Hour) + } +} + +func (s *PaymentService) checkDailyLimit(ctx context.Context, tx *dbent.Tx, userID int64, amount, limit float64) error { + if limit <= 0 { + return nil + } + ts := psStartOfDayUTC(time.Now()) + orders, err := tx.PaymentOrder.Query().Where(paymentorder.UserIDEQ(userID), paymentorder.StatusIn(OrderStatusPaid, OrderStatusRecharging, OrderStatusCompleted), paymentorder.PaidAtGTE(ts)).All(ctx) + if err != nil { + return fmt.Errorf("query daily usage: %w", err) + } + var used float64 + for _, o := range orders { + used += o.Amount + } + if used+amount > limit { + return infraerrors.TooManyRequests("DAILY_LIMIT_EXCEEDED", fmt.Sprintf("daily recharge limit reached, remaining: %.2f", math.Max(0, limit-used))) + } + return nil +} + +func (s *PaymentService) invokeProvider(ctx context.Context, order *dbent.PaymentOrder, req CreateOrderRequest, cfg *PaymentConfig, payAmountStr string, payAmount float64, plan *dbent.SubscriptionPlan) (*CreateOrderResponse, error) { + s.EnsureProviders(ctx) + providerKey := s.registry.GetProviderKey(req.PaymentType) + if providerKey == "" { + return nil, infraerrors.ServiceUnavailable("PAYMENT_GATEWAY_ERROR", fmt.Sprintf("payment method (%s) is not configured", req.PaymentType)) + } + sel, err := s.loadBalancer.SelectInstance(ctx, providerKey, req.PaymentType, payment.Strategy(cfg.LoadBalanceStrategy), payAmount) + if err != nil { + return nil, fmt.Errorf("select provider instance: %w", err) + } + if sel == nil { + return nil, infraerrors.TooManyRequests("NO_AVAILABLE_INSTANCE", "no available payment instance") + } + prov, err := provider.CreateProvider(providerKey, sel.InstanceID, sel.Config) + if err != nil { + return nil, infraerrors.ServiceUnavailable("PAYMENT_GATEWAY_ERROR", "payment method is temporarily unavailable") + } + subject := s.buildPaymentSubject(plan, payAmountStr, cfg) + outTradeNo := order.OutTradeNo + pr, err := prov.CreatePayment(ctx, payment.CreatePaymentRequest{OrderID: outTradeNo, Amount: payAmountStr, PaymentType: req.PaymentType, Subject: subject, ClientIP: req.ClientIP, IsMobile: req.IsMobile, InstanceSubMethods: sel.SupportedTypes}) + if err != nil { + slog.Error("[PaymentService] CreatePayment failed", "provider", providerKey, "instance", sel.InstanceID, "error", err) + return nil, infraerrors.ServiceUnavailable("PAYMENT_GATEWAY_ERROR", fmt.Sprintf("payment gateway error: %s", err.Error())) + } + _, err = s.entClient.PaymentOrder.UpdateOneID(order.ID).SetNillablePaymentTradeNo(psNilIfEmpty(pr.TradeNo)).SetNillablePayURL(psNilIfEmpty(pr.PayURL)).SetNillableQrCode(psNilIfEmpty(pr.QRCode)).SetNillableProviderInstanceID(psNilIfEmpty(sel.InstanceID)).Save(ctx) + if err != nil { + return nil, fmt.Errorf("update order with payment details: %w", err) + } + s.writeAuditLog(ctx, order.ID, "ORDER_CREATED", fmt.Sprintf("user:%d", req.UserID), map[string]any{"amount": req.Amount, "paymentType": req.PaymentType, "orderType": req.OrderType}) + return &CreateOrderResponse{OrderID: order.ID, Amount: order.Amount, PayAmount: payAmount, FeeRate: order.FeeRate, Status: OrderStatusPending, PaymentType: req.PaymentType, PayURL: pr.PayURL, QRCode: pr.QRCode, ClientSecret: pr.ClientSecret, ExpiresAt: order.ExpiresAt, PaymentMode: sel.PaymentMode}, nil +} + +func (s *PaymentService) buildPaymentSubject(plan *dbent.SubscriptionPlan, payAmountStr string, cfg *PaymentConfig) string { + if plan != nil { + if plan.ProductName != "" { + return plan.ProductName + } + return "Sub2API Subscription " + plan.Name + } + pf := strings.TrimSpace(cfg.ProductNamePrefix) + sf := strings.TrimSpace(cfg.ProductNameSuffix) + if pf != "" || sf != "" { + return strings.TrimSpace(pf + " " + payAmountStr + " " + sf) + } + return "Sub2API " + payAmountStr + " CNY" +} + +// --- Order Queries --- + +func (s *PaymentService) GetOrder(ctx context.Context, orderID, userID int64) (*dbent.PaymentOrder, error) { + o, err := s.entClient.PaymentOrder.Get(ctx, orderID) + if err != nil { + return nil, infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.UserID != userID { + return nil, infraerrors.Forbidden("FORBIDDEN", "no permission for this order") + } + return o, nil +} + +func (s *PaymentService) GetOrderByID(ctx context.Context, orderID int64) (*dbent.PaymentOrder, error) { + o, err := s.entClient.PaymentOrder.Get(ctx, orderID) + if err != nil { + return nil, infraerrors.NotFound("NOT_FOUND", "order not found") + } + return o, nil +} + +func (s *PaymentService) GetUserOrders(ctx context.Context, userID int64, p OrderListParams) ([]*dbent.PaymentOrder, int, error) { + q := s.entClient.PaymentOrder.Query().Where(paymentorder.UserIDEQ(userID)) + if p.Status != "" { + q = q.Where(paymentorder.StatusEQ(p.Status)) + } + if p.OrderType != "" { + q = q.Where(paymentorder.OrderTypeEQ(p.OrderType)) + } + if p.PaymentType != "" { + q = q.Where(paymentorder.PaymentTypeEQ(p.PaymentType)) + } + total, err := q.Clone().Count(ctx) + if err != nil { + return nil, 0, fmt.Errorf("count user orders: %w", err) + } + ps, pg := applyPagination(p.PageSize, p.Page) + orders, err := q.Order(dbent.Desc(paymentorder.FieldCreatedAt)).Limit(ps).Offset((pg - 1) * ps).All(ctx) + if err != nil { + return nil, 0, fmt.Errorf("query user orders: %w", err) + } + return orders, total, nil +} + +// AdminListOrders returns a paginated list of orders. If userID > 0, filters by user. +func (s *PaymentService) AdminListOrders(ctx context.Context, userID int64, p OrderListParams) ([]*dbent.PaymentOrder, int, error) { + q := s.entClient.PaymentOrder.Query() + if userID > 0 { + q = q.Where(paymentorder.UserIDEQ(userID)) + } + if p.Status != "" { + q = q.Where(paymentorder.StatusEQ(p.Status)) + } + if p.OrderType != "" { + q = q.Where(paymentorder.OrderTypeEQ(p.OrderType)) + } + if p.PaymentType != "" { + q = q.Where(paymentorder.PaymentTypeEQ(p.PaymentType)) + } + if p.Keyword != "" { + q = q.Where(paymentorder.Or( + paymentorder.OutTradeNoContainsFold(p.Keyword), + paymentorder.UserEmailContainsFold(p.Keyword), + paymentorder.UserNameContainsFold(p.Keyword), + )) + } + total, err := q.Clone().Count(ctx) + if err != nil { + return nil, 0, fmt.Errorf("count admin orders: %w", err) + } + ps, pg := applyPagination(p.PageSize, p.Page) + orders, err := q.Order(dbent.Desc(paymentorder.FieldCreatedAt)).Limit(ps).Offset((pg - 1) * ps).All(ctx) + if err != nil { + return nil, 0, fmt.Errorf("query admin orders: %w", err) + } + return orders, total, nil +} + +// --- Cancel & Expire --- + +func (s *PaymentService) CancelOrder(ctx context.Context, orderID, userID int64) (string, error) { + o, err := s.entClient.PaymentOrder.Get(ctx, orderID) + if err != nil { + return "", infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.UserID != userID { + return "", infraerrors.Forbidden("FORBIDDEN", "no permission for this order") + } + if o.Status != OrderStatusPending { + return "", infraerrors.BadRequest("INVALID_STATUS", "order cannot be cancelled in current status") + } + return s.cancelCore(ctx, o, OrderStatusCancelled, fmt.Sprintf("user:%d", userID), "user cancelled order") +} + +func (s *PaymentService) AdminCancelOrder(ctx context.Context, orderID int64) (string, error) { + o, err := s.entClient.PaymentOrder.Get(ctx, orderID) + if err != nil { + return "", infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.Status != OrderStatusPending { + return "", infraerrors.BadRequest("INVALID_STATUS", "order cannot be cancelled in current status") + } + return s.cancelCore(ctx, o, OrderStatusCancelled, "admin", "admin cancelled order") +} + +func (s *PaymentService) cancelCore(ctx context.Context, o *dbent.PaymentOrder, fs, op, ad string) (string, error) { + if o.PaymentTradeNo != "" || o.PaymentType != "" { + if s.checkPaid(ctx, o) == "already_paid" { + return "already_paid", nil + } + } + c, err := s.entClient.PaymentOrder.Update().Where(paymentorder.IDEQ(o.ID), paymentorder.StatusEQ(OrderStatusPending)).SetStatus(fs).Save(ctx) + if err != nil { + return "", fmt.Errorf("update order status: %w", err) + } + if c > 0 { + auditAction := "ORDER_CANCELLED" + if fs == OrderStatusExpired { + auditAction = "ORDER_EXPIRED" + } + s.writeAuditLog(ctx, o.ID, auditAction, op, map[string]any{"detail": ad}) + } + return "cancelled", nil +} + +func (s *PaymentService) checkPaid(ctx context.Context, o *dbent.PaymentOrder) string { + prov, err := s.getOrderProvider(ctx, o) + if err != nil { + return "" + } + // Use OutTradeNo as fallback when PaymentTradeNo is empty + // (e.g. EasyPay popup mode where trade_no arrives only via notify callback) + tradeNo := o.PaymentTradeNo + if tradeNo == "" { + tradeNo = o.OutTradeNo + } + resp, err := prov.QueryOrder(ctx, tradeNo) + if err != nil { + slog.Warn("query upstream failed", "orderID", o.ID, "error", err) + return "" + } + if resp.Status == payment.ProviderStatusPaid { + if err := s.HandlePaymentNotification(ctx, &payment.PaymentNotification{TradeNo: o.PaymentTradeNo, OrderID: o.OutTradeNo, Amount: resp.Amount, Status: payment.ProviderStatusSuccess}, prov.ProviderKey()); err != nil { + slog.Error("fulfillment failed during checkPaid", "orderID", o.ID, "error", err) + // Still return already_paid — order was paid, fulfillment can be retried + } + return "already_paid" + } + if cp, ok := prov.(payment.CancelableProvider); ok { + _ = cp.CancelPayment(ctx, tradeNo) + } + return "" +} + +// VerifyOrderByOutTradeNo actively queries the upstream provider to check +// if a payment was made, and processes it if so. This handles the case where +// the provider's notify callback was missed (e.g. EasyPay popup mode). +func (s *PaymentService) VerifyOrderByOutTradeNo(ctx context.Context, outTradeNo string, userID int64) (*dbent.PaymentOrder, error) { + o, err := s.entClient.PaymentOrder.Query(). + Where(paymentorder.OutTradeNo(outTradeNo)). + Only(ctx) + if err != nil { + return nil, infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.UserID != userID { + return nil, infraerrors.Forbidden("FORBIDDEN", "no permission for this order") + } + // Only verify orders that are still pending or recently expired + if o.Status == OrderStatusPending || o.Status == OrderStatusExpired { + result := s.checkPaid(ctx, o) + if result == "already_paid" { + // Reload order to get updated status + o, err = s.entClient.PaymentOrder.Get(ctx, o.ID) + if err != nil { + return nil, fmt.Errorf("reload order: %w", err) + } + } + } + return o, nil +} + +// VerifyOrderPublic verifies payment status without user authentication. +// Used by the payment result page when the user's session has expired. +func (s *PaymentService) VerifyOrderPublic(ctx context.Context, outTradeNo string) (*dbent.PaymentOrder, error) { + o, err := s.entClient.PaymentOrder.Query(). + Where(paymentorder.OutTradeNo(outTradeNo)). + Only(ctx) + if err != nil { + return nil, infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.Status == OrderStatusPending || o.Status == OrderStatusExpired { + result := s.checkPaid(ctx, o) + if result == "already_paid" { + o, err = s.entClient.PaymentOrder.Get(ctx, o.ID) + if err != nil { + return nil, fmt.Errorf("reload order: %w", err) + } + } + } + return o, nil +} + +func (s *PaymentService) ExpireTimedOutOrders(ctx context.Context) (int, error) { + now := time.Now() + orders, err := s.entClient.PaymentOrder.Query().Where(paymentorder.StatusEQ(OrderStatusPending), paymentorder.ExpiresAtLTE(now)).All(ctx) + if err != nil { + return 0, fmt.Errorf("query expired: %w", err) + } + n := 0 + for _, o := range orders { + // Check upstream payment status before expiring — the user may have + // paid just before timeout and the webhook hasn't arrived yet. + outcome, _ := s.cancelCore(ctx, o, OrderStatusExpired, "system", "order expired") + if outcome == "already_paid" { + slog.Info("order was paid during expiry", "orderID", o.ID) + continue + } + if outcome != "" { + n++ + } + } + return n, nil +} + +// getOrderProvider creates a provider using the order's original instance config. +// Falls back to registry lookup if instance ID is missing (legacy orders). +func (s *PaymentService) getOrderProvider(ctx context.Context, o *dbent.PaymentOrder) (payment.Provider, error) { + if o.ProviderInstanceID != nil && *o.ProviderInstanceID != "" { + instID, err := strconv.ParseInt(*o.ProviderInstanceID, 10, 64) + if err == nil { + cfg, err := s.loadBalancer.GetInstanceConfig(ctx, instID) + if err == nil { + providerKey := s.registry.GetProviderKey(o.PaymentType) + if providerKey == "" { + providerKey = o.PaymentType + } + p, err := provider.CreateProvider(providerKey, *o.ProviderInstanceID, cfg) + if err == nil { + return p, nil + } + } + } + } + s.EnsureProviders(ctx) + return s.registry.GetProvider(o.PaymentType) +} diff --git a/backend/internal/service/payment_order_expiry_service.go b/backend/internal/service/payment_order_expiry_service.go new file mode 100644 index 00000000..b0cda3e5 --- /dev/null +++ b/backend/internal/service/payment_order_expiry_service.go @@ -0,0 +1,73 @@ +package service + +import ( + "context" + "log/slog" + "sync" + "time" +) + +const expiryCheckTimeout = 30 * time.Second + +// 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(), expiryCheckTimeout) + 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) + } +} diff --git a/backend/internal/service/payment_refund.go b/backend/internal/service/payment_refund.go new file mode 100644 index 00000000..fd2822cc --- /dev/null +++ b/backend/internal/service/payment_refund.go @@ -0,0 +1,248 @@ +package service + +import ( + "context" + "fmt" + "log/slog" + "math" + "strconv" + "strings" + "time" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/paymentorder" + "github.com/Wei-Shaw/sub2api/internal/payment" + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" +) + +// --- Refund Flow --- + +func (s *PaymentService) RequestRefund(ctx context.Context, oid, uid int64, reason string) error { + o, err := s.validateRefundRequest(ctx, oid, uid) + if err != nil { + return err + } + u, err := s.userRepo.GetByID(ctx, o.UserID) + if err != nil { + return fmt.Errorf("get user: %w", err) + } + if u.Balance < o.Amount { + return infraerrors.BadRequest("BALANCE_NOT_ENOUGH", "refund amount exceeds balance") + } + nr := strings.TrimSpace(reason) + now := time.Now() + by := fmt.Sprintf("%d", uid) + c, err := s.entClient.PaymentOrder.Update().Where(paymentorder.IDEQ(oid), paymentorder.UserIDEQ(uid), paymentorder.StatusEQ(OrderStatusCompleted), paymentorder.OrderTypeEQ(payment.OrderTypeBalance)).SetStatus(OrderStatusRefundRequested).SetRefundRequestedAt(now).SetRefundRequestReason(nr).SetRefundRequestedBy(by).SetRefundAmount(o.Amount).Save(ctx) + if err != nil { + return fmt.Errorf("update: %w", err) + } + if c == 0 { + return infraerrors.Conflict("CONFLICT", "order status changed") + } + s.writeAuditLog(ctx, oid, "REFUND_REQUESTED", fmt.Sprintf("user:%d", uid), map[string]any{"amount": o.Amount, "reason": nr}) + return nil +} + +func (s *PaymentService) validateRefundRequest(ctx context.Context, oid, uid int64) (*dbent.PaymentOrder, error) { + o, err := s.entClient.PaymentOrder.Get(ctx, oid) + if err != nil { + return nil, infraerrors.NotFound("NOT_FOUND", "order not found") + } + if o.UserID != uid { + return nil, infraerrors.Forbidden("FORBIDDEN", "no permission") + } + if o.OrderType != payment.OrderTypeBalance { + return nil, infraerrors.BadRequest("INVALID_ORDER_TYPE", "only balance orders can request refund") + } + if o.Status != OrderStatusCompleted { + return nil, infraerrors.BadRequest("INVALID_STATUS", "only completed orders can request refund") + } + return o, nil +} + +func (s *PaymentService) PrepareRefund(ctx context.Context, oid int64, amt float64, reason string, force, deduct bool) (*RefundPlan, *RefundResult, error) { + o, err := s.entClient.PaymentOrder.Get(ctx, oid) + if err != nil { + return nil, nil, infraerrors.NotFound("NOT_FOUND", "order not found") + } + ok := []string{OrderStatusCompleted, OrderStatusRefundRequested, OrderStatusRefundFailed} + if !psSliceContains(ok, o.Status) { + return nil, nil, infraerrors.BadRequest("INVALID_STATUS", "order status does not allow refund") + } + if math.IsNaN(amt) || math.IsInf(amt, 0) { + return nil, nil, infraerrors.BadRequest("INVALID_AMOUNT", "invalid refund amount") + } + if amt <= 0 { + amt = o.Amount + } + if amt-o.Amount > amountToleranceCNY { + return nil, nil, infraerrors.BadRequest("REFUND_AMOUNT_EXCEEDED", "refund amount exceeds recharge") + } + // Full refund: use actual pay_amount for gateway (includes fees) + ga := amt + if math.Abs(amt-o.Amount) <= amountToleranceCNY { + ga = o.PayAmount + } + rr := strings.TrimSpace(reason) + if rr == "" && o.RefundRequestReason != nil { + rr = *o.RefundRequestReason + } + if rr == "" { + rr = fmt.Sprintf("refund order:%d", o.ID) + } + p := &RefundPlan{OrderID: oid, Order: o, RefundAmount: amt, GatewayAmount: ga, Reason: rr, Force: force, DeductBalance: deduct, DeductionType: payment.DeductionTypeNone} + if deduct { + if er := s.prepDeduct(ctx, o, p, force); er != nil { + return nil, er, nil + } + } + return p, nil, nil +} + +func (s *PaymentService) prepDeduct(ctx context.Context, o *dbent.PaymentOrder, p *RefundPlan, force bool) *RefundResult { + if o.OrderType == payment.OrderTypeSubscription { + p.DeductionType = payment.DeductionTypeSubscription + if o.SubscriptionGroupID != nil && o.SubscriptionDays != nil { + p.SubDaysToDeduct = *o.SubscriptionDays + sub, err := s.subscriptionSvc.GetActiveSubscription(ctx, o.UserID, *o.SubscriptionGroupID) + if err == nil && sub != nil { + p.SubscriptionID = sub.ID + } else if !force { + return &RefundResult{Success: false, Warning: "cannot find active subscription for deduction, use force", RequireForce: true} + } + } + return nil + } + u, err := s.userRepo.GetByID(ctx, o.UserID) + if err != nil { + if !force { + return &RefundResult{Success: false, Warning: "cannot fetch user balance, use force", RequireForce: true} + } + return nil + } + p.DeductionType = payment.DeductionTypeBalance + p.BalanceToDeduct = math.Min(p.RefundAmount, u.Balance) + return nil +} + +func (s *PaymentService) ExecuteRefund(ctx context.Context, p *RefundPlan) (*RefundResult, error) { + c, err := s.entClient.PaymentOrder.Update().Where(paymentorder.IDEQ(p.OrderID), paymentorder.StatusIn(OrderStatusCompleted, OrderStatusRefundRequested, OrderStatusRefundFailed)).SetStatus(OrderStatusRefunding).Save(ctx) + if err != nil { + return nil, fmt.Errorf("lock: %w", err) + } + if c == 0 { + return nil, infraerrors.Conflict("CONFLICT", "order status changed") + } + if p.DeductionType == payment.DeductionTypeBalance && p.BalanceToDeduct > 0 { + // Skip balance deduction on retry if previous attempt already deducted + // but failed to roll back (REFUND_ROLLBACK_FAILED in audit log). + if !s.hasAuditLog(ctx, p.OrderID, "REFUND_ROLLBACK_FAILED") { + if err := s.userRepo.DeductBalance(ctx, p.Order.UserID, p.BalanceToDeduct); err != nil { + s.restoreStatus(ctx, p) + return nil, fmt.Errorf("deduction: %w", err) + } + } else { + slog.Warn("skipping balance deduction on retry (previous rollback failed)", "orderID", p.OrderID) + p.BalanceToDeduct = 0 + } + } + if p.DeductionType == payment.DeductionTypeSubscription && p.SubDaysToDeduct > 0 && p.SubscriptionID > 0 { + if !s.hasAuditLog(ctx, p.OrderID, "REFUND_ROLLBACK_FAILED") { + _, err := s.subscriptionSvc.ExtendSubscription(ctx, p.SubscriptionID, -p.SubDaysToDeduct) + if err != nil { + // If deducting would expire the subscription, revoke it entirely + slog.Info("subscription deduction would expire, revoking", "orderID", p.OrderID, "subID", p.SubscriptionID, "days", p.SubDaysToDeduct) + if revokeErr := s.subscriptionSvc.RevokeSubscription(ctx, p.SubscriptionID); revokeErr != nil { + s.restoreStatus(ctx, p) + return nil, fmt.Errorf("revoke subscription: %w", revokeErr) + } + } + } else { + slog.Warn("skipping subscription deduction on retry (previous rollback failed)", "orderID", p.OrderID) + p.SubDaysToDeduct = 0 + } + } + if err := s.gwRefund(ctx, p); err != nil { + return s.handleGwFail(ctx, p, err) + } + return s.markRefundOk(ctx, p) +} + +func (s *PaymentService) gwRefund(ctx context.Context, p *RefundPlan) error { + if p.Order.PaymentTradeNo == "" { + s.writeAuditLog(ctx, p.Order.ID, "REFUND_NO_TRADE_NO", "admin", map[string]any{"detail": "skipped"}) + return nil + } + + // Use the exact provider instance that created this order, not a random one + // from the registry. Each instance has its own merchant credentials. + prov, err := s.getRefundProvider(ctx, p.Order) + if err != nil { + return fmt.Errorf("get refund provider: %w", err) + } + _, err = prov.Refund(ctx, payment.RefundRequest{ + TradeNo: p.Order.PaymentTradeNo, + OrderID: p.Order.OutTradeNo, + Amount: strconv.FormatFloat(p.GatewayAmount, 'f', 2, 64), + Reason: p.Reason, + }) + return err +} + +// getRefundProvider creates a provider using the order's original instance config. +// Delegates to getOrderProvider which handles instance lookup and fallback. +func (s *PaymentService) getRefundProvider(ctx context.Context, o *dbent.PaymentOrder) (payment.Provider, error) { + return s.getOrderProvider(ctx, o) +} + +func (s *PaymentService) handleGwFail(ctx context.Context, p *RefundPlan, gErr error) (*RefundResult, error) { + if s.RollbackRefund(ctx, p, gErr) { + s.restoreStatus(ctx, p) + s.writeAuditLog(ctx, p.OrderID, "REFUND_GATEWAY_FAILED", "admin", map[string]any{"detail": psErrMsg(gErr)}) + return &RefundResult{Success: false, Warning: "gateway failed: " + psErrMsg(gErr) + ", rolled back"}, nil + } + now := time.Now() + _, _ = s.entClient.PaymentOrder.UpdateOneID(p.OrderID).SetStatus(OrderStatusRefundFailed).SetFailedAt(now).SetFailedReason(psErrMsg(gErr)).Save(ctx) + s.writeAuditLog(ctx, p.OrderID, "REFUND_FAILED", "admin", map[string]any{"detail": psErrMsg(gErr)}) + return nil, infraerrors.InternalServer("REFUND_FAILED", psErrMsg(gErr)) +} + +func (s *PaymentService) markRefundOk(ctx context.Context, p *RefundPlan) (*RefundResult, error) { + fs := OrderStatusRefunded + if p.RefundAmount < p.Order.Amount { + fs = OrderStatusPartiallyRefunded + } + now := time.Now() + _, err := s.entClient.PaymentOrder.UpdateOneID(p.OrderID).SetStatus(fs).SetRefundAmount(p.RefundAmount).SetRefundReason(p.Reason).SetRefundAt(now).SetForceRefund(p.Force).Save(ctx) + if err != nil { + return nil, fmt.Errorf("mark refund: %w", err) + } + s.writeAuditLog(ctx, p.OrderID, "REFUND_SUCCESS", "admin", map[string]any{"refundAmount": p.RefundAmount, "reason": p.Reason, "balanceDeducted": p.BalanceToDeduct, "force": p.Force}) + return &RefundResult{Success: true, BalanceDeducted: p.BalanceToDeduct, SubDaysDeducted: p.SubDaysToDeduct}, nil +} + +func (s *PaymentService) RollbackRefund(ctx context.Context, p *RefundPlan, gErr error) bool { + if p.DeductionType == payment.DeductionTypeBalance && p.BalanceToDeduct > 0 { + if err := s.userRepo.UpdateBalance(ctx, p.Order.UserID, p.BalanceToDeduct); err != nil { + slog.Error("[CRITICAL] rollback failed", "orderID", p.OrderID, "amount", p.BalanceToDeduct, "error", err) + s.writeAuditLog(ctx, p.OrderID, "REFUND_ROLLBACK_FAILED", "admin", map[string]any{"gatewayError": psErrMsg(gErr), "rollbackError": psErrMsg(err), "balanceDeducted": p.BalanceToDeduct}) + return false + } + } + if p.DeductionType == payment.DeductionTypeSubscription && p.SubDaysToDeduct > 0 && p.SubscriptionID > 0 { + if _, err := s.subscriptionSvc.ExtendSubscription(ctx, p.SubscriptionID, p.SubDaysToDeduct); err != nil { + slog.Error("[CRITICAL] subscription rollback failed", "orderID", p.OrderID, "subID", p.SubscriptionID, "days", p.SubDaysToDeduct, "error", err) + s.writeAuditLog(ctx, p.OrderID, "REFUND_ROLLBACK_FAILED", "admin", map[string]any{"gatewayError": psErrMsg(gErr), "rollbackError": psErrMsg(err), "subDaysDeducted": p.SubDaysToDeduct}) + return false + } + } + return true +} + +func (s *PaymentService) restoreStatus(ctx context.Context, p *RefundPlan) { + rs := OrderStatusCompleted + if p.Order.Status == OrderStatusRefundRequested { + rs = OrderStatusRefundRequested + } + _, _ = s.entClient.PaymentOrder.UpdateOneID(p.OrderID).SetStatus(rs).Save(ctx) +} diff --git a/backend/internal/service/payment_service.go b/backend/internal/service/payment_service.go new file mode 100644 index 00000000..25ec15f7 --- /dev/null +++ b/backend/internal/service/payment_service.go @@ -0,0 +1,305 @@ +package service + +import ( + "context" + "fmt" + "log/slog" + "math/rand/v2" + "sync" + "time" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/paymentorder" + "github.com/Wei-Shaw/sub2api/ent/paymentproviderinstance" + "github.com/Wei-Shaw/sub2api/internal/payment" + "github.com/Wei-Shaw/sub2api/internal/payment/provider" +) + +// --- Order Status Constants --- + +const ( + OrderStatusPending = payment.OrderStatusPending + OrderStatusPaid = payment.OrderStatusPaid + OrderStatusRecharging = payment.OrderStatusRecharging + OrderStatusCompleted = payment.OrderStatusCompleted + OrderStatusExpired = payment.OrderStatusExpired + OrderStatusCancelled = payment.OrderStatusCancelled + OrderStatusFailed = payment.OrderStatusFailed + OrderStatusRefundRequested = payment.OrderStatusRefundRequested + OrderStatusRefunding = payment.OrderStatusRefunding + OrderStatusPartiallyRefunded = payment.OrderStatusPartiallyRefunded + OrderStatusRefunded = payment.OrderStatusRefunded + OrderStatusRefundFailed = payment.OrderStatusRefundFailed +) + +const ( + // defaultMaxPendingOrders and defaultOrderTimeoutMin are defined in + // payment_config_service.go alongside other payment configuration defaults. + paymentGraceMinutes = 5 + + defaultPageSize = 20 + maxPageSize = 100 + topUsersLimit = 10 + amountToleranceCNY = 0.01 + + orderIDPrefix = "sub2_" +) + +// --- Types --- + +// generateOutTradeNo creates a unique external order ID for payment providers. +// Format: sub2_20250409aB3kX9mQ (prefix + date + 8-char random) +func generateOutTradeNo() string { + date := time.Now().Format("20060102") + rnd := generateRandomString(8) + return orderIDPrefix + date + rnd +} + +func generateRandomString(n int) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + b := make([]byte, n) + for i := range b { + b[i] = charset[rand.IntN(len(charset))] + } + return string(b) +} + +type CreateOrderRequest struct { + UserID int64 + Amount float64 + PaymentType string + ClientIP string + IsMobile bool + SrcHost string + SrcURL string + OrderType string + PlanID int64 +} + +type CreateOrderResponse struct { + OrderID int64 `json:"order_id"` + Amount float64 `json:"amount"` + PayAmount float64 `json:"pay_amount"` + FeeRate float64 `json:"fee_rate"` + Status string `json:"status"` + PaymentType string `json:"payment_type"` + PayURL string `json:"pay_url,omitempty"` + QRCode string `json:"qr_code,omitempty"` + ClientSecret string `json:"client_secret,omitempty"` + ExpiresAt time.Time `json:"expires_at"` + PaymentMode string `json:"payment_mode,omitempty"` +} + +type OrderListParams struct { + Page int + PageSize int + Status string + OrderType string + PaymentType string + Keyword string +} + +type RefundPlan struct { + OrderID int64 + Order *dbent.PaymentOrder + RefundAmount float64 + GatewayAmount float64 + Reason string + Force bool + DeductBalance bool + DeductionType string + BalanceToDeduct float64 + SubDaysToDeduct int + SubscriptionID int64 +} + +type RefundResult struct { + Success bool `json:"success"` + Warning string `json:"warning,omitempty"` + RequireForce bool `json:"require_force,omitempty"` + BalanceDeducted float64 `json:"balance_deducted,omitempty"` + SubDaysDeducted int `json:"subscription_days_deducted,omitempty"` +} + +type DashboardStats struct { + TodayAmount float64 `json:"today_amount"` + TotalAmount float64 `json:"total_amount"` + TodayCount int `json:"today_count"` + TotalCount int `json:"total_count"` + AvgAmount float64 `json:"avg_amount"` + PendingOrders int `json:"pending_orders"` + + DailySeries []DailyStats `json:"daily_series"` + PaymentMethods []PaymentMethodStat `json:"payment_methods"` + TopUsers []TopUserStat `json:"top_users"` +} + +type DailyStats struct { + Date string `json:"date"` + Amount float64 `json:"amount"` + Count int `json:"count"` +} + +type PaymentMethodStat struct { + Type string `json:"type"` + Amount float64 `json:"amount"` + Count int `json:"count"` +} + +type TopUserStat struct { + UserID int64 `json:"user_id"` + Email string `json:"email"` + Amount float64 `json:"amount"` +} + +// --- Service --- + +type PaymentService struct { + providerMu sync.Mutex + providersLoaded bool + entClient *dbent.Client + registry *payment.Registry + loadBalancer payment.LoadBalancer + redeemService *RedeemService + subscriptionSvc *SubscriptionService + configService *PaymentConfigService + userRepo UserRepository + groupRepo GroupRepository +} + +func NewPaymentService(entClient *dbent.Client, registry *payment.Registry, loadBalancer payment.LoadBalancer, redeemService *RedeemService, subscriptionSvc *SubscriptionService, configService *PaymentConfigService, userRepo UserRepository, groupRepo GroupRepository) *PaymentService { + return &PaymentService{entClient: entClient, registry: registry, loadBalancer: loadBalancer, redeemService: redeemService, subscriptionSvc: subscriptionSvc, configService: configService, userRepo: userRepo, groupRepo: groupRepo} +} + +// --- Provider Registry --- + +// EnsureProviders lazily initializes the provider registry on first call. +func (s *PaymentService) EnsureProviders(ctx context.Context) { + s.providerMu.Lock() + defer s.providerMu.Unlock() + if !s.providersLoaded { + s.loadProviders(ctx) + s.providersLoaded = true + } +} + +// RefreshProviders clears and re-registers all providers from the database. +func (s *PaymentService) RefreshProviders(ctx context.Context) { + s.providerMu.Lock() + defer s.providerMu.Unlock() + s.registry.Clear() + s.loadProviders(ctx) + s.providersLoaded = true +} + +func (s *PaymentService) loadProviders(ctx context.Context) { + instances, err := s.entClient.PaymentProviderInstance.Query(). + Where(paymentproviderinstance.EnabledEQ(true)). + All(ctx) + if err != nil { + slog.Error("[PaymentService] failed to query provider instances", "error", err) + return + } + for _, inst := range instances { + cfg, err := s.loadBalancer.GetInstanceConfig(ctx, int64(inst.ID)) + if err != nil { + slog.Warn("[PaymentService] failed to decrypt config for instance", "instanceID", inst.ID, "error", err) + continue + } + if inst.PaymentMode != "" { + cfg["paymentMode"] = inst.PaymentMode + } + instID := fmt.Sprintf("%d", inst.ID) + p, err := provider.CreateProvider(inst.ProviderKey, instID, cfg) + if err != nil { + slog.Warn("[PaymentService] failed to create provider for instance", "instanceID", inst.ID, "key", inst.ProviderKey, "error", err) + continue + } + s.registry.Register(p) + } +} + +// GetWebhookProvider returns the provider instance that should verify a webhook. +// It extracts out_trade_no from the raw body, looks up the order to find the +// original provider instance, and creates a provider with that instance's credentials. +// Falls back to the registry provider when the order cannot be found. +func (s *PaymentService) GetWebhookProvider(ctx context.Context, providerKey, outTradeNo string) (payment.Provider, error) { + if outTradeNo != "" { + order, err := s.entClient.PaymentOrder.Query().Where(paymentorder.OutTradeNo(outTradeNo)).Only(ctx) + if err == nil { + p, pErr := s.getOrderProvider(ctx, order) + if pErr == nil { + return p, nil + } + slog.Warn("[Webhook] order provider creation failed, falling back to registry", "outTradeNo", outTradeNo, "error", pErr) + } + } + s.EnsureProviders(ctx) + return s.registry.GetProviderByKey(providerKey) +} + +// --- Helpers --- + +func psIsRefundStatus(s string) bool { + switch s { + case OrderStatusRefundRequested, OrderStatusRefunding, OrderStatusPartiallyRefunded, OrderStatusRefunded, OrderStatusRefundFailed: + return true + } + return false +} + +func psErrMsg(err error) string { + if err == nil { + return "" + } + return err.Error() +} + +func psNilIfEmpty(s string) *string { + if s == "" { + return nil + } + return &s +} + +func psSliceContains(sl []string, s string) bool { + for _, v := range sl { + if v == s { + return true + } + } + return false +} + +func psComputeValidityDays(days int, unit string) int { + switch unit { + case "week": + return days * 7 + case "month": + return days * 30 + default: + return days + } +} + +func (s *PaymentService) getFeeRate(_ string) float64 { return 0 } + +func psStartOfDayUTC(t time.Time) time.Time { + y, m, d := t.UTC().Date() + return time.Date(y, m, d, 0, 0, 0, 0, time.UTC) +} + +func applyPagination(pageSize, page int) (size, pg int) { + size = pageSize + if size <= 0 { + size = defaultPageSize + } + if size > maxPageSize { + size = maxPageSize + } + pg = page + if pg < 1 { + pg = 1 + } + return size, pg +} diff --git a/backend/internal/service/payment_stats.go b/backend/internal/service/payment_stats.go new file mode 100644 index 00000000..d206b271 --- /dev/null +++ b/backend/internal/service/payment_stats.go @@ -0,0 +1,163 @@ +package service + +import ( + "context" + "encoding/json" + "log/slog" + "math" + "sort" + "strconv" + "time" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/paymentauditlog" + "github.com/Wei-Shaw/sub2api/ent/paymentorder" +) + +// --- Dashboard & Analytics --- + +func (s *PaymentService) GetDashboardStats(ctx context.Context, days int) (*DashboardStats, error) { + if days <= 0 { + days = 30 + } + now := time.Now() + since := now.AddDate(0, 0, -days) + todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + + paidStatuses := []string{OrderStatusCompleted, OrderStatusPaid, OrderStatusRecharging} + + orders, err := s.entClient.PaymentOrder.Query(). + Where( + paymentorder.StatusIn(paidStatuses...), + paymentorder.PaidAtGTE(since), + ). + All(ctx) + if err != nil { + return nil, err + } + + st := &DashboardStats{} + computeBasicStats(st, orders, todayStart) + + st.PendingOrders, err = s.entClient.PaymentOrder.Query(). + Where(paymentorder.StatusEQ(OrderStatusPending)). + Count(ctx) + if err != nil { + return nil, err + } + + st.DailySeries = buildDailySeries(orders, since, days) + st.PaymentMethods = buildMethodDistribution(orders) + st.TopUsers = buildTopUsers(orders) + + return st, nil +} + +func computeBasicStats(st *DashboardStats, orders []*dbent.PaymentOrder, todayStart time.Time) { + var totalAmount, todayAmount float64 + var todayCount int + for _, o := range orders { + totalAmount += o.PayAmount + if o.PaidAt != nil && !o.PaidAt.Before(todayStart) { + todayAmount += o.PayAmount + todayCount++ + } + } + st.TotalAmount = math.Round(totalAmount*100) / 100 + st.TodayAmount = math.Round(todayAmount*100) / 100 + st.TotalCount = len(orders) + st.TodayCount = todayCount + if st.TotalCount > 0 { + st.AvgAmount = math.Round(totalAmount/float64(st.TotalCount)*100) / 100 + } +} + +func buildDailySeries(orders []*dbent.PaymentOrder, since time.Time, days int) []DailyStats { + dailyMap := make(map[string]*DailyStats) + for _, o := range orders { + if o.PaidAt == nil { + continue + } + date := o.PaidAt.Format("2006-01-02") + ds, ok := dailyMap[date] + if !ok { + ds = &DailyStats{Date: date} + dailyMap[date] = ds + } + ds.Amount += o.PayAmount + ds.Count++ + } + series := make([]DailyStats, 0, days) + for i := 0; i < days; i++ { + date := since.AddDate(0, 0, i+1).Format("2006-01-02") + if ds, ok := dailyMap[date]; ok { + ds.Amount = math.Round(ds.Amount*100) / 100 + series = append(series, *ds) + } else { + series = append(series, DailyStats{Date: date}) + } + } + return series +} + +func buildMethodDistribution(orders []*dbent.PaymentOrder) []PaymentMethodStat { + methodMap := make(map[string]*PaymentMethodStat) + for _, o := range orders { + ms, ok := methodMap[o.PaymentType] + if !ok { + ms = &PaymentMethodStat{Type: o.PaymentType} + methodMap[o.PaymentType] = ms + } + ms.Amount += o.PayAmount + ms.Count++ + } + methods := make([]PaymentMethodStat, 0, len(methodMap)) + for _, ms := range methodMap { + ms.Amount = math.Round(ms.Amount*100) / 100 + methods = append(methods, *ms) + } + return methods +} + +func buildTopUsers(orders []*dbent.PaymentOrder) []TopUserStat { + userMap := make(map[int64]*TopUserStat) + for _, o := range orders { + us, ok := userMap[o.UserID] + if !ok { + us = &TopUserStat{UserID: o.UserID, Email: o.UserEmail} + userMap[o.UserID] = us + } + us.Amount += o.PayAmount + } + userList := make([]*TopUserStat, 0, len(userMap)) + for _, us := range userMap { + us.Amount = math.Round(us.Amount*100) / 100 + userList = append(userList, us) + } + sort.Slice(userList, func(i, j int) bool { + return userList[i].Amount > userList[j].Amount + }) + limit := topUsersLimit + if len(userList) < limit { + limit = len(userList) + } + result := make([]TopUserStat, 0, limit) + for i := 0; i < limit; i++ { + result = append(result, *userList[i]) + } + return result +} + +// --- Audit Logs --- + +func (s *PaymentService) writeAuditLog(ctx context.Context, oid int64, action, op string, detail map[string]any) { + dj, _ := json.Marshal(detail) + _, err := s.entClient.PaymentAuditLog.Create().SetOrderID(strconv.FormatInt(oid, 10)).SetAction(action).SetDetail(string(dj)).SetOperator(op).Save(ctx) + if err != nil { + slog.Error("audit log failed", "orderID", oid, "action", action, "error", err) + } +} + +func (s *PaymentService) GetOrderAuditLogs(ctx context.Context, oid int64) ([]*dbent.PaymentAuditLog, error) { + return s.entClient.PaymentAuditLog.Query().Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(oid, 10))).Order(paymentauditlog.ByCreatedAt()).All(ctx) +} diff --git a/backend/internal/service/setting_service.go b/backend/internal/service/setting_service.go index 9a179d67..4b7bd988 100644 --- a/backend/internal/service/setting_service.go +++ b/backend/internal/service/setting_service.go @@ -167,6 +167,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings SettingKeyBackendModeEnabled, SettingKeyOIDCConnectEnabled, SettingKeyOIDCConnectProviderName, + SettingPaymentEnabled, } settings, err := s.settingRepo.GetMultiple(ctx, keys) @@ -227,6 +228,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings BackendModeEnabled: settings[SettingKeyBackendModeEnabled] == "true", OIDCOAuthEnabled: oidcEnabled, OIDCOAuthProviderName: oidcProviderName, + PaymentEnabled: settings[SettingPaymentEnabled] == "true", }, nil } @@ -276,6 +278,7 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any BackendModeEnabled bool `json:"backend_mode_enabled"` OIDCOAuthEnabled bool `json:"oidc_oauth_enabled"` OIDCOAuthProviderName string `json:"oidc_oauth_provider_name"` + PaymentEnabled bool `json:"payment_enabled"` Version string `json:"version,omitempty"` }{ RegistrationEnabled: settings.RegistrationEnabled, @@ -303,6 +306,7 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any BackendModeEnabled: settings.BackendModeEnabled, OIDCOAuthEnabled: settings.OIDCOAuthEnabled, OIDCOAuthProviderName: settings.OIDCOAuthProviderName, + PaymentEnabled: settings.PaymentEnabled, Version: s.version, }, nil } diff --git a/backend/internal/service/settings_view.go b/backend/internal/service/settings_view.go index 80932e9d..68076013 100644 --- a/backend/internal/service/settings_view.go +++ b/backend/internal/service/settings_view.go @@ -139,6 +139,7 @@ type PublicSettings struct { BackendModeEnabled bool OIDCOAuthEnabled bool OIDCOAuthProviderName string + PaymentEnabled bool Version string } diff --git a/backend/internal/service/wire.go b/backend/internal/service/wire.go index d66d8cff..a8ece8a3 100644 --- a/backend/internal/service/wire.go +++ b/backend/internal/service/wire.go @@ -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 +} diff --git a/backend/migrations/090_payment_orders.sql b/backend/migrations/090_payment_orders.sql new file mode 100644 index 00000000..036e4ded --- /dev/null +++ b/backend/migrations/090_payment_orders.sql @@ -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); diff --git a/backend/migrations/091_payment_audit_logs.sql b/backend/migrations/091_payment_audit_logs.sql new file mode 100644 index 00000000..d05b15ef --- /dev/null +++ b/backend/migrations/091_payment_audit_logs.sql @@ -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); diff --git a/backend/migrations/092_removed_payment_channels.sql b/backend/migrations/092_removed_payment_channels.sql new file mode 100644 index 00000000..cb202347 --- /dev/null +++ b/backend/migrations/092_removed_payment_channels.sql @@ -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; diff --git a/backend/migrations/093_subscription_plans.sql b/backend/migrations/093_subscription_plans.sql new file mode 100644 index 00000000..541d8f0c --- /dev/null +++ b/backend/migrations/093_subscription_plans.sql @@ -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); diff --git a/backend/migrations/094_payment_provider_instances.sql b/backend/migrations/094_payment_provider_instances.sql new file mode 100644 index 00000000..bedd75df --- /dev/null +++ b/backend/migrations/094_payment_provider_instances.sql @@ -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); diff --git a/backend/migrations/096_migrate_purchase_subscription_to_custom_menu.sql b/backend/migrations/096_migrate_purchase_subscription_to_custom_menu.sql new file mode 100644 index 00000000..1864459e --- /dev/null +++ b/backend/migrations/096_migrate_purchase_subscription_to_custom_menu.sql @@ -0,0 +1,70 @@ +-- 096_migrate_purchase_subscription_to_custom_menu.sql +-- +-- Migrates the legacy purchase_subscription_url setting into custom_menu_items. +-- After migration, purchase_subscription_enabled is set to "false" and +-- purchase_subscription_url is cleared. +-- +-- Idempotent: skips if custom_menu_items already contains +-- "migrated_purchase_subscription". + +DO $$ +DECLARE + v_enabled text; + v_url text; + v_raw text; + v_items jsonb; + v_new_item jsonb; +BEGIN + -- Read legacy settings + SELECT value INTO v_enabled + FROM settings WHERE key = 'purchase_subscription_enabled'; + SELECT value INTO v_url + FROM settings WHERE key = 'purchase_subscription_url'; + + -- Skip if not enabled or URL is empty + IF COALESCE(v_enabled, '') <> 'true' OR COALESCE(TRIM(v_url), '') = '' THEN + RETURN; + END IF; + + -- Read current custom_menu_items + SELECT value INTO v_raw + FROM settings WHERE key = 'custom_menu_items'; + + IF COALESCE(v_raw, '') = '' OR v_raw = 'null' THEN + v_items := '[]'::jsonb; + ELSE + v_items := v_raw::jsonb; + END IF; + + -- Skip if already migrated (item with id "migrated_purchase_subscription" exists) + IF EXISTS ( + SELECT 1 FROM jsonb_array_elements(v_items) elem + WHERE elem ->> 'id' = 'migrated_purchase_subscription' + ) THEN + RETURN; + END IF; + + -- Build the new menu item + v_new_item := jsonb_build_object( + 'id', 'migrated_purchase_subscription', + 'label', 'Purchase', + 'icon_svg', '', + 'url', TRIM(v_url), + 'visibility', 'user', + 'sort_order', 100 + ); + + -- Append to array + v_items := v_items || jsonb_build_array(v_new_item); + + -- Upsert custom_menu_items + INSERT INTO settings (key, value) + VALUES ('custom_menu_items', v_items::text) + ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value; + + -- Clear legacy settings + UPDATE settings SET value = 'false' WHERE key = 'purchase_subscription_enabled'; + UPDATE settings SET value = '' WHERE key = 'purchase_subscription_url'; + + RAISE NOTICE '[migration-096] Migrated purchase_subscription_url (%) to custom_menu_items', v_url; +END $$; diff --git a/backend/migrations/098_remove_easypay_from_enabled_payment_types.sql b/backend/migrations/098_remove_easypay_from_enabled_payment_types.sql new file mode 100644 index 00000000..8128ed09 --- /dev/null +++ b/backend/migrations/098_remove_easypay_from_enabled_payment_types.sql @@ -0,0 +1,17 @@ +-- 098_remove_easypay_from_enabled_payment_types.sql +-- +-- Removes "easypay" from ENABLED_PAYMENT_TYPES setting. +-- "easypay" is a provider key, not a payment type. Valid payment types +-- are: alipay, wxpay, alipay_direct, wxpay_direct, stripe. +-- +-- Idempotent: safe to run multiple times. + +UPDATE settings + SET value = array_to_string( + array_remove( + string_to_array(value, ','), + 'easypay' + ), ',' + ) + WHERE key = 'ENABLED_PAYMENT_TYPES' + AND value LIKE '%easypay%'; diff --git a/backend/migrations/099_add_payment_mode.sql b/backend/migrations/099_add_payment_mode.sql new file mode 100644 index 00000000..eeb6ba7b --- /dev/null +++ b/backend/migrations/099_add_payment_mode.sql @@ -0,0 +1,16 @@ +-- Add payment_mode field to payment_provider_instances +-- Values: 'redirect' (hosted page redirect), 'api' (API call for QR/payurl), '' (default/N/A) +ALTER TABLE payment_provider_instances ADD COLUMN IF NOT EXISTS payment_mode VARCHAR(20) NOT NULL DEFAULT ''; + +-- Migrate existing data: easypay instances with 'easypay' in supported_types → redirect mode +-- Remove 'easypay' from supported_types and set payment_mode = 'redirect' +UPDATE payment_provider_instances +SET payment_mode = 'redirect', + supported_types = TRIM(BOTH ',' FROM REPLACE(REPLACE(REPLACE( + supported_types, 'easypay,', ''), ',easypay', ''), 'easypay', '')) +WHERE provider_key = 'easypay' AND supported_types LIKE '%easypay%'; + +-- EasyPay instances without 'easypay' in supported_types → api mode +UPDATE payment_provider_instances +SET payment_mode = 'api' +WHERE provider_key = 'easypay' AND payment_mode = ''; diff --git a/backend/migrations/100_add_out_trade_no_to_payment_orders.sql b/backend/migrations/100_add_out_trade_no_to_payment_orders.sql new file mode 100644 index 00000000..896c3c95 --- /dev/null +++ b/backend/migrations/100_add_out_trade_no_to_payment_orders.sql @@ -0,0 +1,6 @@ +-- 100_add_out_trade_no_to_payment_orders.sql +-- Adds out_trade_no column for external order ID used with payment providers. +-- Allows webhook handlers to look up orders by external ID instead of embedding DB ID. + +ALTER TABLE payment_orders ADD COLUMN IF NOT EXISTS out_trade_no VARCHAR(64) NOT NULL DEFAULT ''; +CREATE INDEX IF NOT EXISTS paymentorder_out_trade_no ON payment_orders (out_trade_no); diff --git a/frontend/package.json b/frontend/package.json index d2a6dede..14efbfdb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@lobehub/icons": "^4.0.2", + "@stripe/stripe-js": "^9.0.1", "@tanstack/vue-virtual": "^3.13.23", "@vueuse/core": "^10.7.0", "axios": "^1.13.5", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 505b72f3..9698352b 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@lobehub/icons': specifier: ^4.0.2 version: 4.0.2(@lobehub/ui@4.9.2)(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@stripe/stripe-js': + specifier: ^9.0.1 + version: 9.0.1 '@tanstack/vue-virtual': specifier: ^3.13.23 version: 3.13.23(vue@3.5.26(typescript@5.6.3)) @@ -1379,6 +1382,10 @@ packages: peerDependencies: react: '>= 16.3.0' + '@stripe/stripe-js@9.0.1': + resolution: {integrity: sha512-un0URSosrW7wNr7xZ5iI2mC9mdeXZ3KERoVlA2RdmeLXYxHUPXq0yHzir2n/MtyXXEdSaELtz4WXGS6dzPEeKA==} + engines: {node: '>=12.16'} + '@tanstack/virtual-core@3.13.23': resolution: {integrity: sha512-zSz2Z2HNyLjCplANTDyl3BcdQJc2k1+yyFoKhNRmCr7V7dY8o8q5m8uFTI1/Pg1kL+Hgrz6u3Xo6eFUB7l66cg==} @@ -5819,6 +5826,8 @@ snapshots: dependencies: react: 19.2.3 + '@stripe/stripe-js@9.0.1': {} + '@tanstack/virtual-core@3.13.23': {} '@tanstack/vue-virtual@3.13.23(vue@3.5.26(typescript@5.6.3))': diff --git a/frontend/src/api/admin/index.ts b/frontend/src/api/admin/index.ts index da1e3cfa..72597365 100644 --- a/frontend/src/api/admin/index.ts +++ b/frontend/src/api/admin/index.ts @@ -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 diff --git a/frontend/src/api/admin/payment.ts b/frontend/src/api/admin/payment.ts new file mode 100644 index 00000000..946c91b0 --- /dev/null +++ b/frontend/src/api/admin/payment.ts @@ -0,0 +1,176 @@ +/** + * 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' + +/** Admin-facing payment config returned by GET /admin/payment/config */ +export interface AdminPaymentConfig { + enabled: boolean + min_amount: number + max_amount: number + daily_limit: number + order_timeout_minutes: number + max_pending_orders: number + enabled_payment_types: string[] + balance_disabled: boolean + load_balance_strategy: string + product_name_prefix: string + product_name_suffix: string + help_image_url: string + help_text: string +} + +/** Fields accepted by PUT /admin/payment/config (all optional via pointer semantics) */ +export interface UpdatePaymentConfigRequest { + enabled?: boolean + min_amount?: number + max_amount?: number + daily_limit?: number + order_timeout_minutes?: number + max_pending_orders?: number + enabled_payment_types?: string[] + balance_disabled?: boolean + load_balance_strategy?: string + product_name_prefix?: string + product_name_suffix?: string + help_image_url?: string + help_text?: string +} + +export const adminPaymentAPI = { + // ==================== Config ==================== + + /** Get payment configuration (admin view) */ + getConfig() { + return apiClient.get('/admin/payment/config') + }, + + /** Update payment configuration */ + updateConfig(data: UpdatePaymentConfigRequest) { + return apiClient.put('/admin/payment/config', data) + }, + + // ==================== Dashboard ==================== + + /** Get payment dashboard statistics */ + getDashboard(days?: number) { + return apiClient.get('/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>('/admin/payment/orders', { params }) + }, + + /** Get a specific order by ID */ + getOrder(id: number) { + return apiClient.get(`/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; force?: boolean }) { + return apiClient.post(`/admin/payment/orders/${id}/refund`, data) + }, + + // ==================== Channels ==================== + + /** Get all payment channels */ + getChannels() { + return apiClient.get('/admin/payment/channels') + }, + + /** Create a payment channel */ + createChannel(data: Partial) { + return apiClient.post('/admin/payment/channels', data) + }, + + /** Update a payment channel */ + updateChannel(id: number, data: Partial) { + return apiClient.put(`/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('/admin/payment/plans') + }, + + /** Create a subscription plan */ + createPlan(data: Record) { + return apiClient.post('/admin/payment/plans', data) + }, + + /** Update a subscription plan */ + updatePlan(id: number, data: Record) { + return apiClient.put(`/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('/admin/payment/providers') + }, + + /** Create a provider instance */ + createProvider(data: Partial) { + return apiClient.post('/admin/payment/providers', data) + }, + + /** Update a provider instance */ + updateProvider(id: number, data: Partial) { + return apiClient.put(`/admin/payment/providers/${id}`, data) + }, + + /** Delete a provider instance */ + deleteProvider(id: number) { + return apiClient.delete(`/admin/payment/providers/${id}`) + } +} + +export default adminPaymentAPI diff --git a/frontend/src/api/admin/settings.ts b/frontend/src/api/admin/settings.ts index 9916f1ab..3b529eb2 100644 --- a/frontend/src/api/admin/settings.ts +++ b/frontend/src/api/admin/settings.ts @@ -38,8 +38,7 @@ export interface SystemSettings { doc_url: string home_content: string hide_ccs_import_button: boolean - purchase_subscription_enabled: boolean - purchase_subscription_url: string + sora_client_enabled: boolean backend_mode_enabled: boolean custom_menu_items: CustomMenuItem[] custom_endpoints: CustomEndpoint[] @@ -114,6 +113,26 @@ export interface SystemSettings { enable_fingerprint_unification: boolean enable_metadata_passthrough: boolean enable_cch_signing: boolean + + // Payment configuration + payment_enabled: boolean + payment_min_amount: number + payment_max_amount: number + payment_daily_limit: number + payment_order_timeout_minutes: number + payment_max_pending_orders: number + payment_enabled_types: string[] + payment_balance_disabled: boolean + payment_load_balance_strategy: string + payment_product_name_prefix: string + payment_product_name_suffix: string + payment_help_image_url: string + payment_help_text: string + payment_cancel_rate_limit_enabled: boolean + payment_cancel_rate_limit_max: number + payment_cancel_rate_limit_window: number + payment_cancel_rate_limit_unit: string + payment_cancel_rate_limit_window_mode: string } export interface UpdateSettingsRequest { @@ -136,8 +155,6 @@ export interface UpdateSettingsRequest { doc_url?: string home_content?: string hide_ccs_import_button?: boolean - purchase_subscription_enabled?: boolean - purchase_subscription_url?: string backend_mode_enabled?: boolean custom_menu_items?: CustomMenuItem[] custom_endpoints?: CustomEndpoint[] @@ -194,6 +211,25 @@ export interface UpdateSettingsRequest { enable_fingerprint_unification?: boolean enable_metadata_passthrough?: boolean enable_cch_signing?: boolean + // Payment configuration + payment_enabled?: boolean + payment_min_amount?: number + payment_max_amount?: number + payment_daily_limit?: number + payment_order_timeout_minutes?: number + payment_max_pending_orders?: number + payment_enabled_types?: string[] + payment_balance_disabled?: boolean + payment_load_balance_strategy?: string + payment_product_name_prefix?: string + payment_product_name_suffix?: string + payment_help_image_url?: string + payment_help_text?: string + payment_cancel_rate_limit_enabled?: boolean + payment_cancel_rate_limit_max?: number + payment_cancel_rate_limit_window?: number + payment_cancel_rate_limit_unit?: string + payment_cancel_rate_limit_window_mode?: string } /** diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 070ce648..6b3ef174 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -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' diff --git a/frontend/src/api/payment.ts b/frontend/src/api/payment.ts new file mode 100644 index 00000000..1389b60f --- /dev/null +++ b/frontend/src/api/payment.ts @@ -0,0 +1,79 @@ +/** + * User Payment API endpoints + * Handles payment operations for regular users + */ + +import { apiClient } from './client' +import type { + PaymentConfig, + SubscriptionPlan, + PaymentChannel, + MethodLimitsResponse, + CheckoutInfoResponse, + 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('/payment/config') + }, + + /** Get available subscription plans */ + getPlans() { + return apiClient.get('/payment/plans') + }, + + /** Get available payment channels */ + getChannels() { + return apiClient.get('/payment/channels') + }, + + /** Get all checkout page data in a single call */ + getCheckoutInfo() { + return apiClient.get('/payment/checkout-info') + }, + + /** Get payment method limits and fee rates */ + getLimits() { + return apiClient.get('/payment/limits') + }, + + /** Create a new payment order */ + createOrder(data: CreateOrderRequest) { + return apiClient.post('/payment/orders', data) + }, + + /** Get current user's orders */ + getMyOrders(params?: { page?: number; page_size?: number; status?: string }) { + return apiClient.get>('/payment/orders/my', { params }) + }, + + /** Get a specific order by ID */ + getOrder(id: number) { + return apiClient.get(`/payment/orders/${id}`) + }, + + /** Cancel a pending order */ + cancelOrder(id: number) { + return apiClient.post(`/payment/orders/${id}/cancel`) + }, + + /** Verify order payment status with upstream provider */ + verifyOrder(outTradeNo: string) { + return apiClient.post('/payment/orders/verify', { out_trade_no: outTradeNo }) + }, + + /** Verify order payment status without auth (public endpoint for result page) */ + verifyOrderPublic(outTradeNo: string) { + return apiClient.post('/payment/public/orders/verify', { out_trade_no: outTradeNo }) + }, + + /** Request a refund for a completed order */ + requestRefund(id: number, data: { reason: string }) { + return apiClient.post(`/payment/orders/${id}/refund-request`, data) + } +} diff --git a/frontend/src/assets/icons/alipay.svg b/frontend/src/assets/icons/alipay.svg new file mode 100644 index 00000000..22c744c3 --- /dev/null +++ b/frontend/src/assets/icons/alipay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/icons/easypay.svg b/frontend/src/assets/icons/easypay.svg new file mode 100644 index 00000000..7c7df9a8 --- /dev/null +++ b/frontend/src/assets/icons/easypay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/icons/stripe.svg b/frontend/src/assets/icons/stripe.svg new file mode 100644 index 00000000..7bfb7250 --- /dev/null +++ b/frontend/src/assets/icons/stripe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/icons/wxpay.svg b/frontend/src/assets/icons/wxpay.svg new file mode 100644 index 00000000..3e102acf --- /dev/null +++ b/frontend/src/assets/icons/wxpay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/components/admin/payment/AdminOrderDetail.vue b/frontend/src/components/admin/payment/AdminOrderDetail.vue new file mode 100644 index 00000000..b10bc76b --- /dev/null +++ b/frontend/src/components/admin/payment/AdminOrderDetail.vue @@ -0,0 +1,149 @@ + + + diff --git a/frontend/src/components/admin/payment/AdminOrderTable.vue b/frontend/src/components/admin/payment/AdminOrderTable.vue new file mode 100644 index 00000000..61ffbfa8 --- /dev/null +++ b/frontend/src/components/admin/payment/AdminOrderTable.vue @@ -0,0 +1,237 @@ + + + diff --git a/frontend/src/components/admin/payment/AdminRefundDialog.vue b/frontend/src/components/admin/payment/AdminRefundDialog.vue new file mode 100644 index 00000000..88dfd2ce --- /dev/null +++ b/frontend/src/components/admin/payment/AdminRefundDialog.vue @@ -0,0 +1,234 @@ + + + diff --git a/frontend/src/components/admin/payment/DailyRevenueChart.vue b/frontend/src/components/admin/payment/DailyRevenueChart.vue new file mode 100644 index 00000000..77583da1 --- /dev/null +++ b/frontend/src/components/admin/payment/DailyRevenueChart.vue @@ -0,0 +1,99 @@ + + + diff --git a/frontend/src/components/admin/payment/OrderStatsCards.vue b/frontend/src/components/admin/payment/OrderStatsCards.vue new file mode 100644 index 00000000..0f7ec956 --- /dev/null +++ b/frontend/src/components/admin/payment/OrderStatsCards.vue @@ -0,0 +1,77 @@ + + + diff --git a/frontend/src/components/admin/payment/PaymentMethodChart.vue b/frontend/src/components/admin/payment/PaymentMethodChart.vue new file mode 100644 index 00000000..dd6909e9 --- /dev/null +++ b/frontend/src/components/admin/payment/PaymentMethodChart.vue @@ -0,0 +1,75 @@ + + + diff --git a/frontend/src/components/admin/payment/TopUsersLeaderboard.vue b/frontend/src/components/admin/payment/TopUsersLeaderboard.vue new file mode 100644 index 00000000..1c85fcf1 --- /dev/null +++ b/frontend/src/components/admin/payment/TopUsersLeaderboard.vue @@ -0,0 +1,52 @@ + + + diff --git a/frontend/src/components/payment/AmountInput.vue b/frontend/src/components/payment/AmountInput.vue new file mode 100644 index 00000000..c3d9aa85 --- /dev/null +++ b/frontend/src/components/payment/AmountInput.vue @@ -0,0 +1,111 @@ + + + diff --git a/frontend/src/components/payment/OrderStatusBadge.vue b/frontend/src/components/payment/OrderStatusBadge.vue new file mode 100644 index 00000000..a0425492 --- /dev/null +++ b/frontend/src/components/payment/OrderStatusBadge.vue @@ -0,0 +1,45 @@ + + + diff --git a/frontend/src/components/payment/OrderTable.vue b/frontend/src/components/payment/OrderTable.vue new file mode 100644 index 00000000..73a2ddd9 --- /dev/null +++ b/frontend/src/components/payment/OrderTable.vue @@ -0,0 +1,71 @@ + + + diff --git a/frontend/src/components/payment/PaymentMethodSelector.vue b/frontend/src/components/payment/PaymentMethodSelector.vue new file mode 100644 index 00000000..5e3f801c --- /dev/null +++ b/frontend/src/components/payment/PaymentMethodSelector.vue @@ -0,0 +1,91 @@ + + + diff --git a/frontend/src/components/payment/PaymentProviderDialog.vue b/frontend/src/components/payment/PaymentProviderDialog.vue new file mode 100644 index 00000000..9b60cba1 --- /dev/null +++ b/frontend/src/components/payment/PaymentProviderDialog.vue @@ -0,0 +1,497 @@ + + + + + + + + +
@@ -2388,6 +2442,21 @@
+ + + +
@@ -2402,15 +2471,20 @@ import type { DefaultSubscriptionSetting } from '@/api/admin/settings' import type { AdminGroup } from '@/types' +import type { ProviderInstance } from '@/types/payment' import AppLayout from '@/components/layout/AppLayout.vue' import Icon from '@/components/icons/Icon.vue' import Select from '@/components/common/Select.vue' +import ConfirmDialog from '@/components/common/ConfirmDialog.vue' +import PaymentProviderList from '@/components/payment/PaymentProviderList.vue' +import PaymentProviderDialog from '@/components/payment/PaymentProviderDialog.vue' import GroupBadge from '@/components/common/GroupBadge.vue' import GroupOptionItem from '@/components/common/GroupOptionItem.vue' import Toggle from '@/components/common/Toggle.vue' import ImageUpload from '@/components/common/ImageUpload.vue' import BackupSettings from '@/views/admin/BackupView.vue' import { useClipboard } from '@/composables/useClipboard' +import { extractApiErrorMessage } from '@/utils/apiError' import { useAppStore } from '@/stores' import { useAdminSettingsStore } from '@/stores/adminSettings' import { @@ -2424,13 +2498,14 @@ const { t } = useI18n() const appStore = useAppStore() const adminSettingsStore = useAdminSettingsStore() -type SettingsTab = 'general' | 'security' | 'users' | 'gateway' | 'email' | 'backup' +type SettingsTab = 'general' | 'security' | 'users' | 'gateway' | 'payment' | 'email' | 'backup' | 'data' const activeTab = ref('general') const settingsTabs = [ { key: 'general' as SettingsTab, icon: 'home' as const }, { key: 'security' as SettingsTab, icon: 'shield' as const }, { key: 'users' as SettingsTab, icon: 'user' as const }, { key: 'gateway' as SettingsTab, icon: 'server' as const }, + { key: 'payment' as SettingsTab, icon: 'creditCard' as const }, { key: 'email' as SettingsTab, icon: 'mail' as const }, { key: 'backup' as SettingsTab, icon: 'database' as const }, ] @@ -2537,8 +2612,8 @@ const form = reactive({ home_content: '', backend_mode_enabled: false, hide_ccs_import_button: false, - purchase_subscription_enabled: false, - purchase_subscription_url: '', + payment_enabled: false, payment_min_amount: 1, payment_max_amount: 10000, payment_daily_limit: 50000, payment_max_pending_orders: 3, payment_order_timeout_minutes: 30, payment_balance_disabled: false, payment_enabled_types: [], payment_help_image_url: '', payment_help_text: '', payment_product_name_prefix: '', payment_product_name_suffix: '', payment_load_balance_strategy: 'round-robin', payment_cancel_rate_limit_enabled: false, payment_cancel_rate_limit_max: 10, payment_cancel_rate_limit_window: 1, payment_cancel_rate_limit_unit: 'day', payment_cancel_rate_limit_window_mode: 'rolling', + sora_client_enabled: false, custom_menu_items: [] as Array<{id: string; label: string; icon_svg: string; url: string; visibility: 'user' | 'admin'; sort_order: number}>, custom_endpoints: [] as Array<{name: string; endpoint: string; description: string}>, frontend_url: '', @@ -2767,7 +2842,13 @@ async function loadSettings() { loadFailed.value = false try { const settings = await adminAPI.settings.getSettings() - Object.assign(form, settings) + settings.payment_load_balance_strategy = settings.payment_load_balance_strategy || 'round-robin' + // Only assign non-null values from backend (null means unconfigured, keep defaults) + for (const [key, value] of Object.entries(settings)) { + if (value !== null && value !== undefined) { + (form as Record)[key] = value + } + } form.backend_mode_enabled = settings.backend_mode_enabled form.default_subscriptions = Array.isArray(settings.default_subscriptions) ? settings.default_subscriptions @@ -2786,11 +2867,9 @@ async function loadSettings() { form.turnstile_secret_key = '' form.linuxdo_connect_client_secret = '' form.oidc_connect_client_secret = '' - } catch (error: any) { + } catch (error: unknown) { loadFailed.value = true - appStore.showError( - t('admin.settings.failedToLoad') + ': ' + (error.message || t('common.unknownError')) - ) + appStore.showError(extractApiErrorMessage(error, t('admin.settings.failedToLoad'))) } finally { loading.value = false } @@ -2802,8 +2881,7 @@ async function loadSubscriptionGroups() { subscriptionGroups.value = groups.filter( (group) => group.subscription_type === 'subscription' && group.status === 'active' ) - } catch (error) { - console.error('Failed to load subscription groups:', error) + } catch (_error: unknown) { subscriptionGroups.value = [] } } @@ -2863,21 +2941,6 @@ async function saveSettings() { // Optional URL fields: auto-clear invalid values so they don't cause backend 400 errors if (!isValidHttpUrl(form.frontend_url)) form.frontend_url = '' if (!isValidHttpUrl(form.doc_url)) form.doc_url = '' - // Purchase URL: required when enabled; auto-clear when disabled to avoid backend rejection - if (form.purchase_subscription_enabled) { - if (!form.purchase_subscription_url) { - appStore.showError(t('admin.settings.purchase.url') + ': URL is required when purchase is enabled') - saving.value = false - return - } - if (!isValidHttpUrl(form.purchase_subscription_url)) { - appStore.showError(t('admin.settings.purchase.url') + ': must be an absolute http(s) URL (e.g. https://example.com)') - saving.value = false - return - } - } else if (!isValidHttpUrl(form.purchase_subscription_url)) { - form.purchase_subscription_url = '' - } const payload: UpdateSettingsRequest = { registration_enabled: form.registration_enabled, @@ -2901,8 +2964,6 @@ async function saveSettings() { home_content: form.home_content, backend_mode_enabled: form.backend_mode_enabled, hide_ccs_import_button: form.hide_ccs_import_button, - purchase_subscription_enabled: form.purchase_subscription_enabled, - purchase_subscription_url: form.purchase_subscription_url, custom_menu_items: form.custom_menu_items, custom_endpoints: form.custom_endpoints, frontend_url: form.frontend_url, @@ -2954,10 +3015,34 @@ async function saveSettings() { allow_ungrouped_key_scheduling: form.allow_ungrouped_key_scheduling, enable_fingerprint_unification: form.enable_fingerprint_unification, enable_metadata_passthrough: form.enable_metadata_passthrough, - enable_cch_signing: form.enable_cch_signing + enable_cch_signing: form.enable_cch_signing, + // Payment configuration + payment_enabled: form.payment_enabled, + payment_min_amount: Number(form.payment_min_amount) || 0, + payment_max_amount: Number(form.payment_max_amount) || 0, + payment_daily_limit: Number(form.payment_daily_limit) || 0, + payment_max_pending_orders: Number(form.payment_max_pending_orders) || 0, + payment_order_timeout_minutes: Number(form.payment_order_timeout_minutes) || 0, + payment_balance_disabled: form.payment_balance_disabled, + payment_enabled_types: form.payment_enabled_types, + payment_load_balance_strategy: form.payment_load_balance_strategy, + payment_product_name_prefix: form.payment_product_name_prefix, + payment_product_name_suffix: form.payment_product_name_suffix, + payment_help_image_url: form.payment_help_image_url, + payment_help_text: form.payment_help_text, + payment_cancel_rate_limit_enabled: form.payment_cancel_rate_limit_enabled, + payment_cancel_rate_limit_max: Number(form.payment_cancel_rate_limit_max) || 10, + payment_cancel_rate_limit_window: Number(form.payment_cancel_rate_limit_window) || 1, + payment_cancel_rate_limit_unit: form.payment_cancel_rate_limit_unit, + payment_cancel_rate_limit_window_mode: form.payment_cancel_rate_limit_window_mode, } + const updated = await adminAPI.settings.updateSettings(payload) - Object.assign(form, updated) + for (const [key, value] of Object.entries(updated)) { + if (value !== null && value !== undefined) { + (form as Record)[key] = value + } + } registrationEmailSuffixWhitelistTags.value = normalizeRegistrationEmailSuffixDomains( updated.registration_email_suffix_whitelist ) @@ -2971,10 +3056,8 @@ async function saveSettings() { await appStore.fetchPublicSettings(true) await adminSettingsStore.fetch(true) appStore.showSuccess(t('admin.settings.settingsSaved')) - } catch (error: any) { - appStore.showError( - t('admin.settings.failedToSave') + ': ' + (error.message || t('common.unknownError')) - ) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('admin.settings.failedToSave'))) } finally { saving.value = false } @@ -2993,10 +3076,8 @@ async function testSmtpConnection() { }) // API returns { message: "..." } on success, errors are thrown as exceptions appStore.showSuccess(result.message || t('admin.settings.smtpConnectionSuccess')) - } catch (error: any) { - appStore.showError( - t('admin.settings.failedToTestSmtp') + ': ' + (error.message || t('common.unknownError')) - ) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('admin.settings.failedToTestSmtp'))) } finally { testingSmtp.value = false } @@ -3023,10 +3104,8 @@ async function sendTestEmail() { }) // API returns { message: "..." } on success, errors are thrown as exceptions appStore.showSuccess(result.message || t('admin.settings.testEmailSent')) - } catch (error: any) { - appStore.showError( - t('admin.settings.failedToSendTestEmail') + ': ' + (error.message || t('common.unknownError')) - ) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('admin.settings.failedToSendTestEmail'))) } finally { sendingTestEmail.value = false } @@ -3039,8 +3118,8 @@ async function loadAdminApiKey() { const status = await adminAPI.settings.getAdminApiKey() adminApiKeyExists.value = status.exists adminApiKeyMasked.value = status.masked_key - } catch (error: any) { - console.error('Failed to load admin API key status:', error) + } catch (_error: unknown) { + // Silent fail - admin API key status is non-critical } finally { adminApiKeyLoading.value = false } @@ -3054,8 +3133,8 @@ async function createAdminApiKey() { adminApiKeyExists.value = true adminApiKeyMasked.value = result.key.substring(0, 10) + '...' + result.key.slice(-4) appStore.showSuccess(t('admin.settings.adminApiKey.keyGenerated')) - } catch (error: any) { - appStore.showError(error.message || t('common.error')) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('common.error'))) } finally { adminApiKeyOperating.value = false } @@ -3075,8 +3154,8 @@ async function deleteAdminApiKey() { adminApiKeyMasked.value = '' newAdminApiKey.value = '' appStore.showSuccess(t('admin.settings.adminApiKey.keyDeleted')) - } catch (error: any) { - appStore.showError(error.message || t('common.error')) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('common.error'))) } finally { adminApiKeyOperating.value = false } @@ -3099,8 +3178,8 @@ async function loadOverloadCooldownSettings() { try { const settings = await adminAPI.settings.getOverloadCooldownSettings() Object.assign(overloadCooldownForm, settings) - } catch (error: any) { - console.error('Failed to load overload cooldown settings:', error) + } catch (_error: unknown) { + // Silent fail - settings will use defaults } finally { overloadCooldownLoading.value = false } @@ -3115,10 +3194,8 @@ async function saveOverloadCooldownSettings() { }) Object.assign(overloadCooldownForm, updated) appStore.showSuccess(t('admin.settings.overloadCooldown.saved')) - } catch (error: any) { - appStore.showError( - t('admin.settings.overloadCooldown.saveFailed') + ': ' + (error.message || t('common.unknownError')) - ) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('admin.settings.overloadCooldown.saveFailed'))) } finally { overloadCooldownSaving.value = false } @@ -3130,8 +3207,8 @@ async function loadStreamTimeoutSettings() { try { const settings = await adminAPI.settings.getStreamTimeoutSettings() Object.assign(streamTimeoutForm, settings) - } catch (error: any) { - console.error('Failed to load stream timeout settings:', error) + } catch (_error: unknown) { + // Silent fail - settings will use defaults } finally { streamTimeoutLoading.value = false } @@ -3149,10 +3226,8 @@ async function saveStreamTimeoutSettings() { }) Object.assign(streamTimeoutForm, updated) appStore.showSuccess(t('admin.settings.streamTimeout.saved')) - } catch (error: any) { - appStore.showError( - t('admin.settings.streamTimeout.saveFailed') + ': ' + (error.message || t('common.unknownError')) - ) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('admin.settings.streamTimeout.saveFailed'))) } finally { streamTimeoutSaving.value = false } @@ -3168,8 +3243,8 @@ async function loadRectifierSettings() { if (!Array.isArray(rectifierForm.apikey_signature_patterns)) { rectifierForm.apikey_signature_patterns = [] } - } catch (error: any) { - console.error('Failed to load rectifier settings:', error) + } catch (_error: unknown) { + // Silent fail - settings will use defaults } finally { rectifierLoading.value = false } @@ -3192,10 +3267,8 @@ async function saveRectifierSettings() { rectifierForm.apikey_signature_patterns = [] } appStore.showSuccess(t('admin.settings.rectifier.saved')) - } catch (error: any) { - appStore.showError( - t('admin.settings.rectifier.saveFailed') + ': ' + (error.message || t('common.unknownError')) - ) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('admin.settings.rectifier.saveFailed'))) } finally { rectifierSaving.value = false } @@ -3267,8 +3340,8 @@ async function loadBetaPolicySettings() { try { const settings = await adminAPI.settings.getBetaPolicySettings() betaPolicyForm.rules = settings.rules - } catch (error: any) { - console.error('Failed to load beta policy settings:', error) + } catch (_error: unknown) { + // Silent fail - settings will use defaults } finally { betaPolicyLoading.value = false } @@ -3296,15 +3369,182 @@ async function saveBetaPolicySettings() { }) betaPolicyForm.rules = updated.rules appStore.showSuccess(t('admin.settings.betaPolicy.saved')) - } catch (error: any) { - appStore.showError( - t('admin.settings.betaPolicy.saveFailed') + ': ' + (error.message || t('common.unknownError')) - ) + } catch (error: unknown) { + appStore.showError(extractApiErrorMessage(error, t('admin.settings.betaPolicy.saveFailed'))) } finally { betaPolicySaving.value = false } } +// ==================== Provider Management ==================== + +const allPaymentTypes = computed(() => [ + { value: 'easypay', label: t('payment.methods.easypay') }, + { value: 'alipay', label: t('payment.methods.alipay') }, + { value: 'wxpay', label: t('payment.methods.wxpay') }, + { value: 'stripe', label: t('payment.methods.stripe') }, +]) + +function isPaymentTypeEnabled(type: string): boolean { + return form.payment_enabled_types.includes(type) +} + +const hasAnyPaymentTypeEnabled = computed(() => form.payment_enabled_types.length > 0) + +function togglePaymentType(type: string) { + if (form.payment_enabled_types.includes(type)) { + form.payment_enabled_types = form.payment_enabled_types.filter(t => t !== type) + // Disable all provider instances matching this type + disableProvidersByType(type) + } else { + form.payment_enabled_types = [...form.payment_enabled_types, type] + } +} + +async function disableProvidersByType(type: string) { + const matching = providers.value.filter(p => p.provider_key === type && p.enabled) + for (const p of matching) { + try { + await adminAPI.payment.updateProvider(p.id, { enabled: false }) + p.enabled = false + } catch (err: unknown) { + slog('disable provider failed', p.id, err) + } + } +} + +function slog(...args: unknown[]) { console.warn('[payment]', ...args) } + +const providersLoading = ref(false) +const providerSaving = ref(false) +const providers = ref([]) +const showProviderDialog = ref(false) +const showDeleteProviderDialog = ref(false) +const editingProvider = ref(null) +const deletingProviderId = ref(null) +const providerDialogRef = ref | null>(null) + +const providerKeyOptions = computed(() => [ + { value: 'easypay', label: t('admin.settings.payment.providerEasypay') }, + { value: 'alipay', label: t('admin.settings.payment.providerAlipay') }, + { value: 'wxpay', label: t('admin.settings.payment.providerWxpay') }, + { value: 'stripe', label: t('admin.settings.payment.providerStripe') }, +]) + +const enabledProviderKeyOptions = computed(() => { + const enabled = form.payment_enabled_types + return providerKeyOptions.value.filter(opt => enabled.includes(opt.value)) +}) + +const loadBalanceOptions = computed(() => [ + { value: 'round-robin', label: t('admin.settings.payment.strategyRoundRobin') }, + { value: 'least-amount', label: t('admin.settings.payment.strategyLeastAmount') }, +]) + +const cancelRateLimitUnitOptions = computed(() => [ + { value: 'minute', label: t('admin.settings.payment.cancelRateLimitUnitMinute') }, + { value: 'hour', label: t('admin.settings.payment.cancelRateLimitUnitHour') }, + { value: 'day', label: t('admin.settings.payment.cancelRateLimitUnitDay') }, +]) + +const cancelRateLimitModeOptions = computed(() => [ + { value: 'rolling', label: t('admin.settings.payment.cancelRateLimitWindowModeRolling') }, + { value: 'fixed', label: t('admin.settings.payment.cancelRateLimitWindowModeFixed') }, +]) + +const paymentErrorMap = computed(() => ({ + PENDING_ORDERS: t('payment.errors.PENDING_ORDERS'), +})) + +async function loadProviders() { + providersLoading.value = true + try { const res = await adminAPI.payment.getProviders(); providers.value = res.data || [] } + catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'))) } + finally { providersLoading.value = false } +} + +function openCreateProvider() { + editingProvider.value = null + providerDialogRef.value?.reset(enabledProviderKeyOptions.value[0]?.value || 'easypay') + showProviderDialog.value = true +} + +function openEditProvider(provider: ProviderInstance) { + editingProvider.value = provider + providerDialogRef.value?.loadProvider(provider) + showProviderDialog.value = true +} + +async function handleSaveProvider(payload: Partial) { + providerSaving.value = true + try { + if (editingProvider.value) { + await adminAPI.payment.updateProvider(editingProvider.value.id, payload) + } else { + await adminAPI.payment.createProvider(payload) + } + showProviderDialog.value = false + // Reload full list (API returns decrypted/formatted data with correct sort order) + await loadProviders() + // Auto-save settings so provider changes take effect immediately + await saveSettings() + } catch (err: unknown) { + appStore.showError(extractApiErrorMessage(err, t('common.error'), paymentErrorMap.value)) + } finally { + providerSaving.value = false + } +} + +async function handleToggleField(provider: ProviderInstance, field: 'enabled' | 'refund_enabled') { + const newValue = field === 'enabled' ? !provider.enabled : !provider.refund_enabled + try { + await adminAPI.payment.updateProvider(provider.id, { [field]: newValue }) + if (field === 'enabled') provider.enabled = newValue + else provider.refund_enabled = newValue + } catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'), paymentErrorMap.value)) } +} + +async function handleToggleType(provider: ProviderInstance, type: string) { + const updated = provider.supported_types.includes(type) + ? provider.supported_types.filter(t => t !== type) + : [...provider.supported_types, type] + try { + await adminAPI.payment.updateProvider(provider.id, { supported_types: updated } as any) + provider.supported_types = updated + } catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'), paymentErrorMap.value)) } +} + +function confirmDeleteProvider(provider: ProviderInstance) { + deletingProviderId.value = provider.id + showDeleteProviderDialog.value = true +} + +async function handleReorderProviders(updates: { id: number; sort_order: number }[]) { + try { + await Promise.all( + updates.map(u => adminAPI.payment.updateProvider(u.id, { sort_order: u.sort_order } as Partial)) + ) + // Update local state to match new order + for (const u of updates) { + const p = providers.value.find(p => p.id === u.id) + if (p) p.sort_order = u.sort_order + } + } catch (err: unknown) { + appStore.showError(extractApiErrorMessage(err, t('common.error'))) + loadProviders() + } +} + +async function handleDeleteProvider() { + if (!deletingProviderId.value) return + try { + await adminAPI.payment.deleteProvider(deletingProviderId.value) + appStore.showSuccess(t('common.deleted')) + showDeleteProviderDialog.value = false + loadProviders() + } catch (err: unknown) { appStore.showError(extractApiErrorMessage(err, t('common.error'), paymentErrorMap.value)) } +} + onMounted(() => { loadSettings() loadSubscriptionGroups() @@ -3313,6 +3553,7 @@ onMounted(() => { loadStreamTimeoutSettings() loadRectifierSettings() loadBetaPolicySettings() + loadProviders() }) diff --git a/frontend/src/views/admin/orders/AdminOrdersView.vue b/frontend/src/views/admin/orders/AdminOrdersView.vue new file mode 100644 index 00000000..b6a902e1 --- /dev/null +++ b/frontend/src/views/admin/orders/AdminOrdersView.vue @@ -0,0 +1,239 @@ + + + diff --git a/frontend/src/views/admin/orders/AdminPaymentDashboardView.vue b/frontend/src/views/admin/orders/AdminPaymentDashboardView.vue new file mode 100644 index 00000000..7320037d --- /dev/null +++ b/frontend/src/views/admin/orders/AdminPaymentDashboardView.vue @@ -0,0 +1,121 @@ + + + diff --git a/frontend/src/views/admin/orders/AdminPaymentPlansView.vue b/frontend/src/views/admin/orders/AdminPaymentPlansView.vue new file mode 100644 index 00000000..639b4f66 --- /dev/null +++ b/frontend/src/views/admin/orders/AdminPaymentPlansView.vue @@ -0,0 +1,317 @@ + + + diff --git a/frontend/src/views/user/PaymentQRCodeView.vue b/frontend/src/views/user/PaymentQRCodeView.vue new file mode 100644 index 00000000..50173a1a --- /dev/null +++ b/frontend/src/views/user/PaymentQRCodeView.vue @@ -0,0 +1,203 @@ + + + diff --git a/frontend/src/views/user/PaymentResultView.vue b/frontend/src/views/user/PaymentResultView.vue new file mode 100644 index 00000000..bc16918c --- /dev/null +++ b/frontend/src/views/user/PaymentResultView.vue @@ -0,0 +1,165 @@ + + + diff --git a/frontend/src/views/user/PaymentView.vue b/frontend/src/views/user/PaymentView.vue new file mode 100644 index 00000000..055e42f2 --- /dev/null +++ b/frontend/src/views/user/PaymentView.vue @@ -0,0 +1,616 @@ + + + diff --git a/frontend/src/views/user/StripePaymentView.vue b/frontend/src/views/user/StripePaymentView.vue new file mode 100644 index 00000000..6fc810c6 --- /dev/null +++ b/frontend/src/views/user/StripePaymentView.vue @@ -0,0 +1,287 @@ + + + diff --git a/frontend/src/views/user/StripePopupView.vue b/frontend/src/views/user/StripePopupView.vue new file mode 100644 index 00000000..c06c2ac5 --- /dev/null +++ b/frontend/src/views/user/StripePopupView.vue @@ -0,0 +1,164 @@ + + + diff --git a/frontend/src/views/user/SubscriptionsView.vue b/frontend/src/views/user/SubscriptionsView.vue index 5442c43b..17d5baa0 100644 --- a/frontend/src/views/user/SubscriptionsView.vue +++ b/frontend/src/views/user/SubscriptionsView.vue @@ -28,39 +28,50 @@
-
- -
+
-

- {{ subscription.group?.name || `Group #${subscription.group_id}` }} -

-

- {{ subscription.group?.description || '' }} +

+

+ {{ subscription.group?.name || `Group #${subscription.group_id}` }} +

+ + {{ platformLabel(subscription.group?.platform || '') }} + +
+

+ {{ subscription.group.description }}

- - {{ t(`userSubscriptions.status.${subscription.status}`) }} - +
+ + {{ t(`userSubscriptions.status.${subscription.status}`) }} + + +
@@ -237,14 +248,27 @@