coupons

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 2, 2025 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrCouponExpired = errors.New("coupon expired")

ErrCouponExpired is returned when a coupon has expired.

View Source
var ErrCouponNotFound = errors.New("coupon not found")

ErrCouponNotFound is returned when a coupon doesn't exist.

View Source
var ErrCouponNotStarted = errors.New("coupon not started yet")

ErrCouponNotStarted is returned when coupon hasn't started yet.

View Source
var ErrCouponUsageLimitReached = errors.New("coupon usage limit reached")

ErrCouponUsageLimitReached is returned when coupon has no remaining uses.

Functions

This section is empty.

Types

type AppliesAt

type AppliesAt string

AppliesAt represents when the coupon should be displayed and applied.

const (
	AppliesAtCatalog  AppliesAt = "catalog"  // Product-level: Show on product pages with discounted price
	AppliesAtCheckout AppliesAt = "checkout" // Site-wide: Show only at cart/checkout
)

type CachedRepository

type CachedRepository struct {
	// contains filtered or unexported fields
}

CachedRepository wraps any Repository with a TTL-based cache.

func NewCachedRepository

func NewCachedRepository(underlying Repository, cacheTTL time.Duration) *CachedRepository

NewCachedRepository wraps a repository with caching.

func (*CachedRepository) Close

func (r *CachedRepository) Close() error

Close closes the underlying repository.

func (*CachedRepository) CreateCoupon

func (r *CachedRepository) CreateCoupon(ctx context.Context, coupon Coupon) error

CreateCoupon creates a coupon and invalidates cache.

func (*CachedRepository) DeleteCoupon

func (r *CachedRepository) DeleteCoupon(ctx context.Context, code string) error

DeleteCoupon deletes a coupon and invalidates cache.

func (*CachedRepository) GetAllAutoApplyCouponsForPayment

func (r *CachedRepository) GetAllAutoApplyCouponsForPayment(ctx context.Context, paymentMethod PaymentMethod) (map[string][]Coupon, error)

GetAllAutoApplyCouponsForPayment returns auto-apply coupons for all products with caching.

func (*CachedRepository) GetAutoApplyCouponsForPayment

func (r *CachedRepository) GetAutoApplyCouponsForPayment(ctx context.Context, productID string, paymentMethod PaymentMethod) ([]Coupon, error)

GetAutoApplyCouponsForPayment delegates to the underlying repository (no caching).

func (*CachedRepository) GetCoupon

func (r *CachedRepository) GetCoupon(ctx context.Context, code string) (Coupon, error)

GetCoupon retrieves a coupon with caching.

func (*CachedRepository) IncrementUsage

func (r *CachedRepository) IncrementUsage(ctx context.Context, code string) error

IncrementUsage increments usage and invalidates cache.

func (*CachedRepository) InvalidateCache

func (r *CachedRepository) InvalidateCache()

InvalidateCache forces the next operations to fetch fresh data.

func (*CachedRepository) ListCoupons

func (r *CachedRepository) ListCoupons(ctx context.Context) ([]Coupon, error)

ListCoupons returns all coupons with caching.

func (*CachedRepository) UpdateCoupon

func (r *CachedRepository) UpdateCoupon(ctx context.Context, coupon Coupon) error

UpdateCoupon updates a coupon and invalidates cache.

type Coupon

type Coupon struct {
	Code          string            // Coupon code (e.g., "SUMMER2024")
	DiscountType  DiscountType      // "percentage" or "fixed"
	DiscountValue float64           // Percentage (0-100) or fixed amount
	Currency      string            // For fixed discounts (usd, usdc, etc.)
	Scope         Scope             // "all" or "specific"
	ProductIDs    []string          // Applicable product IDs (for scope=specific)
	PaymentMethod PaymentMethod     // Restrict to specific payment method ("stripe", "x402", or "" for any)
	AutoApply     bool              // If true, automatically apply to matching products
	AppliesAt     AppliesAt         // When to display: "catalog" (product page) or "checkout" (cart only)
	UsageLimit    *int              // nil = unlimited, N = max uses
	UsageCount    int               // Current usage count
	StartsAt      *time.Time        // When coupon becomes valid
	ExpiresAt     *time.Time        // When coupon expires
	Active        bool              // Enable/disable coupon
	Metadata      map[string]string // Custom key-value pairs
	CreatedAt     time.Time         // Creation timestamp
	UpdatedAt     time.Time         // Last update timestamp
}

