| @@ -30,14 +30,15 @@ | ||
| 30 | 30 | { |
| 31 | 31 | return [ |
| 32 | 32 | 'fluent-cart/list-coupons' => [ |
| 33 | 33 | 'label' => __('List Coupons', 'fluent-cart'), |
| 34 | - 'description' => __('Find and filter coupons with usage counts and validity windows. Interpret amount via type: percentage means a percent (10 = 10 percent), fixed means a currency value. Use active_now to get only coupons usable today.', 'fluent-cart'), | |
| 34 | + 'description' => __('Find and filter coupons with usage counts (times_used) and validity windows. Filter by status, by code substring, or by type; paginate with page/per_page. Interpret amount via type: percentage means a percent (10 = 10 percent), fixed means a currency value. Use active_now to get only coupons usable today (status active and within the start/end window — i.e. not expired). status inactive means disabled.', 'fluent-cart'), | |
| 35 | 35 | 'input_schema' => [ |
| 36 | 36 | 'type' => 'object', |
| 37 | 37 | 'properties' => [ |
| 38 | 38 | 'search' => ['type' => 'string', 'description' => 'Matches coupon code or title.'], |
| 39 | - 'status' => ['type' => 'string', 'enum' => ['active', 'inactive']], | |
| 39 | + 'code' => ['type' => 'string', 'description' => 'Matches the coupon code only (substring). Narrower than search.'], | |
| 40 | + 'status' => ['type' => 'string', 'enum' => ['active', 'inactive'], 'description' => 'inactive = disabled. For "expired", use active_now=false / read valid_now on each row.'], | |
| 40 | 41 | 'type' => ['type' => 'string', 'enum' => ['fixed', 'percentage']], |
| 41 | 42 | 'active_now' => ['type' => 'boolean', 'description' => 'Only coupons that are active and within their start/end window right now.'], |
| 42 | 43 | 'sort_by' => ['type' => 'string', 'enum' => ['id', 'use_count', 'priority', 'end_date'], 'default' => 'id'], |
| 43 | 44 | 'sort_type' => ['type' => 'string', 'enum' => ['ASC', 'DESC'], 'default' => 'DESC'], |
| @@ -74,8 +75,12 @@ | ||
| 74 | 75 | 'execute_callback' => [self::class, 'manageCoupon'], |
| 75 | 76 | 'permission_callback' => function () { |
| 76 | 77 | return PermissionGate::can('coupons/manage'); |
| 77 | 78 | }, |
| 79 | + // Mutating; deactivate sets status inactive rather than deleting, | |
| 80 | + // so not destructive. create is not idempotent (a repeat makes a | |
| 81 | + // second coupon), so no idempotent hint on the dispatcher. | |
| 82 | + 'annotations' => ['readonly' => false, 'destructive' => false], | |
| 78 | 83 | ], |
| 79 | 84 | ]; |
| 80 | 85 | } |
| 81 | 86 | |
| @@ -254,8 +259,11 @@ | ||
| 254 | 259 | $query->where(function ($q) use ($like) { |
| 255 | 260 | $q->where('code', 'LIKE', $like)->orWhere('title', 'LIKE', $like); |
| 256 | 261 | }); |
| 257 | 262 | } |
| 263 | + if (!empty($params['code'])) { | |
| 264 | + $query->where('code', 'LIKE', '%' . sanitize_text_field($params['code']) . '%'); | |
| 265 | + } | |
| 258 | 266 | if (!empty($params['status'])) { |
| 259 | 267 | $query->where('status', sanitize_text_field($params['status'])); |
| 260 | 268 | } |
| 261 | 269 | if (!empty($params['type'])) { |
| @@ -308,8 +316,11 @@ | ||
| 308 | 316 | 'type' => $coupon->type, |
| 309 | 317 | 'amount' => self::couponAmount($coupon), |
| 310 | 318 | 'status' => $coupon->status, |
| 311 | 319 | 'use_count' => (int) $coupon->use_count, |
| 320 | + // times_used is the doc-facing alias of use_count — same value, kept so | |
| 321 | + // agents can read either name. | |
| 322 | + 'times_used' => (int) $coupon->use_count, | |
| 312 | 323 | 'stackable' => $coupon->stackable, |
| 313 | 324 | 'start_date' => MCPHelper::toIso8601($coupon->start_date), |
| 314 | 325 | 'end_date' => MCPHelper::toIso8601($coupon->end_date), |
| 315 | 326 | 'valid_now' => self::validNow($coupon, $now), |