Ai knowledge and logicHelpers

WooCommerce Subscriptions subscription helpers

Look up, cancel and reschedule WooCommerce Subscriptions subscriptions from Python, returning the raw WooCommerce Subscriptions subscription.

Plain helpers for the common WooCommerce Subscriptions subscription tasks. They read the business's WooCommerce Subscriptions connection with get_integration_credentials, call the WooCommerce Subscriptions REST API and return subscriptions as WooCommerce Subscriptions returns them; see the WooCommerce Subscriptions API reference for every field. Like the order helpers, they leave out the customer's IP address and browser, the order key and payment URL, and tracking and payment-gateway meta. They raise ValueError if WooCommerce Subscriptions isn't connected and requests.HTTPError if WooCommerce Subscriptions rejects the request.

HelperWhat it does
woocommerce_get_subscription(context, subscription_id)The subscription, or None.
woocommerce_find_subscriptions(context, email=None, phone=None)The subscriptions whose billing email is exactly email.
woocommerce_cancel_subscription(context, subscription_id)Sets the subscription to cancelled.
woocommerce_next_charge_date(subscription)The next renewal as a UTC datetime, or None.
woocommerce_set_next_charge_date(context, subscription_id, when)Moves the next renewal to when.

Businesses moved off the built-in subscription actions get default actions with the built-in names (getSubscriptionById, getSubscriptionByEmail, cancelSubscription, skipSubscriptionMonths, ...) that call these helpers. They are ordinary Python actions you can read and change.

The full source is below. Copy it into your own action when you need something it doesn't do.


woocommerce_subscription_widget(context, cancel_action="cancel_subscription") returns a ready-to-render subscription panel with confirmation buttons. Pair it with woocommerce_cancel_widget_subscription(context) in a widget-owned action. Setup, business scoping and shared source.

Source

from datetime import datetime, timezone

import requests


def woocommerce_get_subscription(context, subscription_id):
    """The WooCommerce Subscriptions subscription with this ID, or None."""
    subscription_id = str(subscription_id).strip().lstrip("#")
    if not subscription_id.isdigit():
        return None
    subscription = _woocommerce_get(_woocommerce_store(context), f"subscriptions/{subscription_id}")
    # Subscriptions are orders: the same customer IP, order key and payment URL are left out.
    return _woocommerce_clean_order(subscription) if subscription else None


def woocommerce_find_subscriptions(context, email=None, phone=None):
    """The customer's subscriptions with this billing email."""
    if not email:
        return []
    email = email.strip().lower()
    hits = _woocommerce_get(_woocommerce_store(context), "subscriptions", {"search": email}) or []
    return [
        _woocommerce_clean_order(s) for s in hits
        if ((s.get("billing") or {}).get("email") or "").strip().lower() == email
    ]


def _woocommerce_update_subscription(context, subscription_id, changes):
    store = _woocommerce_store(context)
    response = requests.put(
        f"https://{store['domain']}/wp-json/wc/v3/subscriptions/{subscription_id}",
        auth=(store["consumerKey"], store["consumerSecret"]),
        headers={"User-Agent": "octocom"},
        json=changes,
        timeout=20,
    )
    response.raise_for_status()


def woocommerce_cancel_subscription(context, subscription_id):
    _woocommerce_update_subscription(context, subscription_id, {"status": "cancelled"})


def woocommerce_subscription_widget(context, cancel_action="cancel_subscription"):
    """Sidebar data for the current customer's WooCommerce subscriptions, with cancel buttons."""
    _, email = _subscription_widget_identity(context)
    items = []
    for sub in woocommerce_find_subscriptions(context, email=email) if email else []:
        lines = sub.get("line_items") or []
        currency = sub.get("currency") or ""
        date = woocommerce_next_charge_date(sub)
        items.append(_subscription_widget_item(
            context, sub["id"], (lines[0].get("name") if lines else None) or "Subscription",
            sub.get("status"), {
                "Total": _subscription_widget_value(sub.get("total"), currency),
                "Next charge": date.strftime("%Y-%m-%d UTC") if date else None,
                "Billing": _subscription_widget_value(sub.get("billing_interval"), sub.get("billing_period")),
            }, [{"title": str(line.get("name") or "Product"), "fields": {
                "Quantity": line.get("quantity"), "SKU": line.get("sku"),
                "Total": _subscription_widget_value(line.get("total"), currency),
            }} for line in lines], cancel_action,
        ))
    return {"title": "Subscriptions", "items": items}


def woocommerce_cancel_widget_subscription(context):
    """Action for woocommerce_subscription_widget; validates the current customer before cancelling."""
    return _subscription_widget_cancel(context, woocommerce_find_subscriptions, woocommerce_cancel_subscription)


def woocommerce_next_charge_date(subscription):
    """When the subscription next renews (UTC), or None."""
    value = subscription.get("next_payment_date_gmt")
    return datetime.fromisoformat(value.replace("Z", "")).replace(tzinfo=timezone.utc) if value else None


def woocommerce_set_next_charge_date(context, subscription_id, when):
    _woocommerce_update_subscription(
        context, subscription_id, {"next_payment_date_gmt": when.strftime("%Y-%m-%dT%H:%M:%S")}
    )

On this page