PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.1
1.7.1 1.7.0 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 All 51 releases
← All changes | app/Services/Reminders/RenewalReminderService.php +44 -1 1.6.2 → 1.7.1 View file →
@@ -7,8 +7,9 @@
7 7 use FluentCart\App\Models\OrderMeta;
8 8 use FluentCart\App\Models\Subscription;
9 9 use FluentCart\App\Modules\Subscriptions\Services\SystemChargeService;
10 10 use FluentCart\App\Services\Payments\PaymentHelper;
11 +use FluentCart\App\Services\Payments\SubscriptionHelper;
11 12
12 13 class RenewalReminderService extends ReminderService
13 14 {
14 15 const META_KEY = 'renewal_reminder_state';
@@ -64,8 +65,23 @@
64 65 ];
65 66
66 67 do_action('fluent_cart/' . $eventName, $data);
67 68
69 + if (strpos($stage, 'overdue_') === 0) {
70 + // Legacy hook shipped in 1.6.0 for scheduled overdue reminders.
71 + // Kept for third-party listeners; the flag tells the core mailer
72 + // the staged email above was already sent, so it must not mail
73 + // again — direct dispatches of the legacy hook lack the flag and
74 + // still deliver.
75 + $data['staged_email_dispatched'] = true;
76 + do_action_deprecated(
77 + 'fluent_cart/renewal_reminder_overdue',
78 + [$data],
79 + '1.6.3',
80 + 'fluent_cart/' . $eventName
81 + );
82 + }
83 +
68 84 $state = $this->markStageSent($state, $cycleKey, $stage);
69 85 $order->updateMeta(static::META_KEY, $state);
70 86
71 87 return true;
@@ -328,8 +344,15 @@
328 344 */
329 345
330 346 protected function isEligible(Order $order): bool
331 347 {
348 + // Live invoice on a test-mode store (or vice versa): don't email — the
349 + // guard's promise covers reminders too. Checked at both scan and send
350 + // time so pre-queued actions copied to a clone are also caught.
351 + if (!SubscriptionHelper::canProcessInMode($order->mode)) {
352 + return false;
353 + }
354 +
332 355 if (!in_array($order->payment_status, static::getReminderPaymentStatuses(), true)) {
333 356 return false;
334 357 }
335 358
@@ -416,10 +439,30 @@
416 439
417 440 protected function resolveEventName(string $stage): string
418 441 {
419 442 if (strpos($stage, 'overdue_') === 0) {
420 - return 'renewal_reminder_overdue';
443 + return $this->resolveOverdueEventName((int)substr($stage, strlen('overdue_')));
421 444 }
422 445
423 446 return 'renewal_reminder_due';
447 + }
448 +
449 + /**
450 + * Map an overdue stage to a notification event by its position in the
451 + * configured day list, not by a fixed day threshold — the escalation tone
452 + * follows the admin's schedule (e.g. 14,30 → first at 14, final at 30).
453 + */
454 + protected function resolveOverdueEventName(int $daysAfter): string
455 + {
456 + $days = $this->getOverdueDays();
457 +
458 + if (empty($days) || $daysAfter <= min($days)) {
459 + return 'renewal_overdue_first';
460 + }
461 +
462 + if ($daysAfter >= max($days)) {
463 + return 'renewal_overdue_final';
464 + }
465 +
466 + return 'renewal_overdue_followup';
424 467 }
425 468 }