Files
commerce/api/subscription/subscribe.go
zeekay 1943f1c093 Hanzo Commerce
Multi-tenant commerce and billing: orders, subscriptions, invoices, plans,
usage metering and a credit ledger. One Go binary. MIT OR Apache-2.0.

Claude-Session: https://claude.ai/code/session_01SAtaDFm8VDiWrhYHNNtxMw
2026-09-23 21:52:16 -07:00

139 lines
3.2 KiB
Go

package subscription
import (
"github.com/zap-proto/zip"
"github.com/hanzoai/commerce/datastore"
"github.com/hanzoai/commerce/log"
"github.com/hanzoai/commerce/models/organization"
"github.com/hanzoai/commerce/models/plan"
"github.com/hanzoai/commerce/models/subscription"
"github.com/hanzoai/commerce/models/user"
"github.com/hanzoai/commerce/util/json"
)
func subscriptionRequest(c *zip.Ctx, org *organization.Organization) (*SubscriptionReq, error) {
// Create AuthReq properly by calling order.New
sr := new(SubscriptionReq)
sr.Db = datastore.New(org.Namespaced(c.Context()))
// Try decode request body
if err := json.DecodeBytes(c.Body(), &sr); err != nil {
log.Error("Failed to decode request body: %v\n%v", c.Body(), err, c)
return nil, FailedToDecodeRequestBody
}
return sr, nil
}
func subscribe(c *zip.Ctx, org *organization.Organization) (*subscription.Subscription, *user.User, error) {
ctx := org.Datastore().Context
nsCtx := org.Namespaced(ctx)
db := datastore.New(nsCtx)
// Parse request
sr, err := subscriptionRequest(c, org)
if err != nil {
return nil, nil, err
}
log.Debug("AuthorizationReq.User_: %#v", sr.User_, c)
log.Debug("AuthorizationReq.Subscription_: %#v", sr.Subscription_, c)
sub, err := sr.Subscription()
if err != nil {
return nil, nil, err
}
log.Debug("Subscription: %#v", sub, c)
// Subscription w/o quantity defaults to 1
if sub.Quantity < 1 {
sub.Quantity = 1
}
// Try to find plan
pln := plan.New(db)
err = pln.GetById(sub.PlanId)
if err != nil {
return nil, nil, PlanDoesNotExist
}
log.Debug("Plan: %#v", pln, c)
// Get user
usr, err := sr.User()
if err != nil {
return nil, nil, err
}
log.Debug("User: %#v", usr, c)
// Payment information
sub.Buyer = usr.Buyer()
log.Debug("Buyer: %#v", sub.Buyer, c)
// The mode is the server's: the org's, or a test buyer's. Never the body's.
sub.Test = org.TestMode() || org.IsTestEmail(sub.Buyer.Email)
// Parent subscription to user
sub.Parent = usr.Key()
sub.UserId = usr.Id()
// Set plan on subscription
sub.PlanId = pln.Id()
sub.Plan = *pln
// Save user and subscription
usr.MustPut()
sub.MustPut()
return sub, usr, nil
}
func updateSubscribe(c *zip.Ctx, org *organization.Organization, sub *subscription.Subscription) (*subscription.Subscription, error) {
ctx := org.Datastore().Context
nsCtx := org.Namespaced(ctx)
db := datastore.New(nsCtx)
userId := sub.UserId
test := sub.Test
// Try decode request body
if err := json.DecodeBytes(c.Body(), &sub); err != nil {
log.Error("Failed to decode request body: %v\n%v", c.Body(), err, c)
return nil, FailedToDecodeRequestBody
}
sub.Test = test
if userId != sub.UserId {
return nil, CannotChangeUser
}
log.Warn("Quantity %v", sub.Quantity)
// Delete Case
if sub.Quantity < 1 {
return unsubscribe(c, org, sub)
}
pln := plan.New(db)
err := pln.GetById(sub.PlanId)
if err != nil {
return nil, PlanDoesNotExist
}
log.Debug("Plan: %#v", pln, c)
sub.Plan = *pln
sub.MustPut()
return sub, nil
}
func unsubscribe(c *zip.Ctx, org *organization.Organization, sub *subscription.Subscription) (*subscription.Subscription, error) {
_ = c
_ = org
sub.MustPut()
return sub, nil
}