You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Invoices]: Reactivate a stopped recurring invoice #362
Story: As a company admin, I want to reactivate a stopped recurring invoice, so that I can resume billing without recreating the entire recurring schedule from scratch.
v2 context: The RecurringInvoice model has a recurring_invoice_status field (enum). In v1, the "stop" action set status to stopped but no "reactivate" action existed. In v2 the RecurringInvoicesTable action group needs a conditional action.
Acceptance Criteria:
A stopped recurring invoice shows an Activate action in the actions dropdown.
An active recurring invoice shows a Stop action (existing).
Activating a stopped recurring invoice sets recurring_invoice_status = 'active' and resumes the billing schedule from the next due date.
Stopping and re-activating does not generate back-dated invoices for the paused period.
Implementation:
Add Action::make('activate') in RecurringInvoicesTable (or wherever the Stop action lives), visible only when $record->recurring_invoice_status === 'stopped'.
RecurringInvoiceService::activate($record): set status to active, recalculate next_invoice_date from today + interval.
Hide the stop action when status is already stopped.
changed the title [-]Recurring invoice can't be activated after being "stopped"[/-][+][Invoices]: Reactivate a stopped recurring invoice[/+]on Jun 13, 2026
Added to support future implementation of this request. The issue body is unchanged.
RecurringInvoicesTable (Modules/Invoices/Filament/Company/Resources/RecurringInvoices/Tables/RecurringInvoicesTable.php) currently only exposes EditAction and DeleteAction inside an ActionGroup — there is no "stop"/"options" dropdown at all in v2 today. The reporter is describing v1 behavior ("options button only shows stop"); in the current codebase there isn't yet a stop action to reactivate from. RecurringInvoice only has start_at/end_at date columns — there's no boolean/status column (e.g. is_stopped) representing "stopped" vs. "active" at all, and Modules\Invoices\Services\RecurringInvoiceService is an empty stub, so there's no service-layer home for a reactivate() method either. This needs the stop/active concept designed and built (likely alongside #52's full recurring lifecycle) before "reactivate" has any meaning.
Edge cases worth covering: a recurring invoice whose end_at has already passed (does reactivating also require bumping end_at, or is that a separate step?), and reactivating a profile whose linked numbering scheme was deleted in the meantime.
Original report (preserved): Restarting a stopped recurring invoice should be an option. The options button only shows "stop" for stopped recurring invoices. Steps: Go to recurring invoices → options → stop. Tested with v1.6.2 and v1.7.0 beta.
v1 could stop a schedule (application/modules/invoices/controllers/Recurring.php:51 → Mdl_invoices_recurring::stop() sets recur_end_date = today, recur_next_date = NULL) but never restart it — this issue closes that hole in v2. Depends on the v2 Stop action ([Invoices]: Stop a recurring invoice) and the next_run_at column from the generation-engine issue (Epic #52).
Specific
Add a reactivate record action to Modules/Invoices/Filament/Company/Resources/RecurringInvoices/Tables/RecurringInvoicesTable.php, visible only for stopped schedules (next_run_at IS NULL). It opens a small form: new optional end_at (must be in the future), then recomputes next_run_at as the first frequency-step from the original start_at (or last last_run_at) that lands strictly after today, clears/updates end_at, and returns the schedule to "active".
Measurable
Stopped schedules show "Reactivate" and not "Stop"; active schedules show "Stop" and not "Reactivate".
After reactivation the schedule generates again on its next due date; no back-fill of the stopped period occurs.
Recomputed next_run_at is aligned to the original cadence, not simply "today".
Achievable
Single Filament action + one service method RecurringInvoiceService::reactivate(RecurringInvoice $r, ?Carbon $newEndAt); date walk uses the same frequency-increment helper as the engine.
Relevant
Stop is destructive-but-reversible in spirit (pause a subscription over a dispute, resume later); without reactivation users must delete and re-create the schedule, losing history. Epic #52 lists "Pausing stops generation without deleting history" as a requirement.
Time-Bound
Half a sprint, after Stop action and engine schema land; part of Epic #52.
Arrange
A monthly schedule started 3 months ago, stopped last month (end_at = stop date, next_run_at = NULL), with last_run_at set.
Act
Trigger the reactivate action with end_at = null; run the generation engine for today.
Assert
next_run_at equals the first monthly step after today on the original cadence; end_at is null.
Row shows status "active"; "Stop" action visible again, "Reactivate" hidden.
Engine run generates no invoice today (next_run_at is future) and exactly one on the recomputed date.
Reactivating with a past end_at is rejected with a validation error.
Activity
nielsdrost7 commentedon Jun 13, 2026
Planning Note — v2 Implementation
Story: As a company admin, I want to reactivate a stopped recurring invoice, so that I can resume billing without recreating the entire recurring schedule from scratch.
v2 context: The
RecurringInvoicemodel has arecurring_invoice_statusfield (enum). In v1, the "stop" action set status tostoppedbut no "reactivate" action existed. In v2 theRecurringInvoicesTableaction group needs a conditional action.Acceptance Criteria:
recurring_invoice_status = 'active'and resumes the billing schedule from the next due date.Implementation:
Action::make('activate')inRecurringInvoicesTable(or wherever the Stop action lives), visible only when$record->recurring_invoice_status === 'stopped'.RecurringInvoiceService::activate($record): set status toactive, recalculatenext_invoice_datefrom today + interval.stopaction when status is alreadystopped.Test Scenarios (PHPUnit + Livewire):
Generated by Claude Code
[-]Recurring invoice can't be activated after being "stopped"[/-][+][Invoices]: Reactivate a stopped recurring invoice[/+]nielsdrost7 commentedon Jul 16, 2026
Test Suggestions
Added to support future implementation of this request. The issue body is unchanged.
RecurringInvoicesTable(Modules/Invoices/Filament/Company/Resources/RecurringInvoices/Tables/RecurringInvoicesTable.php) currently only exposesEditActionandDeleteActioninside anActionGroup— there is no "stop"/"options" dropdown at all in v2 today. The reporter is describing v1 behavior ("options button only shows stop"); in the current codebase there isn't yet a stop action to reactivate from.RecurringInvoiceonly hasstart_at/end_atdate columns — there's no boolean/status column (e.g.is_stopped) representing "stopped" vs. "active" at all, andModules\Invoices\Services\RecurringInvoiceServiceis an empty stub, so there's no service-layer home for areactivate()method either. This needs the stop/active concept designed and built (likely alongside #52's full recurring lifecycle) before "reactivate" has any meaning.it_reactivates_a_stopped_recurring_invoice()it_hides_the_reactivate_action_for_a_recurring_invoice_that_is_already_active()it_resumes_generating_invoices_on_the_next_scheduled_run_after_reactivation()Edge cases worth covering: a recurring invoice whose
end_athas already passed (does reactivating also require bumpingend_at, or is that a separate step?), and reactivating a profile whose linked numbering scheme was deleted in the meantime.nielsdrost7 commentedon Jul 18, 2026
v1 could stop a schedule (
application/modules/invoices/controllers/Recurring.php:51→Mdl_invoices_recurring::stop()setsrecur_end_date = today,recur_next_date = NULL) but never restart it — this issue closes that hole in v2. Depends on the v2 Stop action ([Invoices]: Stop a recurring invoice) and thenext_run_atcolumn from the generation-engine issue (Epic #52).Specific
Add a
reactivaterecord action toModules/Invoices/Filament/Company/Resources/RecurringInvoices/Tables/RecurringInvoicesTable.php, visible only for stopped schedules (next_run_at IS NULL). It opens a small form: new optionalend_at(must be in the future), then recomputesnext_run_atas the first frequency-step from the originalstart_at(or lastlast_run_at) that lands strictly after today, clears/updatesend_at, and returns the schedule to "active".Measurable
next_run_atis aligned to the original cadence, not simply "today".Achievable
Single Filament action + one service method
RecurringInvoiceService::reactivate(RecurringInvoice $r, ?Carbon $newEndAt); date walk uses the same frequency-increment helper as the engine.Relevant
Stop is destructive-but-reversible in spirit (pause a subscription over a dispute, resume later); without reactivation users must delete and re-create the schedule, losing history. Epic #52 lists "Pausing stops generation without deleting history" as a requirement.
Time-Bound
Half a sprint, after Stop action and engine schema land; part of Epic #52.
Arrange
end_at = stop date,next_run_at = NULL), withlast_run_atset.Act
reactivateaction withend_at = null; run the generation engine for today.Assert
next_run_atequals the first monthly step after today on the original cadence;end_atis null.end_atis rejected with a validation error.