Coupon represents a discount code that users can apply.

func (Coupon) AppliesToPaymentMethod

func (c Coupon) AppliesToPaymentMethod(method PaymentMethod) bool

AppliesToPaymentMethod checks if the coupon applies to a given payment method. Empty string (PaymentMethodAny) matches all payment methods.

func (Coupon) AppliesToProduct

func (c Coupon) AppliesToProduct(productID string) bool

AppliesToProduct checks if the coupon applies to a given product ID.

func (Coupon) ApplyDiscount

func (c Coupon) ApplyDiscount(originalPrice float64) float64

ApplyDiscount calculates the price after applying this coupon.

func (Coupon) IsValid

func (c Coupon) IsValid() error

IsValid checks if the coupon is currently valid for use.

func (Coupon) ValidateConfiguration

func (c Coupon) ValidateConfiguration() error

ValidateConfiguration checks if the coupon configuration is consistent. Returns error if AppliesAt constraints are violated.

type DisabledRepository

type DisabledRepository struct{}

DisabledRepository is a no-op repository for when coupons are disabled.

func NewDisabledRepository

func NewDisabledRepository() *DisabledRepository

NewDisabledRepository creates a disabled repository.

func (*DisabledRepository) Close

func (r *DisabledRepository) Close() error

Close is a no-op when coupons are disabled.

func (*DisabledRepository) CreateCoupon

func (r *DisabledRepository) CreateCoupon(_ context.Context, _ Coupon) error

CreateCoupon is a no-op when coupons are disabled.

func (*DisabledRepository) DeleteCoupon

func (r *DisabledRepository) DeleteCoupon(_ context.Context, _ string) error

DeleteCoupon is a no-op when coupons are disabled.

func (*DisabledRepository) GetAllAutoApplyCouponsForPayment

func (r *DisabledRepository) GetAllAutoApplyCouponsForPayment(_ context.Context, _ PaymentMethod) (map[string][]Coupon, error)

GetAllAutoApplyCouponsForPayment returns an empty map when coupons are disabled.

func (*DisabledRepository) GetAutoApplyCouponsForPayment

func (r *DisabledRepository) GetAutoApplyCouponsForPayment(_ context.Context, _ string, _ PaymentMethod) ([]Coupon, error)

GetAutoApplyCouponsForPayment returns an empty list when coupons are disabled.

func (*DisabledRepository) GetCoupon

func (r *DisabledRepository) GetCoupon(_ context.Context, _ string) (Coupon, error)

GetCoupon always returns ErrCouponNotFound when coupons are disabled.

func (*DisabledRepository) IncrementUsage

func (r *DisabledRepository) IncrementUsage(_ context.Context, _ string) error

IncrementUsage is a no-op when coupons are disabled.

func (*DisabledRepository) ListCoupons

func (r *DisabledRepository) ListCoupons(_ context.Context) ([]Coupon, error)

ListCoupons returns an empty list when coupons are disabled.

func (*DisabledRepository) UpdateCoupon

func (r *DisabledRepository) UpdateCoupon(_ context.Context, _ Coupon) error

UpdateCoupon is a no-op when coupons are disabled.

type DiscountType

type DiscountType string

DiscountType represents how the discount is applied.

const (
	DiscountTypePercentage DiscountType = "percentage" // Percentage off (0-100)
	DiscountTypeFixed      DiscountType = "fixed"      // Fixed amount off
)

type MongoDBRepository

type MongoDBRepository struct {
	// contains filtered or unexported fields
}

MongoDBRepository implements Repository using MongoDB.

func NewMongoDBRepository

func NewMongoDBRepository(connectionString, database, collection string) (*MongoDBRepository, error)

NewMongoDBRepository creates a MongoDB-backed repository.

func (*MongoDBRepository) Close

func (r *MongoDBRepository) Close() error

Close closes the MongoDB connection.

func (*MongoDBRepository) CreateCoupon

func (r *MongoDBRepository) CreateCoupon(ctx context.Context, c Coupon) error

CreateCoupon creates a new coupon.

func (*MongoDBRepository) DeleteCoupon

func (r *MongoDBRepository) DeleteCoupon(ctx context.Context, code string) error

DeleteCoupon soft-deletes a coupon (sets active = false).

func (*MongoDBRepository) GetAllAutoApplyCouponsForPayment

func (r *MongoDBRepository) GetAllAutoApplyCouponsForPayment(ctx context.Context, paymentMethod PaymentMethod) (map[string][]Coupon, error)

