> ## Documentation Index
> Fetch the complete documentation index at: https://docs.subscribd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Bulk Operations

> Perform administrative billing operations across multiple subscriptions at once

# Bulk Operations

The `BulkOperations` service lets you perform administrative billing changes across many subscriptions at once. Use it for price increases, mass plan swaps, global coupon campaigns, and cleanup tasks.

## Available operations

| Operation             | What it does                                          |
| --------------------- | ----------------------------------------------------- |
| `swapPlans`           | Move a set of subscriptions to a new plan             |
| `cancelSubscriptions` | Cancel a set of subscriptions                         |
| `updatePrices`        | Apply a price override to a set of subscription items |
| `applyCoupons`        | Apply a coupon to a set of subscriptions              |

## Using the BulkOperations service

Inject or resolve the service and pass a query scope or collection:

```php theme={null}
use Pixelworxio\Subscribd\Support\BulkOperations;
use Pixelworxio\Subscribd\Models\Plan;
use Pixelworxio\Subscribd\Models\Subscription;

$operations = app(BulkOperations::class);

// Move all Legacy subscribers to the Pro plan
$legacyPlan = Plan::where('key', 'legacy')->firstOrFail();
$proPlan    = Plan::where('key', 'pro')->firstOrFail();

$operations->swapPlans(
    subscriptions: Subscription::wherePlanId($legacyPlan->id)->active(),
    newPlan: $proPlan,
    options: ['prorate' => 'none'],
);
```

### Swap plans

```php theme={null}
$operations->swapPlans(
    subscriptions: Subscription::query()->wherePlanId($oldPlan->id),
    newPlan: $newPlan,
    options: ['prorate' => 'renewal'],  // 'now' | 'renewal' | 'none'
);
```

### Cancel subscriptions

```php theme={null}
$operations->cancelSubscriptions(
    subscriptions: Subscription::query()
        ->pastDue()
        ->where('created_at', '<', now()->subMonths(3)),
    immediately: false,
);
```

### Update prices (bulk price override)

Apply a promotional price to a set of subscription items. Useful for grandfathered pricing — existing subscribers keep their old price while new subscribers pay the new rate.

```php theme={null}
use Carbon\CarbonImmutable;

$operations->updatePrices(
    subscriptions: Subscription::query()->wherePlanId($plan->id),
    planItemKey: 'projects',
    newPrice: 800,   // $8.00 per additional project (down from $10.00)
    expiresAt: null, // Permanent override
);

// Or time-limited
$operations->updatePrices(
    subscriptions: Subscription::query()->wherePlanId($plan->id),
    planItemKey: null,  // null = base plan price override
    newPrice: 3900,
    expiresAt: CarbonImmutable::parse('2026-12-31'),
);
```

### Apply coupons

```php theme={null}
use Pixelworxio\Subscribd\Models\Coupon;

$coupon = Coupon::where('code', 'LOYALTY20')->firstOrFail();

$operations->applyCoupons(
    subscriptions: Subscription::query()
        ->active()
        ->where('created_at', '<', now()->subYear()),
    coupon: $coupon,
);
```

## Artisan command

The `subscribd:bulk-operations` command reads a JSON file of operation definitions and executes them in sequence. Useful for deployment scripts and cron-driven operations.

```bash theme={null}
php artisan subscribd:bulk-operations --file=storage/bulk-ops.json
```

Operation file format:

```json theme={null}
[
  {
    "type": "swap_plans",
    "from_plan": "legacy",
    "to_plan": "pro",
    "options": { "prorate": "none" }
  },
  {
    "type": "apply_coupons",
    "coupon_code": "LOYALTY20",
    "filter": { "plan": "pro", "created_before": "2025-01-01" }
  }
]
```

## Admin Livewire component

The `admin.bulk-operations` Livewire component provides a UI for running bulk operations from the admin panel:

```blade theme={null}
<livewire:subscribd.admin.bulk-operations />
```

Features:

* Plan swap with plan picker and proration option
* Bulk cancel with immediately/grace-period toggle
* Price override with per-item targeting and expiry date
* Coupon application with code lookup
* Progress indicator for large batches
* Confirmation step before executing

For Filament users, this is available as a custom page registered by `SubscribdFilamentPlugin`.

## Error handling

Bulk operations apply changes one subscription at a time inside a transaction per subscription. A failure on one subscription is logged and skipped — the operation continues with the remaining subscriptions. Check your logs for `BulkOperation.failed` entries after a run.

To treat any failure as fatal (stop on first error), pass `stopOnError: true`:

```php theme={null}
$operations->swapPlans(
    subscriptions: $query,
    newPlan: $newPlan,
    stopOnError: true,
);
```

## Next steps

* **[Proration](/advanced/proration)** — How proration is calculated during plan swaps
* **[Coupons](/coupons/applying)** — Coupon validation rules
* **[Hooks and Events](/advanced/hooks-and-events)** — Events fired during bulk operations
