diff --git a/app/controllers/mailings_controller.rb b/app/controllers/mailings_controller.rb index 45fe9e4..15b92d9 100644 --- a/app/controllers/mailings_controller.rb +++ b/app/controllers/mailings_controller.rb @@ -1,6 +1,6 @@ class MailingsController < ApplicationController before_action :require_current_project! - before_action :set_mailing, only: %i[show edit update destroy queue test_send test_preview refresh_recipients update_recipients preview] + before_action :set_mailing, only: %i[show edit update destroy queue cancel test_send test_preview refresh_recipients update_recipients preview] before_action :load_form_collections, only: %i[new create edit update] def index @@ -139,6 +139,20 @@ class MailingsController < ApplicationController redirect_to @mailing, alert: e.message end + def cancel + unless @mailing.sending? + redirect_to @mailing, alert: "Solo un invio in corso può essere fermato." + 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." + rescue StandardError => e + redirect_to @mailing, alert: e.message + end + def test_send assign_test_preview to = @test_to.to_s.strip diff --git a/app/models/mailing.rb b/app/models/mailing.rb index 3011f92..18ff949 100644 --- a/app/models/mailing.rb +++ b/app/models/mailing.rb @@ -72,6 +72,10 @@ class Mailing < ApplicationRecord status == "sent" end + def cancelled? + status == "cancelled" + end + def editable? draft? end @@ -187,6 +191,17 @@ class Mailing < ApplicationRecord update!(status: "sent", completed_at: Time.current, next_send_at: nil) end + def cancel_send! + raise "Solo un invio in corso può essere fermato" unless sending? + + transaction do + mailing_recipients.where(status: %w[pending queued]).find_each do |recipient| + recipient.update!(status: "skipped", skip_reason: "invio annullato") + end + update!(status: "cancelled", next_send_at: nil, completed_at: Time.current) + end + end + private def send_window_order diff --git a/app/models/mailing_recipient.rb b/app/models/mailing_recipient.rb index 930bfb3..eae4933 100644 --- a/app/models/mailing_recipient.rb +++ b/app/models/mailing_recipient.rb @@ -47,10 +47,13 @@ class MailingRecipient < ApplicationRecord def deliver! with_lock do return if status.in?(%w[sent skipped]) + return abort_delivery!("invio annullato") unless mailing.sending? update!(status: "queued") end + return unless mailing.sending? + html = rendered_html subject_line = rendered_subject_line CampaignMailer.outreach(self, html: html, subject: subject_line).deliver_now @@ -63,6 +66,10 @@ class MailingRecipient < ApplicationRecord private + def abort_delivery!(reason) + update!(status: "skipped", skip_reason: reason) + end + def record_success!(subject_line) transaction do update!(status: "sent", sent_at: Time.current, rendered_subject: subject_line, error_message: nil) diff --git a/app/views/mailings/_progress_card.html.erb b/app/views/mailings/_progress_card.html.erb index 113e11d..9d6f212 100644 --- a/app/views/mailings/_progress_card.html.erb +++ b/app/views/mailings/_progress_card.html.erb @@ -30,4 +30,11 @@ <% elsif mailing.pending_count.positive? %>

Prossima email in lavorazione.

<% end %> + <% if mailing.sending? %> +
+ <%= 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." } } %> +
+ <% end %> diff --git a/app/views/mailings/show.html.erb b/app/views/mailings/show.html.erb index e8ef0f7..a1ffeff 100644 --- a/app/views/mailings/show.html.erb +++ b/app/views/mailings/show.html.erb @@ -30,6 +30,10 @@ <% if @mailing.editable? %> <%= link_to "Modifica contenuto", edit_mailing_path(@mailing), class: btn_secondary %> <%= button_to "Aggiorna lista", refresh_recipients_mailing_path(@mailing), method: :post, class: btn_secondary %> + <% 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." } } %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index e3c4365..d03f4e2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -55,6 +55,7 @@ Rails.application.routes.draw do end member do post :queue + post :cancel post :test_send get :test_preview post :refresh_recipients diff --git a/test/controllers/mailings_controller_test.rb b/test/controllers/mailings_controller_test.rb index 8488f95..1e6a59c 100644 --- a/test/controllers/mailings_controller_test.rb +++ b/test/controllers/mailings_controller_test.rb @@ -184,4 +184,25 @@ class MailingsControllerTest < ActionDispatch::IntegrationTest assert_equal "B {{societa}}", mailing.subject_b assert_includes mailing.body_html_b, "Versione B dal template" end + + test "cancel stops pending recipients and keeps sent ones" do + login_as users(:admin) + follow_redirect! if response.redirect? + create_campaign_org(name: "Seconda societa", email: "seconda@example.com") + mailing = create_mailing(identity: @identity, audience: "to_send") + mailing.rebuild_recipients! + recipients = mailing.mailing_recipients.order(:id).to_a + assert recipients.size >= 2 + recipients.first.update!(status: "sent", sent_at: Time.current) + mailing.update!(status: "sending", queued_at: Time.current, test_sent_at: Time.current, test_sent_to: "test@example.com") + + post cancel_mailing_path(mailing, project_code: @project.code) + + assert_redirected_to dashboard_mailings_path(project_code: @project.code) + assert_equal "cancelled", mailing.reload.status + assert_equal "sent", recipients.first.reload.status + assert_equal "skipped", recipients.second.reload.status + assert_equal "invio annullato", recipients.second.skip_reason + assert mailing.mailing_recipients.pending.none? + end end