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.
const ObservationKind = "commerce.billing_server"
ObservationKind is the background capability that reads each billing server's catalog. System Health reads the saved observation; it never calls a server while rendering.
const (
SettingSettingsVersion = "commerce.settings_version" // bootstrap steps applied to this store
)
Stripe mode settings. commerce.stripe_mode stays "test" | "live" and an absent value still means live (stripeMode); bootstrapStripeMode pins the value explicitly once per store so that rule is only ever a fallback.
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.
func (*Module) Enabled ¶ added in v0.16.0
Enabled implements kernel.OptionalModule. The store is on unless the operator turned it off (addons.commerce in the config, or the addons.commerce.enabled setting). Disabled, it registers no routes, jobs, theme kinds, admin pages or hooks; products, orders and entitlements stay in the database for when it is enabled again.
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"`
StripeMode string `` /* 136-byte string literal not displayed */
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
- stripe_mode.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. |