Documentation
¶
Overview ¶
Package commerce sells access to MCP servers: products → Stripe Checkout → orders → customers → entitlements → provisioning on billing servers over the signed mcp-billing/v1 protocol (spec §4.6, docs/COMMERCE.md).
Index ¶
- Constants
- Variables
- func FormatPrice(minor int64, currency string) string
- func IsExampleProductSlug(slug string) bool
- func ParsePrice(s, currency string) (int64, error)
- func RequirePlan(ctx context.Context, d *kernel.Deps, accountID, plan string) error
- func Slugify(s string) string
- type AccountSettings
- type ActionResponse
- type Cart
- type CartCheckout
- type CartItem
- type CartLine
- type Catalog
- type CurrencyPrice
- type DeleteResponse
- type Entitlement
- type IntakeField
- type Invoice
- type ListQuery
- type MCBBError
- type Module
- type Order
- type OrderItem
- type Plan
- type Product
- type ProductGroup
- type RequestDetail
- type RequestUpdate
- type Server
- type ServerTestResponse
- type Service
- type SubscriptionEvent
- type ValidationError
- type WPProduct
Constants ¶
const ( ProductProvisioning = "provisioning" ProductService = "service" ProductDigital = "digital" )
Product is a provisioning plan, service or private digital download. PriceMinor is in the currency's minor unit (fils for AED). SEO uses the seo.FromMap keys.
const ( OrderPending = "pending" OrderPaid = "paid" OrderProvisioning = "provisioning" OrderActive = "active" OrderFailed = "failed" OrderRefunded = "refunded" OrderCancelled = "cancelled" )
Order statuses.
const ( EntitlementPending = "pending" EntitlementActive = "active" EntitlementSuspended = "suspended" EntitlementExpired = "expired" EntitlementFailed = "failed" )
Entitlement statuses.
const ( ServerUnknown = "unknown" ServerOK = "ok" ServerError = "error" )
Server statuses.
const ( SettingCurrency = "commerce.currency" SettingStripeSecret = "commerce.stripe_secret_key" // live key; db.Encrypt, AAD = key SettingWebhookSecret = "commerce.stripe_webhook_secret" // live webhook; db.Encrypt, AAD = key SettingStripeMode = "commerce.stripe_mode" // test | live SettingStripeTestKey = "commerce.stripe_test_secret_key" SettingWebhookTest = "commerce.stripe_test_webhook_secret" SettingGraceDays = "commerce.grace_days" SettingAutomaticTax = "commerce.automatic_tax" )
Setting keys.
const ( PermManage = "commerce.manage" PermViewOrders = "commerce.view_orders" )
Permissions.
const ( JobProvision = "commerce.provision" JobSuspend = "commerce.suspend" JobMagicMail = "commerce.magic_mail" JobBillingMail = "commerce.billing_mail" JobResume = "commerce.resume" CronExpire = "commerce.expire" CronGrace = "commerce.billing_grace" HookOrderPaid = "commerce.order.paid" HookEntitlementActivate = "commerce.entitlement.activated" HookSubActivated = "subscription.activated" HookSubPastDue = "subscription.past_due" HookSubCanceled = "subscription.canceled" )
Job kinds and hook names.
Variables ¶
var ( ErrNotFound = errors.New("commerce: not found") ErrStripeNotConfigured = errors.New("commerce: Stripe is not configured") ErrInvalidSignature = errors.New("commerce: invalid Stripe webhook signature") ErrNotActive = errors.New("commerce: entitlement is not active") ErrNoServer = errors.New("commerce: entitlement has no reachable billing server") ErrPeriodEnded = errors.New("commerce: the entitlement period has ended") ErrPlanRequired = errors.New("commerce: subscription plan required") )
Errors returned by the service.
Functions ¶
func FormatPrice ¶
FormatPrice renders minor units as a major-unit decimal string ("12.50").
func IsExampleProductSlug ¶ added in v0.12.0
IsExampleProductSlug reports inactive learning templates seeded on first boot.
func ParsePrice ¶
ParsePrice converts a major-unit amount ("12.5", "12,50") to minor units of currency. It rejects negatives and more decimals than the currency has.
func RequirePlan ¶ added in v0.12.0
RequirePlan looks up the commerce service. Plugins and later modules call it instead of reimplementing billing.
Types ¶
type AccountSettings ¶
type AccountSettings struct {
RegistrationEnabled bool `json:"registration_enabled"`
}
AccountSettings controls native customer registration only. Registration does not grant paid access or claim verified ownership of an email address.
type ActionResponse ¶
type ActionResponse struct {
Entitlement *Entitlement `json:"entitlement"`
}
ActionResponse is returned by entitlement actions.
type CartCheckout ¶
type Catalog ¶
type Catalog struct {
Product map[string]any `json:"product,omitempty"`
Plans []Plan `json:"plans"`
Tools []any `json:"tools,omitempty"`
Raw json.RawMessage `json:"raw,omitempty"`
}
Catalog is a billing server's GET /catalog data. Raw keeps the full payload (tools, product description…).
type CurrencyPrice ¶ added in v0.12.0
type CurrencyPrice struct {
PriceID string `json:"price_id"`
AmountMinor int64 `json:"amount_minor"`
}
CurrencyPrice is one plan price in a single ISO currency.
type DeleteResponse ¶
DeleteResponse is returned by DELETE operations.
type Entitlement ¶
type Entitlement struct {
ID string `json:"id"`
CustomerID string `json:"customer_id"`
Email string `json:"email"`
OrderID string `json:"order_id"`
OrderNumber string `json:"order_number"`
ProductID string `json:"product_id"`
ProductName string `json:"product_name"`
ServerID string `json:"server_id"`
ServerName string `json:"server_name"`
PlanCode string `json:"plan_code"`
ExternalID string `json:"external_id"`
Status string `json:"status"`
StartsAt string `json:"starts_at"`
EndsAt string `json:"ends_at"`
LastSyncAt string `json:"last_sync_at"`
Meta map[string]any `json:"meta"`
CreatedAt string `json:"created_at"`
}
Entitlement is a customer's access to a plan on a billing server, created by exactly one order.
type IntakeField ¶
type Invoice ¶ added in v0.12.0
type Invoice struct {
ID string `json:"id"`
StripeInvoiceID string `json:"stripe_invoice_id"`
HostedInvoiceURL string `json:"hosted_invoice_url"`
PDFURL string `json:"pdf_url"`
Status string `json:"status"`
AmountMinor int64 `json:"amount_minor"`
Currency string `json:"currency"`
CreatedAt string `json:"created_at"`
}
Invoice is one Stripe invoice stored for /account.
type ListQuery ¶
ListQuery filters Orders and Entitlements. Search matches the email or order number; Status filters exactly. Page/PerPage default 1/20 (max 100).
type MCBBError ¶
MCBBError is a failed billing-server call. Status is the HTTP status (0 for transport failures). Retryable reports transient failures (transport, 408, 429, 5xx), mirroring the PHP client's retry rule.
type Module ¶
type Module struct {
// contains filtered or unexported fields
}
Module is the commerce kernel.Module.
type Order ¶
type Order struct {
ReceiptStatus string `json:"receipt_status,omitempty"`
ReceiptError string `json:"receipt_error,omitempty"`
ReceiptSentAt string `json:"receipt_sent_at,omitempty"`
RequestStatus string `json:"request_status"`
FulfillmentNote string `json:"fulfillment_note"`
ID string `json:"id"`
Number string `json:"number"`
CustomerID string `json:"customer_id"`
Email string `json:"email"`
Status string `json:"status"`
Currency string `json:"currency"`
TotalMinor int64 `json:"total_minor"`
ProductID string `json:"product_id"`
ProductName string `json:"product_name"`
ProductSnapshot map[string]any `json:"product_snapshot"`
StripeSessionID string `json:"stripe_session_id"`
StripePaymentIntent string `json:"stripe_payment_intent"`
PaidAt string `json:"paid_at"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
Order freezes a single Stripe product or the line items of a manual request.
type OrderItem ¶
type OrderItem struct {
Intake map[string]string `json:"intake,omitempty"`
IntakeSchema []IntakeField `json:"intake_schema,omitempty"`
ID string `json:"id"`
ProductID string `json:"product_id"`
Quantity int `json:"quantity"`
UnitMinor int64 `json:"unit_minor"`
ProductName string `json:"product_name"`
Kind string `json:"kind"`
DownloadURL string `json:"download_url,omitempty"`
}
type Plan ¶
type Plan struct {
Code string `json:"code"`
Name string `json:"name"`
NameAr string `json:"name_ar,omitempty"`
}
Plan is one plan advertised by a billing server's GET /catalog.
type Product ¶
type Product struct {
Intake []IntakeField `json:"intake,omitempty"`
Kind string `json:"kind"`
DigitalFile string `json:"digital_file,omitempty"`
DownloadDays int `json:"download_days"`
BillingMode string `json:"billing_mode,omitempty"`
StripePriceID string `json:"stripe_price_id,omitempty"`
Interval string `json:"interval,omitempty"`
TrialDays int `json:"trial_days,omitempty"`
Prices map[string]CurrencyPrice `json:"prices,omitempty"`
ID string `json:"id"`
Slug string `json:"slug"`
Name string `json:"name"`
Description string `json:"description"`
ShortDescription string `json:"short_description"`
PriceMinor int64 `json:"price_minor"`
Currency string `json:"currency"`
Active bool `json:"active"`
GroupSlug string `json:"group_slug"`
GroupName string `json:"group_name"`
PlanCode string `json:"plan_code"`
ServerID string `json:"server_id"`
AccessMonths int `json:"access_months"`
Features []string `json:"features"`
ImageMediaID string `json:"image_media_id"`
Sort int `json:"sort"`
SEO map[string]any `json:"seo"`
WPProductID string `json:"wp_product_id"`
}
type ProductGroup ¶
ProductGroup is a shop section: active products sharing GroupSlug.
type RequestDetail ¶
type RequestUpdate ¶
type Server ¶
type Server struct {
ID string `json:"id"`
Name string `json:"name"`
BaseURL string `json:"base_url"`
ClientID string `json:"client_id"`
Secret string `json:"secret,omitempty"`
SecretSet bool `json:"secret_set"`
Protocol string `json:"protocol"`
Status string `json:"status"`
LastCheckAt string `json:"last_check_at"`
LastError string `json:"last_error"`
}
Server is a billing server speaking the mcp-billing/v1 protocol. Secret is write-only: SaveServer encrypts it when non-empty (empty keeps the stored secret) and reads never return it; SecretSet reports whether one exists.
type ServerTestResponse ¶
type ServerTestResponse struct {
OK bool `json:"ok"`
Error string `json:"error,omitempty"`
Catalog Catalog `json:"catalog"`
}
ServerTestResponse is returned by POST /v1/commerce/servers/{id}/test.
type Service ¶
type Service interface {
Products(ctx context.Context, activeOnly bool) ([]Product, error)
Product(ctx context.Context, slug string) (*Product, error)
SaveProduct(ctx context.Context, p Product) (*Product, error)
DeleteProduct(ctx context.Context, id string) error
UpsertFromWP(ctx context.Context, wp WPProduct) (*Product, error)
// ReplaceMediaRef re-points every product image from media oldID to
// newID (the migrator replaced a re-imported file).
ReplaceMediaRef(ctx context.Context, oldID, newID string) error
SubmitCart(ctx context.Context, request CartCheckout) (*Order, error)
UpdateRequest(ctx context.Context, id string, request RequestUpdate) (*Order, error)
StartCheckout(ctx context.Context, productID, email string) (redirectURL string, orderID string, err error)
HandleStripeEvent(ctx context.Context, payload []byte, sigHeader string) error
Orders(ctx context.Context, q ListQuery) ([]Order, int, error)
Entitlements(ctx context.Context, q ListQuery) ([]Entitlement, int, error)
CustomerEntitlements(ctx context.Context, userID string) ([]Entitlement, error)
Suspend(ctx context.Context, entitlementID string) error
Resume(ctx context.Context, entitlementID string) error
Reconcile(ctx context.Context, entitlementID string) error
LoginLink(ctx context.Context, entitlementID string) (string, error)
// RequirePlan allows the call when accountID has an on or in-grace
// subscription for plan (empty plan: any such subscription).
RequirePlan(ctx context.Context, accountID, plan string) error
Servers(ctx context.Context) ([]Server, error)
SaveServer(ctx context.Context, s Server) error
TestServer(ctx context.Context, id string) (Catalog, error)
}
Service is the commerce API published as kernel.ServiceCommerce.
type SubscriptionEvent ¶ added in v0.12.0
type SubscriptionEvent struct {
SubscriptionID string `json:"subscription_id"`
StripeSubscriptionID string `json:"stripe_subscription_id"`
CustomerID string `json:"customer_id"`
AccountID string `json:"account_id"`
Plan string `json:"plan"`
SiteID string `json:"site_id"`
Status string `json:"status"`
PriceID string `json:"price_id"`
CurrentPeriodEnd string `json:"current_period_end"`
GraceUntil string `json:"grace_until,omitempty"`
Reason string `json:"reason,omitempty"`
}
SubscriptionEvent is emitted on subscription.activated, subscription.past_due and subscription.canceled so other modules and webhook subscribers can react without talking to Stripe.
type ValidationError ¶
ValidationError carries per-field i18n keys (implements api.FieldErrorer).
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
func (*ValidationError) FieldErrors ¶
func (e *ValidationError) FieldErrors() map[string]string
FieldErrors implements api.FieldErrorer.
type WPProduct ¶
type WPProduct struct {
ID int
Slug, Name, Description, ShortDescription string
PriceMinor int64
Currency string
Categories []string
ImageURLs []string
Meta map[string]string
}
WPProduct is a WooCommerce catalog product as read by the migrator (its adapter maps an identical struct 1:1). Meta holds WooCommerce meta_data (e.g. _mcbb_server_id, _mcbb_plan_code, _mcbb_months).
Source Files
¶
- account.go
- account_password.go
- account_redirect.go
- account_registration.go
- admin_entitlements.go
- admin_orders.go
- admin_products.go
- admin_servers.go
- admin_settings.go
- admin_setup.go
- api.go
- cart.go
- checkout.go
- contract.go
- customers.go
- digital.go
- entitlements.go
- example_products.go
- fragments.go
- health.go
- intake.go
- mail.go
- mcbb_client.go
- module.go
- orders.go
- products.go
- provisioning.go
- receipts.go
- refund.go
- requests.go
- servers.go
- service.go
- stripe.go
- subscriptions.go
- theme_funcs.go
- webhooks.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package fakebilling is an in-memory billing server implementing the mcp-billing/v1 protocol (see docs/COMMERCE.md) for tests and local e2e runs: signature verification (same scheme as the real servers), Idempotency-Key replay on mutations, and failure injection.
|
Package fakebilling is an in-memory billing server implementing the mcp-billing/v1 protocol (see docs/COMMERCE.md) for tests and local e2e runs: signature verification (same scheme as the real servers), Idempotency-Key replay on mutations, and failure injection. |