Aggiunge fascia oraria, prova manuale obbligatoria e cruscotto invii email.
CI / lint (push) Failing after 16m2s
CI / scan_ruby (push) Has been cancelled
CI / scan_js (push) Has been cancelled

Le campagne rispettano orario e giorni lavorativi, richiedono una mail di test con dati inseriti a mano prima dell'invio massivo e offrono una dashboard per monitorare l'avanzamento.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-18 00:04:33 +02:00
co-authored by Cursor
parent 4ddf534a0c
commit 98dcdbbf82
33 changed files with 882 additions and 56 deletions
+79
View File
@@ -0,0 +1,79 @@
module Mailings
class SendClock
def initialize(mailing, time: Time.zone.now)
@mailing = mailing
@time = time.in_time_zone
end
def open?(at = @time)
t = at.in_time_zone
return true unless @mailing.send_window_enabled?
working_day?(t.to_date) && minutes_in_window?(t)
end
def next_send_at(earliest: @time)
t = earliest.in_time_zone
return t unless @mailing.send_window_enabled?
next_open_at(from: t)
end
def next_open_at(from: @time)
t = from.in_time_zone
return t unless @mailing.send_window_enabled?
0.upto(21) do |offset|
day = t.to_date + offset
next unless working_day?(day)
start_at = time_on(day, start_minutes)
end_at = time_on(day, end_minutes)
if offset.zero?
return t if t >= start_at && t < end_at
return start_at if t < start_at
next
end
return start_at
end
t + 21.days
end
def window_label
"#{format_minutes(start_minutes)}#{format_minutes(end_minutes)}"
end
private
def working_day?(date)
date.on_weekday? && !Italy::Holidays.holiday?(date)
end
def minutes_in_window?(time)
minutes = (time.hour * 60) + time.min
minutes >= start_minutes && minutes < end_minutes
end
def start_minutes
@mailing.send_window_start_minutes.presence || (10 * 60)
end
def end_minutes
@mailing.send_window_end_minutes.presence || (18 * 60)
end
def time_on(date, minutes)
if minutes >= (24 * 60)
Time.zone.local(date.year, date.month, date.day).beginning_of_day + 1.day
else
Time.zone.local(date.year, date.month, date.day, minutes / 60, minutes % 60, 0)
end
end
def format_minutes(minutes)
format("%02d:%02d", minutes / 60, minutes % 60)
end
end
end
+3
View File
@@ -0,0 +1,3 @@
module Mailings
TestRecipient = Struct.new(:mailing, :email, keyword_init: true)
end