GetAllAutoApplyCouponsForPayment returns all auto-apply coupons grouped by product ID.

func (*MongoDBRepository) GetAutoApplyCouponsForPayment

func (r *MongoDBRepository) GetAutoApplyCouponsForPayment(ctx context.Context, productID string, paymentMethod PaymentMethod) ([]Coupon, error)

GetAutoApplyCouponsForPayment returns auto-apply coupons filtered by payment method. Optimized to filter by payment method at database level.

func (*MongoDBRepository) GetCoupon

func (r *MongoDBRepository) GetCoupon(ctx context.Context, code string) (Coupon, error)

GetCoupon retrieves a coupon by code.

func (*MongoDBRepository) IncrementUsage

func (r *MongoDBRepository) IncrementUsage(ctx context.Context, code string) error

IncrementUsage atomically increments the usage count.

func (*MongoDBRepository) ListCoupons

func (r *MongoDBRepository) ListCoupons(ctx context.Context) ([]Coupon, error)

ListCoupons returns all active coupons.

func (*MongoDBRepository) UpdateCoupon

func (r *MongoDBRepository) UpdateCoupon(ctx context.Context, c Coupon) error

UpdateCoupon updates an existing coupon.

type PaymentMethod

type PaymentMethod string

PaymentMethod represents which payment method the coupon applies to.

const (
	PaymentMethodAny    PaymentMethod = ""       // Any payment method (default, empty string)
	PaymentMethodStripe PaymentMethod = "stripe" // Stripe (fiat) payments only
	PaymentMethodX402   PaymentMethod = "x402"   // x402 (crypto) payments only
)

type PostgresRepository

type PostgresRepository struct {
	// contains filtered or unexported fields
}

PostgresRepository implements Repository using PostgreSQL.

func NewPostgresRepository

func NewPostgresRepository(connectionString string, poolConfig config.PostgresPoolConfig) (*PostgresRepository, error)

NewPostgresRepository creates a PostgreSQL-backed repository.

func NewPostgresRepositoryWithDB

func NewPostgresRepositoryWithDB(db *sql.DB) *PostgresRepository

NewPostgresRepositoryWithDB creates a PostgreSQL-backed repository using an existing connection pool. This allows sharing a single connection pool across multiple repositories.

func (*PostgresRepository) Close

func (r *PostgresRepository) Close() error

Close closes the database connection.

func (*PostgresRepository) CreateCoupon

func (r *PostgresRepository) CreateCoupon(ctx context.Context, c Coupon) error

CreateCoupon creates a new coupon.

func (*PostgresRepository) DeleteCoupon

func (r *PostgresRepository) DeleteCoupon(ctx context.Context, code string) error

DeleteCoupon soft-deletes a coupon (sets active = false).

func (*PostgresRepository) GetAllAutoApplyCouponsForPayment

func (r *PostgresRepository) GetAllAutoApplyCouponsForPayment(ctx context.Context, paymentMethod PaymentMethod) (map[string][]Coupon, error)

GetAllAutoApplyCouponsForPayment returns all auto-apply coupons grouped by product ID.

func (*PostgresRepository) GetAutoApplyCouponsForPayment

func (r *PostgresRepository) GetAutoApplyCouponsForPayment(ctx context.Context, productID string, paymentMethod PaymentMethod) ([]Coupon, error)

GetAutoApplyCouponsForPayment returns auto-apply coupons filtered by payment method.

func (*PostgresRepository) GetCoupon

func (r *PostgresRepository) GetCoupon(ctx context.Context, code string) (Coupon, error)

GetCoupon retrieves a coupon by code.

func (*PostgresRepository) IncrementUsage

func (r *PostgresRepository) IncrementUsage(ctx context.Context, code string) error

IncrementUsage atomically increments the usage count.

func (*PostgresRepository) ListCoupons

func (r *PostgresRepository) ListCoupons(ctx context.Context) ([]Coupon, error)

ListCoupons returns all active coupons.

func (*PostgresRepository) UpdateCoupon

func (r *PostgresRepository) UpdateCoupon(ctx context.Context, c Coupon) error

UpdateCoupon updates an existing coupon.

func (*PostgresRepository) WithTableName

func (r *PostgresRepository) WithTableName(tableName string) *PostgresRepository

WithTableName sets a custom table name (for schema_mapping support).

type Repository

