67826b92c0
* implement core foundation * inject deps * fix incorrect migration * tail migration * use transaction for migration * fix: inject deps for tests * cleanup billing management for admin * upgrade stripe sdk to v85 * set price env variables * cleanup billing management * allow multiple dev windows * fix: settings scroll * feat: show nice video thumbnail in listview * feat: implement freemium restrictions * remove unnecessary comments * refactor * docs * format * tweak network settings better hierarchy
113 lines
3.5 KiB
Go
113 lines
3.5 KiB
Go
package billing
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
var errNotFound = errors.New("not found")
|
|
|
|
type repository interface {
|
|
getSubscriptionByNetworkID(ctx context.Context, networkID string) (*Subscription, error)
|
|
upsertSubscription(ctx context.Context, sub *Subscription) error
|
|
deleteSubscriptionByID(ctx context.Context, subscriptionID string) error
|
|
|
|
getStripeCustomerID(ctx context.Context, networkID string) (string, error)
|
|
setStripeCustomerID(ctx context.Context, networkID, customerID string) error
|
|
}
|
|
|
|
type repositoryImpl struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
func newRepository(pool *pgxpool.Pool) repository {
|
|
return &repositoryImpl{pool: pool}
|
|
}
|
|
|
|
const subscriptionColumns = `id, network_id, stripe_customer_id, status, price_id, cadence, quantity, cancel_at_period_end, current_period_start, current_period_end, created_at, updated_at`
|
|
|
|
func scanSubscription(row pgx.Row, s *Subscription) error {
|
|
return row.Scan(
|
|
&s.ID, &s.NetworkID, &s.StripeCustomerID, &s.Status, &s.PriceID,
|
|
&s.Cadence, &s.Quantity, &s.CancelAtPeriodEnd,
|
|
&s.CurrentPeriodStart, &s.CurrentPeriodEnd,
|
|
&s.CreatedAt, &s.UpdatedAt,
|
|
)
|
|
}
|
|
|
|
func (r *repositoryImpl) getSubscriptionByNetworkID(ctx context.Context, networkID string) (*Subscription, error) {
|
|
var s Subscription
|
|
err := scanSubscription(
|
|
r.pool.QueryRow(ctx,
|
|
`SELECT `+subscriptionColumns+` FROM network_subscriptions WHERE network_id = $1`,
|
|
networkID,
|
|
),
|
|
&s,
|
|
)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, errNotFound
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &s, nil
|
|
}
|
|
|
|
func (r *repositoryImpl) upsertSubscription(ctx context.Context, sub *Subscription) error {
|
|
_, err := r.pool.Exec(ctx, `
|
|
INSERT INTO network_subscriptions (
|
|
id, network_id, stripe_customer_id, status, price_id, cadence,
|
|
quantity, cancel_at_period_end, current_period_start, current_period_end
|
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
ON CONFLICT (id) DO UPDATE SET
|
|
stripe_customer_id = EXCLUDED.stripe_customer_id,
|
|
status = EXCLUDED.status,
|
|
price_id = EXCLUDED.price_id,
|
|
cadence = EXCLUDED.cadence,
|
|
quantity = EXCLUDED.quantity,
|
|
cancel_at_period_end = EXCLUDED.cancel_at_period_end,
|
|
current_period_start = EXCLUDED.current_period_start,
|
|
current_period_end = EXCLUDED.current_period_end,
|
|
updated_at = NOW()
|
|
`,
|
|
sub.ID, sub.NetworkID, sub.StripeCustomerID, sub.Status, sub.PriceID, sub.Cadence,
|
|
sub.Quantity, sub.CancelAtPeriodEnd, sub.CurrentPeriodStart, sub.CurrentPeriodEnd,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (r *repositoryImpl) deleteSubscriptionByID(ctx context.Context, subscriptionID string) error {
|
|
_, err := r.pool.Exec(ctx,
|
|
`DELETE FROM network_subscriptions WHERE id = $1`,
|
|
subscriptionID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (r *repositoryImpl) getStripeCustomerID(ctx context.Context, networkID string) (string, error) {
|
|
var customerID string
|
|
err := r.pool.QueryRow(ctx,
|
|
`SELECT stripe_customer_id FROM network_stripe_customers WHERE network_id = $1`,
|
|
networkID,
|
|
).Scan(&customerID)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return "", errNotFound
|
|
}
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return customerID, nil
|
|
}
|
|
|
|
func (r *repositoryImpl) setStripeCustomerID(ctx context.Context, networkID, customerID string) error {
|
|
_, err := r.pool.Exec(ctx, `
|
|
INSERT INTO network_stripe_customers (network_id, stripe_customer_id)
|
|
VALUES ($1, $2)
|
|
ON CONFLICT (network_id) DO NOTHING
|
|
`, networkID, customerID)
|
|
return err
|
|
}
|