Skill: zero2ai-hub/skill-woocommerce-order-guard (version 1.0.0)

# skill-woocommerce-order-guard ## Description Watches WooCommerce for new 'processing' orders and auto-fixes missing shipping addresses by copying billing → shipping. Deduplicates alerts so each new order triggers exactly once. Designed to run as a cron heartbeat or webhook trigger. ## Use case WooCommerce sometimes receives orders where customers skip the shipping address form. This script ensures every processing order has a valid shipping address before fulfillment, and emits a signal for downstream automation (Telegram alert, CJ fulfillment, etc.) ## Usage ```bash python3 scripts/order-guard.py ``` Optional args: ```bash python3 scripts/order-guard.py \ --creds /path/to/woo-api.json \ --storage /path/to/fulfilled_orders.json ``` ## Output - `HEARTBEAT_OK` — no new orders - `NEW_ORDER_ID: <id>` — one line per new order (pipe to Telegram alert, CJ submit, etc.) ## Configuration ### `woo-api.json` ```json { "url": "https://yourstore.com", "consumerKey": "ck_...", "consumerSecret": "cs_..." } ``` Generate keys: WooCommerce → Settings → Advanced → REST API. ### Storage file Local JSON at `--storage` path (default: `~/.openclaw/workspace/memory/fulfilled_orders.json`). ```json {"alerted_orders": [12345, 12346]} ``` Prevents duplicate alerts across runs. ## Example cron (every 5 min) ``` */5 * * * * python3 /path/to/skill-woocommerce-order-guard/scripts/order-guard.py >> /tmp/order-guard.log 2>&1 ``` ## Dependencies - Python 3.x - `requests` library (`pip install requests`) ## Logic flow 1. Fetch all `processing` orders (last 20) 2. Filter out already-alerted order IDs 3. For each new order: if shipping.address_1 is empty → PUT billing address to shipping 4. Print `NEW_ORDER_ID: <id>` and save to dedup store

path: scripts/order-guard.py
content: #!/usr/bin/env python3
"""
WooCommerce Order Guard
- Fetches all 'processing' orders
- Copies billing address → shipping when shipping address is empty
- Deduplicates alerts via a local JSON store
- Prints NEW_ORDER_ID: <id> for each new order (for cron/webhook upstream)
- Prints HEARTBEAT_OK if no new orders

Usage:
  python3 order-guard.py [--creds /path/to/woo-api.json] [--storage /path/to/fulfilled_orders.json]
"""

import requests
import json
import os
import argparse

DEFAULT_CREDS = os.path.expanduser("~/woo-api.json")
DEFAULT_STORAGE = os.path.expanduser("~/.openclaw/workspace/memory/fulfilled_orders.json")


def load_creds(path):
    with open(path) as f:
        return json.load(f)


def load_storage(path):
    if os.path.exists(path):
        with open(path) as f:
            return json.load(f).get("alerted_orders", [])
    return []


def save_storage(path, alerted_orders):
    with open(path, 'w') as f:
        json.dump({"alerted_orders": alerted_orders}, f)


def copy_billing_to_shipping(order):
    billing = order.get('billing', {})
    return {
        "first_name": billing.get('first_name'),
        "last_name": billing.get('last_name'),
        "company": billing.get('company'),
        "address_1": billing.get('address_1'),
        "address_2": billing.get('address_2'),
        "city": billing.get('city'),
        "state": billing.get('state'),
        "postcode": billing.get('postcode'),
        "country": billing.get('country'),
    }


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--creds', default=DEFAULT_CREDS)
    parser.add_argument('--storage', default=DEFAULT_STORAGE)
    args = parser.parse_args()

    creds = load_creds(args.creds)
    url = creds['url']
    auth = (creds['consumerKey'], creds['consumerSecret'])
    alerted_orders = load_storage(args.storage)

    resp = requests.get(f"{url}/wp-json/wc/v3/orders?status=processing&per_page=20", auth=auth)
    resp.raise_for_status()
    orders = resp.json()

    new_orders = [o for o in orders if o['id'] not in alerted_orders]

    if not new_orders:
        print("HEARTBEAT_OK")
        return

    for order in new_orders:
        order_id = order['id']
        shipping = order.get('shipping', {})

        if not shipping.get('address_1'):
            update_data = {"shipping": copy_billing_to_shipping(order)}
            requests.put(f"{url}/wp-json/wc/v3/orders/{order_id}", auth=auth, json=update_data)

        alerted_orders.append(order_id)
        print(f"NEW_ORDER_ID: {order_id}")

    save_storage(args.storage, alerted_orders)


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)