Community edition generated from private repo via sync pipeline. Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~587 tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
496 lines
20 KiB
Python
496 lines
20 KiB
Python
"""Coupons Handler - manages WooCommerce coupons"""
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from plugins.wordpress.client import WordPressClient
|
|
|
|
def get_tool_specifications() -> list[dict[str, Any]]:
|
|
"""Return tool specifications for ToolGenerator"""
|
|
return [
|
|
{
|
|
"name": "list_coupons",
|
|
"method_name": "list_coupons",
|
|
"description": "List WooCommerce coupons. Returns paginated coupon list with discount details and usage restrictions.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"per_page": {
|
|
"type": "integer",
|
|
"description": "Number of coupons per page (1-100)",
|
|
"default": 10,
|
|
"minimum": 1,
|
|
"maximum": 100,
|
|
},
|
|
"page": {
|
|
"type": "integer",
|
|
"description": "Page number",
|
|
"default": 1,
|
|
"minimum": 1,
|
|
},
|
|
"search": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Search term to filter coupons by code",
|
|
},
|
|
},
|
|
},
|
|
"scope": "read",
|
|
},
|
|
{
|
|
"name": "create_coupon",
|
|
"method_name": "create_coupon",
|
|
"description": "Create a new WooCommerce coupon. Supports percentage and fixed discounts with usage limits and restrictions.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"code": {
|
|
"type": "string",
|
|
"description": "Coupon code (e.g., 'SAVE20')",
|
|
"minLength": 1,
|
|
},
|
|
"amount": {
|
|
"type": "string",
|
|
"description": "Discount amount (e.g., '20' for 20% or $20)",
|
|
},
|
|
"discount_type": {
|
|
"type": "string",
|
|
"description": "Type of discount",
|
|
"enum": ["percent", "fixed_cart", "fixed_product"],
|
|
"default": "percent",
|
|
},
|
|
"description": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Coupon description (internal note)",
|
|
},
|
|
"date_expires": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Expiration date in ISO 8601 format (e.g., '2024-12-31T23:59:59')",
|
|
},
|
|
"minimum_amount": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Minimum order amount required to use coupon",
|
|
},
|
|
"maximum_amount": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Maximum order amount allowed to use coupon",
|
|
},
|
|
"individual_use": {
|
|
"type": "boolean",
|
|
"description": "If true, coupon cannot be combined with other coupons",
|
|
"default": False,
|
|
},
|
|
"product_ids": {
|
|
"anyOf": [
|
|
{"type": "array", "items": {"type": "integer"}},
|
|
{"type": "null"},
|
|
],
|
|
"description": "Array of product IDs coupon applies to",
|
|
},
|
|
"excluded_product_ids": {
|
|
"anyOf": [
|
|
{"type": "array", "items": {"type": "integer"}},
|
|
{"type": "null"},
|
|
],
|
|
"description": "Array of product IDs coupon does NOT apply to",
|
|
},
|
|
"usage_limit": {
|
|
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
|
"description": "Maximum number of times coupon can be used",
|
|
},
|
|
"usage_limit_per_user": {
|
|
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
|
"description": "Maximum number of times coupon can be used per user",
|
|
},
|
|
"limit_usage_to_x_items": {
|
|
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
|
"description": "Maximum number of items coupon applies to",
|
|
},
|
|
"free_shipping": {
|
|
"type": "boolean",
|
|
"description": "If true, grants free shipping",
|
|
"default": False,
|
|
},
|
|
},
|
|
"required": ["code", "amount"],
|
|
},
|
|
"scope": "write",
|
|
},
|
|
{
|
|
"name": "update_coupon",
|
|
"method_name": "update_coupon",
|
|
"description": "Update an existing WooCommerce coupon. Can update discount amount, restrictions, and expiration.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"coupon_id": {
|
|
"type": "integer",
|
|
"description": "Coupon ID to update",
|
|
"minimum": 1,
|
|
},
|
|
"code": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Coupon code (e.g., 'SAVE20')",
|
|
},
|
|
"discount_type": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Type of discount",
|
|
"enum": ["percent", "fixed_cart", "fixed_product"],
|
|
},
|
|
"amount": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Discount amount",
|
|
},
|
|
"description": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Coupon description (internal note)",
|
|
},
|
|
"date_expires": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Expiration date in ISO 8601 format",
|
|
},
|
|
"minimum_amount": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Minimum order amount",
|
|
},
|
|
"maximum_amount": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Maximum order amount",
|
|
},
|
|
"individual_use": {
|
|
"anyOf": [{"type": "boolean"}, {"type": "null"}],
|
|
"description": "If true, coupon cannot be combined with other coupons",
|
|
},
|
|
"product_ids": {
|
|
"anyOf": [
|
|
{"type": "array", "items": {"type": "integer"}},
|
|
{"type": "null"},
|
|
],
|
|
"description": "Array of product IDs coupon applies to",
|
|
},
|
|
"excluded_product_ids": {
|
|
"anyOf": [
|
|
{"type": "array", "items": {"type": "integer"}},
|
|
{"type": "null"},
|
|
],
|
|
"description": "Array of product IDs coupon does NOT apply to",
|
|
},
|
|
"usage_limit": {
|
|
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
|
"description": "Maximum number of uses",
|
|
},
|
|
"usage_limit_per_user": {
|
|
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
|
"description": "Maximum uses per user",
|
|
},
|
|
"limit_usage_to_x_items": {
|
|
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
|
"description": "Maximum number of items coupon applies to",
|
|
},
|
|
"free_shipping": {
|
|
"anyOf": [{"type": "boolean"}, {"type": "null"}],
|
|
"description": "If true, grants free shipping",
|
|
},
|
|
},
|
|
"required": ["coupon_id"],
|
|
},
|
|
"scope": "write",
|
|
},
|
|
{
|
|
"name": "delete_coupon",
|
|
"method_name": "delete_coupon",
|
|
"description": "Delete a WooCommerce coupon. Can force delete or move to trash.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"coupon_id": {
|
|
"type": "integer",
|
|
"description": "Coupon ID to delete",
|
|
"minimum": 1,
|
|
},
|
|
"force": {
|
|
"type": "boolean",
|
|
"description": "Force permanent delete (bypass trash)",
|
|
"default": False,
|
|
},
|
|
},
|
|
"required": ["coupon_id"],
|
|
},
|
|
"scope": "write",
|
|
},
|
|
]
|
|
|
|
class CouponsHandler:
|
|
"""Handle coupon-related operations for WooCommerce"""
|
|
|
|
def __init__(self, client: WordPressClient):
|
|
"""
|
|
Initialize coupons handler.
|
|
|
|
Args:
|
|
client: WordPress API client instance
|
|
"""
|
|
self.client = client
|
|
|
|
async def list_coupons(
|
|
self, per_page: int = 10, page: int = 1, search: str | None = None
|
|
) -> str:
|
|
"""
|
|
List WooCommerce coupons.
|
|
|
|
Args:
|
|
per_page: Number of coupons per page (1-100)
|
|
page: Page number
|
|
search: Search term to filter coupons by code
|
|
|
|
Returns:
|
|
JSON string with coupons list
|
|
"""
|
|
try:
|
|
params = {"per_page": per_page, "page": page}
|
|
if search:
|
|
params["search"] = search
|
|
|
|
coupons = await self.client.get("coupons", params=params, use_woocommerce=True)
|
|
|
|
result = {
|
|
"total": len(coupons),
|
|
"page": page,
|
|
"per_page": per_page,
|
|
"coupons": [
|
|
{
|
|
"id": coupon["id"],
|
|
"code": coupon["code"],
|
|
"discount_type": coupon["discount_type"],
|
|
"amount": coupon["amount"],
|
|
"description": coupon.get("description", ""),
|
|
"date_expires": coupon.get("date_expires"),
|
|
"usage_count": coupon.get("usage_count", 0),
|
|
"usage_limit": coupon.get("usage_limit"),
|
|
"individual_use": coupon.get("individual_use", False),
|
|
"free_shipping": coupon.get("free_shipping", False),
|
|
"minimum_amount": coupon.get("minimum_amount", "0"),
|
|
"maximum_amount": coupon.get("maximum_amount", "0"),
|
|
}
|
|
for coupon in coupons
|
|
],
|
|
}
|
|
|
|
return json.dumps(result, indent=2)
|
|
except Exception as e:
|
|
return json.dumps(
|
|
{"error": str(e), "message": f"Failed to list coupons: {str(e)}"}, indent=2
|
|
)
|
|
|
|
async def create_coupon(
|
|
self,
|
|
code: str,
|
|
amount: str,
|
|
discount_type: str = "percent",
|
|
description: str | None = None,
|
|
date_expires: str | None = None,
|
|
minimum_amount: str | None = None,
|
|
maximum_amount: str | None = None,
|
|
individual_use: bool = False,
|
|
product_ids: list[int] | None = None,
|
|
excluded_product_ids: list[int] | None = None,
|
|
usage_limit: int | None = None,
|
|
usage_limit_per_user: int | None = None,
|
|
limit_usage_to_x_items: int | None = None,
|
|
free_shipping: bool = False,
|
|
) -> str:
|
|
"""
|
|
Create a new WooCommerce coupon.
|
|
|
|
Args:
|
|
code: Coupon code (e.g., 'SAVE20')
|
|
amount: Discount amount (e.g., '20' for 20% or $20)
|
|
discount_type: Type of discount (percent, fixed_cart, fixed_product)
|
|
description: Coupon description (internal note)
|
|
date_expires: Expiration date in ISO 8601 format
|
|
minimum_amount: Minimum order amount required
|
|
maximum_amount: Maximum order amount allowed
|
|
individual_use: If true, coupon cannot be combined with others
|
|
product_ids: Product IDs coupon applies to
|
|
excluded_product_ids: Product IDs coupon does NOT apply to
|
|
usage_limit: Maximum number of times coupon can be used
|
|
usage_limit_per_user: Maximum uses per user
|
|
limit_usage_to_x_items: Maximum number of items coupon applies to
|
|
free_shipping: If true, grants free shipping
|
|
|
|
Returns:
|
|
JSON string with created coupon data
|
|
"""
|
|
try:
|
|
data = {
|
|
"code": code,
|
|
"discount_type": discount_type,
|
|
"amount": amount,
|
|
"individual_use": individual_use,
|
|
"free_shipping": free_shipping,
|
|
}
|
|
|
|
# Add optional fields
|
|
if description:
|
|
data["description"] = description
|
|
if date_expires:
|
|
data["date_expires"] = date_expires
|
|
if minimum_amount:
|
|
data["minimum_amount"] = minimum_amount
|
|
if maximum_amount:
|
|
data["maximum_amount"] = maximum_amount
|
|
if product_ids:
|
|
data["product_ids"] = product_ids
|
|
if excluded_product_ids:
|
|
data["excluded_product_ids"] = excluded_product_ids
|
|
if usage_limit:
|
|
data["usage_limit"] = usage_limit
|
|
if usage_limit_per_user:
|
|
data["usage_limit_per_user"] = usage_limit_per_user
|
|
if limit_usage_to_x_items:
|
|
data["limit_usage_to_x_items"] = limit_usage_to_x_items
|
|
|
|
coupon = await self.client.post("coupons", json_data=data, use_woocommerce=True)
|
|
|
|
result = {
|
|
"id": coupon["id"],
|
|
"code": coupon["code"],
|
|
"discount_type": coupon["discount_type"],
|
|
"amount": coupon["amount"],
|
|
"date_expires": coupon.get("date_expires"),
|
|
"message": f"Coupon '{code}' created successfully with ID {coupon['id']}",
|
|
}
|
|
|
|
return json.dumps(result, indent=2)
|
|
except Exception as e:
|
|
return json.dumps(
|
|
{"error": str(e), "message": f"Failed to create coupon: {str(e)}"}, indent=2
|
|
)
|
|
|
|
async def update_coupon(
|
|
self,
|
|
coupon_id: int,
|
|
code: str | None = None,
|
|
discount_type: str | None = None,
|
|
amount: str | None = None,
|
|
description: str | None = None,
|
|
date_expires: str | None = None,
|
|
minimum_amount: str | None = None,
|
|
maximum_amount: str | None = None,
|
|
individual_use: bool | None = None,
|
|
product_ids: list[int] | None = None,
|
|
excluded_product_ids: list[int] | None = None,
|
|
usage_limit: int | None = None,
|
|
usage_limit_per_user: int | None = None,
|
|
limit_usage_to_x_items: int | None = None,
|
|
free_shipping: bool | None = None,
|
|
) -> str:
|
|
"""
|
|
Update an existing WooCommerce coupon.
|
|
|
|
Args:
|
|
coupon_id: Coupon ID to update
|
|
code: Coupon code
|
|
discount_type: Type of discount
|
|
amount: Discount amount
|
|
description: Coupon description
|
|
date_expires: Expiration date in ISO 8601 format
|
|
minimum_amount: Minimum order amount
|
|
maximum_amount: Maximum order amount
|
|
individual_use: If true, coupon cannot be combined with others
|
|
product_ids: Product IDs coupon applies to
|
|
excluded_product_ids: Product IDs coupon does NOT apply to
|
|
usage_limit: Maximum number of uses
|
|
usage_limit_per_user: Maximum uses per user
|
|
limit_usage_to_x_items: Maximum number of items coupon applies to
|
|
free_shipping: If true, grants free shipping
|
|
|
|
Returns:
|
|
JSON string with updated coupon data
|
|
"""
|
|
try:
|
|
# Build data dict with only provided values
|
|
data = {}
|
|
if code is not None:
|
|
data["code"] = code
|
|
if discount_type is not None:
|
|
data["discount_type"] = discount_type
|
|
if amount is not None:
|
|
data["amount"] = amount
|
|
if description is not None:
|
|
data["description"] = description
|
|
if date_expires is not None:
|
|
data["date_expires"] = date_expires
|
|
if minimum_amount is not None:
|
|
data["minimum_amount"] = minimum_amount
|
|
if maximum_amount is not None:
|
|
data["maximum_amount"] = maximum_amount
|
|
if individual_use is not None:
|
|
data["individual_use"] = individual_use
|
|
if product_ids is not None:
|
|
data["product_ids"] = product_ids
|
|
if excluded_product_ids is not None:
|
|
data["excluded_product_ids"] = excluded_product_ids
|
|
if usage_limit is not None:
|
|
data["usage_limit"] = usage_limit
|
|
if usage_limit_per_user is not None:
|
|
data["usage_limit_per_user"] = usage_limit_per_user
|
|
if limit_usage_to_x_items is not None:
|
|
data["limit_usage_to_x_items"] = limit_usage_to_x_items
|
|
if free_shipping is not None:
|
|
data["free_shipping"] = free_shipping
|
|
|
|
if not data:
|
|
raise Exception("No update data provided")
|
|
|
|
coupon = await self.client.put(
|
|
f"coupons/{coupon_id}", json_data=data, use_woocommerce=True
|
|
)
|
|
|
|
result = {
|
|
"id": coupon["id"],
|
|
"code": coupon["code"],
|
|
"discount_type": coupon["discount_type"],
|
|
"amount": coupon["amount"],
|
|
"message": f"Coupon ID {coupon_id} updated successfully",
|
|
}
|
|
|
|
return json.dumps(result, indent=2)
|
|
except Exception as e:
|
|
return json.dumps(
|
|
{"error": str(e), "message": f"Failed to update coupon {coupon_id}: {str(e)}"},
|
|
indent=2,
|
|
)
|
|
|
|
async def delete_coupon(self, coupon_id: int, force: bool = False) -> str:
|
|
"""
|
|
Delete a WooCommerce coupon.
|
|
|
|
Args:
|
|
coupon_id: Coupon ID to delete
|
|
force: Force permanent delete (True) or move to trash (False)
|
|
|
|
Returns:
|
|
JSON string with deletion result
|
|
"""
|
|
try:
|
|
params = {"force": "true" if force else "false"}
|
|
result = await self.client.delete(
|
|
f"coupons/{coupon_id}", params=params, use_woocommerce=True
|
|
)
|
|
|
|
action = "permanently deleted" if force else "moved to trash"
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"coupon_id": coupon_id,
|
|
"message": f"Coupon {action} successfully",
|
|
"result": result,
|
|
},
|
|
indent=2,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps(
|
|
{"error": str(e), "message": f"Failed to delete coupon {coupon_id}: {str(e)}"},
|
|
indent=2,
|
|
)
|