storj/satellite/payments/coupons.go
Yingrong Zhao 5304f672ad satellite/payments: fix invoice generation to include the last day of
the month

The Stripe API had a bug before that it wasn't calcualting the input
timestamp based on correct timezone. We had a workaround to not include
the last day of the month in our code when submitting to Stripe.
Now, Stripe has fixed the issue. We need to remove the workaround and
include the last day of the month into our invoice generation

Change-Id: Ic6364ed071be73a19f0b0b46f274a02fb2489db5
2021-08-31 16:25:18 +00:00

125 lines
4.4 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package payments
import (
"context"
"time"
"storj.io/common/memory"
"storj.io/common/uuid"
)
// Coupons exposes all needed functionality to manage coupons.
//
// architecture: Service
type Coupons interface {
// GetByUserID returns the coupon applied to the specified user.
GetByUserID(ctx context.Context, userID uuid.UUID) (*Coupon, error)
// ListByUserID return list of all coupons of specified payment account.
ListByUserID(ctx context.Context, userID uuid.UUID) ([]CouponOld, error)
// TotalUsage returns sum of all usage records for specified coupon.
TotalUsage(ctx context.Context, couponID uuid.UUID) (int64, error)
// Create attaches a coupon for payment account.
Create(ctx context.Context, coupon CouponOld) (coup CouponOld, err error)
// AddPromotionalCoupon is used to add a promotional coupon for specified users who already have
// a project and do not have a promotional coupon yet.
// And updates project limits to selected size.
AddPromotionalCoupon(ctx context.Context, userID uuid.UUID) error
// PopulatePromotionalCoupons is used to populate promotional coupons through all active users who already have
// a project, payment method and do not have a promotional coupon yet.
// And updates project limits to selected size.
PopulatePromotionalCoupons(ctx context.Context, duration *int, amount int64, projectLimit memory.Size) error
// ApplyCouponCode attempts to apply a coupon code to the user.
ApplyCouponCode(ctx context.Context, userID uuid.UUID, couponCode string) (*Coupon, error)
}
// Coupon describes a discount to the payment account of a user.
type Coupon struct {
ID string `json:"id"`
PromoCode string `json:"promoCode"`
Name string `json:"name"`
AmountOff int64 `json:"amountOff"`
PercentOff float64 `json:"percentOff"`
AddedAt time.Time `json:"addedAt"`
ExpiresAt time.Time `json:"expiresAt"`
Duration CouponDuration `json:"duration"`
}
// CouponDuration represents how many billing periods a coupon is applied.
type CouponDuration string
const (
// CouponOnce indicates that a coupon can only be applied once.
CouponOnce CouponDuration = "once"
// CouponRepeating indicates that a coupon is applied every billing period for a definite amount of time.
CouponRepeating = "repeating"
// CouponForever indicates that a coupon is applied every billing period forever.
CouponForever = "forever"
)
// CouponOld is an entity that adds some funds to Accounts balance for some fixed period.
// CouponOld is attached to the project.
// At the end of the period, the entire remaining coupon amount will be returned from the account balance.
// Deprecated: Use Coupon instead.
// TODO: This struct should be removed with the rest of the custom coupon implementation code.
type CouponOld struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"userId"`
Amount int64 `json:"amount"` // Amount is stored in cents.
Duration *int `json:"duration"` // Duration is stored in number of billing periods.
Description string `json:"description"`
Type CouponType `json:"type"`
Status CouponStatus `json:"status"`
Created time.Time `json:"created"`
}
// ExpirationDate returns coupon expiration date.
//
// A coupon is valid for Duration number of full months. The month the user
// signs up is not counted in the duration. The expirated date is at the last
// day of the last valid month.
func (coupon *CouponOld) ExpirationDate() *time.Time {
if coupon.Duration == nil {
return nil
}
expireDate := time.Date(coupon.Created.Year(), coupon.Created.Month()+time.Month(*coupon.Duration)+1, 1, 0, 0, 0, 0, time.UTC)
return &expireDate
}
// CouponType indicates the type of the coupon.
type CouponType int
const (
// CouponTypePromotional defines that this coupon is a promotional coupon.
CouponTypePromotional CouponType = 0
)
// CouponStatus indicates the state of the coupon.
type CouponStatus int
const (
// CouponActive is a default coupon state.
CouponActive CouponStatus = 0
// CouponUsed status indicates that coupon was used.
CouponUsed CouponStatus = 1
// CouponExpired status indicates that coupon is expired and unavailable.
CouponExpired CouponStatus = 2
)
// CouponsPage holds set of coupon and indicates if
// there are more coupons to fetch.
type CouponsPage struct {
Coupons []CouponOld
Next bool
NextOffset int64
}