Permette di mettere in pausa un invio e riprenderlo senza perdere la coda.
CI / scan_js (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / scan_ruby (push) Has been cancelled

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-07 12:35:42 +02:00
co-authored by Cursor
parent 4cf34b2033
commit 3c8bfe053f
10 changed files with 108 additions and 17 deletions
+33 -6
View File
@@ -1,6 +1,6 @@
class MailingsController < ApplicationController
before_action :require_current_project!
before_action :set_mailing, only: %i[show edit update destroy queue cancel test_send test_preview refresh_recipients update_recipients preview audience update_audience]
before_action :set_mailing, only: %i[show edit update destroy queue pause resume cancel test_send test_preview refresh_recipients update_recipients preview audience update_audience]
before_action :load_form_collections, only: %i[new create edit update]
def index
@@ -11,8 +11,9 @@ class MailingsController < ApplicationController
@page_title = "Invii email"
@mailings = Mailing.for_project(current_project).includes(:mail_identity).recent
@mail_identities_count = MailIdentity.active.count
@active_mailings = @mailings.select(&:sending?)
@paused_mailings = @active_mailings.select { |mailing| mailing.next_send_at.present? && mailing.next_send_at > Time.current }
@active_mailings = @mailings.select { |mailing| mailing.sending? || mailing.paused? }
@window_paused_mailings = @mailings.select(&:sending?).select { |mailing| mailing.next_send_at.present? && mailing.next_send_at > Time.current }
@paused_mailings = @window_paused_mailings
@completed_today = @mailings.count { |mailing| mailing.sent? && mailing.completed_at&.to_date == Time.zone.today }
@failed_open = @mailings.sum(&:failed_count)
end
@@ -180,16 +181,42 @@ class MailingsController < ApplicationController
redirect_to @mailing, alert: e.message
end
def cancel
def pause
unless @mailing.sending?
redirect_to @mailing, alert: "Solo un invio in corso può essere fermato."
redirect_to @mailing, alert: "Solo un invio in corso può essere messo in pausa."
return
end
remaining = @mailing.pending_count + @mailing.queued_count
@mailing.pause_send!
redirect_to dashboard_mailings_path,
notice: "Invio in pausa. #{@mailing.sent_count} già inviate, #{remaining} pronte per quando riprendi."
rescue StandardError => e
redirect_to @mailing, alert: e.message
end
def resume
unless @mailing.paused?
redirect_to @mailing, alert: "Solo un invio in pausa può essere ripreso."
return
end
@mailing.resume_send!
redirect_to dashboard_mailings_path, notice: "Invio ripreso da dove era rimasto."
rescue StandardError => e
redirect_to @mailing, alert: e.message
end
def cancel
unless @mailing.sending? || @mailing.paused?
redirect_to @mailing, alert: "Solo un invio in corso o in pausa può essere annullato."
return
end
pending = @mailing.pending_count + @mailing.queued_count
@mailing.cancel_send!
redirect_to dashboard_mailings_path,
notice: "Invio fermato. #{@mailing.sent_count} già inviate, #{pending} annullate in coda."
notice: "Invio annullato. #{@mailing.sent_count} già inviate, #{pending} in coda saltate."
rescue StandardError => e
redirect_to @mailing, alert: e.message
end
+1
View File
@@ -163,6 +163,7 @@ module ApplicationHelper
colors = {
"draft" => "bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200",
"sending" => "bg-amber-100 text-amber-800 dark:bg-amber-950 dark:text-amber-200",
"paused" => "bg-sky-100 text-sky-800 dark:bg-sky-950 dark:text-sky-200",
"sent" => "bg-emerald-100 text-emerald-800 dark:bg-emerald-950 dark:text-emerald-200",
"cancelled" => "bg-rose-100 text-rose-800 dark:bg-rose-950 dark:text-rose-200"
}
+1
View File
@@ -68,6 +68,7 @@ module Catalog
MAILING_STATUSES = {
"draft" => "Bozza",
"sending" => "Invio in corso",
"paused" => "In pausa",
"sent" => "Inviata",
"cancelled" => "Annullata"
}.freeze
+20 -1
View File
@@ -77,6 +77,10 @@ class Mailing < ApplicationRecord
status == "sending"
end
def paused?
status == "paused"
end
def sent?
status == "sent"
end
@@ -215,8 +219,23 @@ class Mailing < ApplicationRecord
update!(status: "sent", completed_at: Time.current, next_send_at: nil)
end
def pause_send!
raise "Solo un invio in corso può essere messo in pausa" unless sending?
update!(status: "paused", next_send_at: nil)
end
def resume_send!
raise "Solo un invio in pausa può essere ripreso" unless paused?
raise "Nessun destinatario da inviare" if pending_count.zero? && queued_count.zero?
update!(status: "sending")
enqueue_next_recipient!(mailing_recipients.pending.order(:id).first, from: Time.current) if pending_count.positive?
DrainOutboundJob.perform_later if mailing_recipients.queued.exists?
end
def cancel_send!
raise "Solo un invio in corso può essere fermato" unless sending?
raise "Solo un invio in corso o in pausa può essere annullato" unless sending? || paused?
transaction do
mailing_recipients.where(status: %w[pending queued]).find_each do |recipient|
+2 -4
View File
@@ -31,11 +31,9 @@
<% elsif mailing.pending_count.positive? %>
<p class="mt-3 text-xs text-zinc-500">Prossima email in lavorazione.</p>
<% end %>
<% if mailing.sending? %>
<% if mailing.sending? || mailing.paused? %>
<div class="mt-4 border-t border-zinc-100 pt-4 dark:border-zinc-800">
<%= button_to "Ferma invio", cancel_mailing_path(mailing), method: :post,
class: btn_danger,
form: { data: { turbo_confirm: "Fermare l'invio? Restano inviate #{mailing.sent_count} email, #{mailing.pending_count + mailing.queued_count} in coda verranno annullate." } } %>
<%= render "mailings/send_controls", mailing: mailing %>
</div>
<% end %>
</div>
@@ -0,0 +1,17 @@
<% if mailing.sending? %>
<div class="flex flex-wrap gap-2">
<%= button_to "Metti in pausa", pause_mailing_path(mailing), method: :post,
class: btn_secondary,
form: { data: { turbo_confirm: "Mettere in pausa? Le #{mailing.sent_count} già inviate restano. Le #{mailing.pending_count + mailing.queued_count} non ancora partite si riprendono da qui." } } %>
<%= button_to "Annulla definitivamente", cancel_mailing_path(mailing), method: :post,
class: btn_danger,
form: { data: { turbo_confirm: "Annullare l'invio? Le #{mailing.sent_count} già inviate restano, le #{mailing.pending_count + mailing.queued_count} in coda verranno saltate e non si potranno riprendere." } } %>
</div>
<% elsif mailing.paused? %>
<div class="flex flex-wrap gap-2">
<%= button_to "Riprendi invio", resume_mailing_path(mailing), method: :post, class: btn_primary %>
<%= button_to "Annulla definitivamente", cancel_mailing_path(mailing), method: :post,
class: btn_danger,
form: { data: { turbo_confirm: "Annullare l'invio? Le #{mailing.sent_count} già inviate restano, le #{mailing.pending_count + mailing.queued_count} in coda verranno saltate e non si potranno riprendere." } } %>
</div>
<% end %>
+2
View File
@@ -77,6 +77,8 @@
<%= mailing.sent_count %> inviate · <%= mailing.opened_count %> aperte · <%= mailing.pending_count %> in coda
<% if mailing.sending? && mailing.next_send_at.present? && mailing.next_send_at > Time.current %>
· Riparte <%= l(mailing.next_send_at, format: :short) %>
<% elsif mailing.paused? %>
· In pausa, si può riprendere
<% end %>
</div>
<% end %>
+4 -6
View File
@@ -34,15 +34,13 @@
<%= link_to "Raffina destinatari", audience_mailing_path(@mailing), class: btn_secondary %>
<%= button_to "Rigenera lista", refresh_recipients_mailing_path(@mailing), method: :post, class: btn_secondary %>
<%= render "mailings/delete_draft_button", mailing: @mailing, extra_class: "flex-1 sm:flex-none" %>
<% elsif @mailing.sending? %>
<%= button_to "Ferma invio", cancel_mailing_path(@mailing), method: :post,
class: btn_danger,
form: { data: { turbo_confirm: "Fermare l'invio? Le #{@mailing.sent_count} già inviate restano, #{@mailing.pending_count + @mailing.queued_count} in coda verranno annullate." } } %>
<% elsif @mailing.sending? || @mailing.paused? %>
<%= render "mailings/send_controls", mailing: @mailing %>
<% end %>
</div>
</div>
<% if @mailing.sending? || @mailing.sent? %>
<% if @mailing.sending? || @mailing.paused? || @mailing.sent? %>
<%= render "mailings/progress_card", mailing: @mailing %>
<% end %>
@@ -65,7 +63,7 @@
</div>
</div>
<% if @mailing.sending? || @mailing.sent? || @mailing.cancelled? %>
<% if @mailing.sending? || @mailing.paused? || @mailing.sent? || @mailing.cancelled? %>
<div class="grid grid-cols-2 gap-3">
<div class="<%= card_class %> p-4">
<div class="text-xs uppercase tracking-wide text-zinc-500">Aperte</div>