type Repository interface {
	// GetCoupon retrieves a coupon by code.
	GetCoupon(ctx context.Context, code string) (Coupon, error)

	// ListCoupons returns all active coupons.
	ListCoupons(ctx context.Context) ([]Coupon, error)

	// GetAutoApplyCouponsForPayment returns auto-apply coupons that match the product ID and payment method.
	// Returns coupons where AutoApply=true, product matches, and payment method matches (or is empty).
	// paymentMethod should be "stripe", "x402", or "" for any.
	GetAutoApplyCouponsForPayment(ctx context.Context, productID string, paymentMethod PaymentMethod) ([]Coupon, error)

	// GetAllAutoApplyCouponsForPayment returns all auto-apply coupons for a specific payment method.
	// Returns a map of productID -> []Coupon for efficient batch lookup.
	GetAllAutoApplyCouponsForPayment(ctx context.Context, paymentMethod PaymentMethod) (map[string][]Coupon, error)

	// CreateCoupon creates a new coupon.
	CreateCoupon(ctx context.Context, coupon Coupon) error

	// UpdateCoupon updates an existing coupon.
	UpdateCoupon(ctx context.Context, coupon Coupon) error

	// IncrementUsage atomically increments the usage count.
	IncrementUsage(ctx context.Context, code string) error

	// DeleteCoupon soft-deletes a coupon (sets active = false).
	DeleteCoupon(ctx context.Context, code string) error

	// Close closes any open connections.
	Close() error
}

Repository defines the interface for coupon storage.

func NewRepository

func NewRepository(cfg config.CouponConfig) (Repository, error)

NewRepository creates a coupon repository based on config.

func NewRepositoryWithDB

func NewRepositoryWithDB(cfg config.CouponConfig, sharedDB *sql.DB) (Repository, error)

NewRepositoryWithDB creates a coupon repository with an optional shared database pool. If sharedDB is provided (non-nil) for postgres sources, it will be used instead of creating a new connection. Pass nil to create a new connection pool.

type Scope

type Scope string

Scope represents what products the coupon applies to.

const (
	ScopeAll      Scope = "all"      // All products
	ScopeSpecific Scope = "specific" // Specific product IDs
)

type YAMLRepository

type YAMLRepository struct {
	// contains filtered or unexported fields
}

YAMLRepository implements Repository using in-memory YAML config.

func NewYAMLRepository

func NewYAMLRepository(coupons map[string]config.Coupon) *YAMLRepository

NewYAMLRepository creates a repository from YAML config.

func (*YAMLRepository) Close

func (r *YAMLRepository) Close() error

Close is a no-op for YAML repository.

func (*YAMLRepository) CreateCoupon

func (r *YAMLRepository) CreateCoupon(_ context.Context, _ Coupon) error

CreateCoupon is not supported for YAML repository (read-only).

func (*YAMLRepository) DeleteCoupon

func (r *YAMLRepository) DeleteCoupon(_ context.Context, _ string) error

DeleteCoupon is not supported for YAML repository (read-only).

func (*YAMLRepository) GetAllAutoApplyCouponsForPayment

func (r *YAMLRepository) GetAllAutoApplyCouponsForPayment(_ context.Context, paymentMethod PaymentMethod) (map[string][]Coupon, error)

GetAllAutoApplyCouponsForPayment returns all auto-apply coupons grouped by product ID.

func (*YAMLRepository) GetAutoApplyCouponsForPayment

func (r *YAMLRepository) GetAutoApplyCouponsForPayment(ctx context.Context, productID string, paymentMethod PaymentMethod) ([]Coupon, error)

GetAutoApplyCouponsForPayment returns auto-apply coupons that match the product ID and payment method.

func (*YAMLRepository) GetCoupon

func (r *YAMLRepository) GetCoupon(_ context.Context, code string) (Coupon, error)

GetCoupon retrieves a coupon by code.

func (*YAMLRepository) IncrementUsage

func (r *YAMLRepository) IncrementUsage(_ context.Context, _ string) error

IncrementUsage is not supported for YAML repository (read-only).

func (*YAMLRepository) ListCoupons

func (r *YAMLRepository) ListCoupons(_ context.Context) ([]Coupon, error)

ListCoupons returns all active coupons.

func (*YAMLRepository) UpdateCoupon

func (r *YAMLRepository) UpdateCoupon(_ context.Context, _ Coupon) error

UpdateCoupon is not supported for YAML repository (read-only).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL