Page MenuHomePhorge

No OneTemporary

Size
74 KB
Referenced Files
None
Subscribers
None
diff --git a/src/app/Jobs/WalletCheck.php b/src/app/Jobs/WalletCheck.php
index 85e53e38..f7629bc3 100644
--- a/src/app/Jobs/WalletCheck.php
+++ b/src/app/Jobs/WalletCheck.php
@@ -1,397 +1,273 @@
<?php
namespace App\Jobs;
use App\Http\Controllers\API\V4\PaymentsController;
use App\Wallet;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class WalletCheck implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public const THRESHOLD_DEGRADE = 'degrade';
public const THRESHOLD_DEGRADE_REMINDER = 'degrade-reminder';
- public const THRESHOLD_BEFORE_DEGRADE = 'before_degrade';
- public const THRESHOLD_DELETE = 'delete';
- public const THRESHOLD_BEFORE_DELETE = 'before_delete';
- public const THRESHOLD_SUSPEND = 'suspend';
- public const THRESHOLD_BEFORE_SUSPEND = 'before_suspend';
+ public const THRESHOLD_BEFORE_DEGRADE = 'before-degrade';
public const THRESHOLD_REMINDER = 'reminder';
- public const THRESHOLD_BEFORE_REMINDER = 'before_reminder';
+ public const THRESHOLD_BEFORE_REMINDER = 'before-reminder';
public const THRESHOLD_INITIAL = 'initial';
/** @var int The number of seconds to wait before retrying the job. */
public $backoff = 10;
/** @var int How many times retry the job if it fails. */
public $tries = 5;
/** @var bool Delete the job if the wallet no longer exist. */
public $deleteWhenMissingModels = true;
/** @var \App\Wallet A wallet object */
protected $wallet;
/**
* Create a new job instance.
*
* @param \App\Wallet $wallet The wallet that has been charged.
*
* @return void
*/
public function __construct(Wallet $wallet)
{
$this->wallet = $wallet;
}
/**
* Execute the job.
*
* @return ?string Executed action (THRESHOLD_*)
*/
public function handle()
{
if ($this->wallet->balance >= 0) {
return null;
}
$now = Carbon::now();
-/*
- // Steps for old "first suspend then delete" approach
- $steps = [
- // Send the initial reminder
- self::THRESHOLD_INITIAL => 'initialReminder',
- // Try to top-up the wallet before the second reminder
- self::THRESHOLD_BEFORE_REMINDER => 'topUpWallet',
- // Send the second reminder
- self::THRESHOLD_REMINDER => 'secondReminder',
- // Try to top-up the wallet before suspending the account
- self::THRESHOLD_BEFORE_SUSPEND => 'topUpWallet',
- // Suspend the account
- self::THRESHOLD_SUSPEND => 'suspendAccount',
- // Warn about the upcomming account deletion
- self::THRESHOLD_BEFORE_DELETE => 'warnBeforeDelete',
- // Delete the account
- self::THRESHOLD_DELETE => 'deleteAccount',
- ];
-*/
- // Steps for "demote instead of suspend+delete" approach
+
$steps = [
// Send the initial reminder
self::THRESHOLD_INITIAL => 'initialReminderForDegrade',
// Try to top-up the wallet before the second reminder
self::THRESHOLD_BEFORE_REMINDER => 'topUpWallet',
// Send the second reminder
self::THRESHOLD_REMINDER => 'secondReminderForDegrade',
// Try to top-up the wallet before the account degradation
self::THRESHOLD_BEFORE_DEGRADE => 'topUpWallet',
// Degrade the account
self::THRESHOLD_DEGRADE => 'degradeAccount',
];
if ($this->wallet->owner && $this->wallet->owner->isDegraded()) {
$this->degradedReminder();
return self::THRESHOLD_DEGRADE_REMINDER;
}
foreach (array_reverse($steps, true) as $type => $method) {
if (self::threshold($this->wallet, $type) < $now) {
$this->{$method}();
return $type;
}
}
return null;
}
- /**
- * Send the initial reminder (for the suspend+delete process)
- */
- protected function initialReminder()
- {
- if ($this->wallet->getSetting('balance_warning_initial')) {
- return;
- }
-
- // TODO: Should we check if the account is already suspended?
-
- $this->sendMail(\App\Mail\NegativeBalance::class, false);
-
- $now = \Carbon\Carbon::now()->toDateTimeString();
- $this->wallet->setSetting('balance_warning_initial', $now);
- }
-
/**
* Send the initial reminder (for the process of degrading a account)
*/
protected function initialReminderForDegrade()
{
if ($this->wallet->getSetting('balance_warning_initial')) {
return;
}
if (!$this->wallet->owner || $this->wallet->owner->isDegraded()) {
return;
}
- $this->sendMail(\App\Mail\NegativeBalance::class, false);
-
- $now = \Carbon\Carbon::now()->toDateTimeString();
- $this->wallet->setSetting('balance_warning_initial', $now);
- }
-
- /**
- * Send the second reminder (for the suspend+delete process)
- */
- protected function secondReminder()
- {
- if ($this->wallet->getSetting('balance_warning_reminder')) {
- return;
+ if (!$this->wallet->owner->isSuspended()) {
+ $this->sendMail(\App\Mail\NegativeBalance::class, false);
}
- // TODO: Should we check if the account is already suspended?
-
- $this->sendMail(\App\Mail\NegativeBalanceReminder::class, false);
-
$now = \Carbon\Carbon::now()->toDateTimeString();
- $this->wallet->setSetting('balance_warning_reminder', $now);
+ $this->wallet->setSetting('balance_warning_initial', $now);
}
/**
* Send the second reminder (for the process of degrading a account)
*/
protected function secondReminderForDegrade()
{
if ($this->wallet->getSetting('balance_warning_reminder')) {
return;
}
if (!$this->wallet->owner || $this->wallet->owner->isDegraded()) {
return;
}
- $this->sendMail(\App\Mail\NegativeBalanceReminderDegrade::class, true);
+ if (!$this->wallet->owner->isSuspended()) {
+ $this->sendMail(\App\Mail\NegativeBalanceReminderDegrade::class, true);
+ }
$now = \Carbon\Carbon::now()->toDateTimeString();
$this->wallet->setSetting('balance_warning_reminder', $now);
}
/**
- * Suspend the account (and send the warning)
+ * Degrade the account
*/
- protected function suspendAccount()
+ protected function degradeAccount()
{
- if ($this->wallet->getSetting('balance_warning_suspended')) {
- return;
- }
-
- // Sanity check, already deleted
- if (!$this->wallet->owner) {
+ // The account may be already deleted, or degraded
+ if (!$this->wallet->owner || $this->wallet->owner->isDegraded()) {
return;
}
- // Suspend the account
- $this->wallet->owner->suspendAccount();
-
- $this->sendMail(\App\Mail\NegativeBalanceSuspended::class, true);
+ $email = $this->wallet->owner->email;
- $now = \Carbon\Carbon::now()->toDateTimeString();
- $this->wallet->setSetting('balance_warning_suspended', $now);
- }
+ // The dirty work will be done by UserObserver
+ $this->wallet->owner->degrade();
- /**
- * Send the last warning before delete
- */
- protected function warnBeforeDelete()
- {
- if ($this->wallet->getSetting('balance_warning_before_delete')) {
- return;
- }
+ \Log::info(
+ sprintf(
+ "[WalletCheck] Account degraded %s (%s)",
+ $this->wallet->id,
+ $email
+ )
+ );
- // Sanity check, already deleted
- if (!$this->wallet->owner) {
- return;
+ if (!$this->wallet->owner->isSuspended()) {
+ $this->sendMail(\App\Mail\NegativeBalanceDegraded::class, true);
}
-
- $this->sendMail(\App\Mail\NegativeBalanceBeforeDelete::class, true);
-
- $now = \Carbon\Carbon::now()->toDateTimeString();
- $this->wallet->setSetting('balance_warning_before_delete', $now);
}
/**
* Send the periodic reminder to the degraded account owners
*/
protected function degradedReminder()
{
// Sanity check
if (!$this->wallet->owner || !$this->wallet->owner->isDegraded()) {
return;
}
+ if ($this->wallet->owner->isSuspended()) {
+ return;
+ }
+
$now = \Carbon\Carbon::now();
$last = $this->wallet->getSetting('degraded_last_reminder');
if ($last) {
$last = new Carbon($last);
$period = 14;
if ($last->addDays($period) > $now) {
return;
}
- $this->sendMail(\App\Mail\DegradedAccountReminder::class, true);
+ $this->sendMail(\App\Mail\DegradedAccountReminder::class, false);
}
$this->wallet->setSetting('degraded_last_reminder', $now->toDateTimeString());
}
- /**
- * Degrade the account
- */
- protected function degradeAccount()
- {
- // The account may be already deleted, or degraded
- if (!$this->wallet->owner || $this->wallet->owner->isDegraded()) {
- return;
- }
-
- $email = $this->wallet->owner->email;
-
- // The dirty work will be done by UserObserver
- $this->wallet->owner->degrade();
-
- \Log::info(
- sprintf(
- "[WalletCheck] Account degraded %s (%s)",
- $this->wallet->id,
- $email
- )
- );
-
- $this->sendMail(\App\Mail\NegativeBalanceDegraded::class, true);
- }
-
- /**
- * Delete the account
- */
- protected function deleteAccount()
- {
- // TODO: This will not work when we actually allow multiple-wallets per account
- // but in this case we anyway have to change the whole thing
- // and calculate summarized balance from all wallets.
- // The dirty work will be done by UserObserver
- if ($this->wallet->owner) {
- $email = $this->wallet->owner->email;
-
- $this->wallet->owner->delete();
-
- \Log::info(
- sprintf(
- "[WalletCheck] Account deleted %s (%s)",
- $this->wallet->id,
- $email
- )
- );
- }
- }
-
/**
* Send the email
*
* @param string $class Mailable class name
* @param bool $with_external Use users's external email
*/
protected function sendMail($class, $with_external = false): void
{
// TODO: Send the email to all wallet controllers?
$mail = new $class($this->wallet, $this->wallet->owner);
list($to, $cc) = \App\Mail\Helper::userEmails($this->wallet->owner, $with_external);
if (!empty($to) || !empty($cc)) {
$params = [
'to' => $to,
'cc' => $cc,
'add' => " for {$this->wallet->id}",
];
\App\Mail\Helper::sendMail($mail, $this->wallet->owner->tenant_id, $params);
}
}
/**
* Get the date-time for an action threshold. Calculated using
* the date when a wallet balance turned negative.
*
* @param \App\Wallet $wallet A wallet
* @param string $type Action type (one of self::THRESHOLD_*)
*
* @return \Carbon\Carbon The threshold date-time object
*/
public static function threshold(Wallet $wallet, string $type): ?Carbon
{
$negative_since = $wallet->getSetting('balance_negative_since');
// Migration scenario: balance<0, but no balance_negative_since set
if (!$negative_since) {
// 2h back from now, so first run can sent the initial notification
$negative_since = Carbon::now()->subHours(2);
$wallet->setSetting('balance_negative_since', $negative_since->toDateTimeString());
} else {
$negative_since = new Carbon($negative_since);
}
// Initial notification
// Give it an hour so the async recurring payment has a chance to be finished
if ($type == self::THRESHOLD_INITIAL) {
return $negative_since->addHours(1);
}
$thresholds = [
// A day before the second reminder
self::THRESHOLD_BEFORE_REMINDER => 7 - 1,
// Second notification
self::THRESHOLD_REMINDER => 7,
-
- // A day before account suspension
- self::THRESHOLD_BEFORE_SUSPEND => 14 + 7 - 1,
- // Account suspension
- self::THRESHOLD_SUSPEND => 14 + 7,
- // Warning about the upcomming account deletion
- self::THRESHOLD_BEFORE_DELETE => 21 + 14 + 7 - 3,
- // Acount deletion
- self::THRESHOLD_DELETE => 21 + 14 + 7,
-
// Last chance to top-up the wallet
self::THRESHOLD_BEFORE_DEGRADE => 13,
// Account degradation
self::THRESHOLD_DEGRADE => 14,
];
if (!empty($thresholds[$type])) {
return $negative_since->addDays($thresholds[$type]);
}
return null;
}
/**
* Try to automatically top-up the wallet
*/
protected function topUpWallet(): void
{
PaymentsController::topUpWallet($this->wallet);
}
}
diff --git a/src/app/Mail/NegativeBalanceBeforeDelete.php b/src/app/Mail/NegativeBalanceBeforeDelete.php
deleted file mode 100644
index b05c0398..00000000
--- a/src/app/Mail/NegativeBalanceBeforeDelete.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-
-namespace App\Mail;
-
-use App\Jobs\WalletCheck;
-use App\Tenant;
-use App\User;
-use App\Utils;
-use App\Wallet;
-use Illuminate\Bus\Queueable;
-use Illuminate\Mail\Mailable;
-use Illuminate\Queue\SerializesModels;
-
-class NegativeBalanceBeforeDelete extends Mailable
-{
- use Queueable;
- use SerializesModels;
-
- /** @var \App\Wallet A wallet with a negative balance */
- protected $wallet;
-
- /** @var \App\User A wallet controller to whom the email is being sent */
- protected $user;
-
-
- /**
- * Create a new message instance.
- *
- * @param \App\Wallet $wallet A wallet
- * @param \App\User $user An email recipient
- *
- * @return void
- */
- public function __construct(Wallet $wallet, User $user)
- {
- $this->wallet = $wallet;
- $this->user = $user;
- }
-
- /**
- * Build the message.
- *
- * @return $this
- */
- public function build()
- {
- $threshold = WalletCheck::threshold($this->wallet, WalletCheck::THRESHOLD_DELETE);
- $appName = Tenant::getConfig($this->user->tenant_id, 'app.name');
- $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url');
-
- $subject = \trans('mail.negativebalancebeforedelete-subject', ['site' => $appName]);
-
- $this->view('emails.html.negative_balance_before_delete')
- ->text('emails.plain.negative_balance_before_delete')
- ->subject($subject)
- ->with([
- 'site' => $appName,
- 'subject' => $subject,
- 'username' => $this->user->name(true),
- 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id),
- 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id),
- 'date' => $threshold->toDateString(),
- ]);
-
- return $this;
- }
-
- /**
- * Render the mail template with fake data
- *
- * @param string $type Output format ('html' or 'text')
- *
- * @return string HTML or Plain Text output
- */
- public static function fakeRender(string $type = 'html'): string
- {
- $wallet = new Wallet();
- $user = new User();
-
- $mail = new self($wallet, $user);
-
- return Helper::render($mail, $type);
- }
-}
diff --git a/src/app/Mail/NegativeBalanceReminder.php b/src/app/Mail/NegativeBalanceReminder.php
deleted file mode 100644
index 211e7e21..00000000
--- a/src/app/Mail/NegativeBalanceReminder.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-
-namespace App\Mail;
-
-use App\Jobs\WalletCheck;
-use App\Tenant;
-use App\User;
-use App\Utils;
-use App\Wallet;
-use Illuminate\Bus\Queueable;
-use Illuminate\Mail\Mailable;
-use Illuminate\Queue\SerializesModels;
-
-class NegativeBalanceReminder extends Mailable
-{
- use Queueable;
- use SerializesModels;
-
- /** @var \App\Wallet A wallet with a negative balance */
- protected $wallet;
-
- /** @var \App\User A wallet controller to whom the email is being sent */
- protected $user;
-
-
- /**
- * Create a new message instance.
- *
- * @param \App\Wallet $wallet A wallet
- * @param \App\User $user An email recipient
- *
- * @return void
- */
- public function __construct(Wallet $wallet, User $user)
- {
- $this->wallet = $wallet;
- $this->user = $user;
- }
-
- /**
- * Build the message.
- *
- * @return $this
- */
- public function build()
- {
- $threshold = WalletCheck::threshold($this->wallet, WalletCheck::THRESHOLD_SUSPEND);
- $appName = Tenant::getConfig($this->user->tenant_id, 'app.name');
- $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url');
-
- $subject = \trans('mail.negativebalancereminder-subject', ['site' => $appName]);
-
- $this->view('emails.html.negative_balance_reminder')
- ->text('emails.plain.negative_balance_reminder')
- ->subject($subject)
- ->with([
- 'site' => $appName,
- 'subject' => $subject,
- 'username' => $this->user->name(true),
- 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id),
- 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id),
- 'date' => $threshold->toDateString(),
- ]);
-
- return $this;
- }
-
- /**
- * Render the mail template with fake data
- *
- * @param string $type Output format ('html' or 'text')
- *
- * @return string HTML or Plain Text output
- */
- public static function fakeRender(string $type = 'html'): string
- {
- $wallet = new Wallet();
- $user = new User();
-
- $mail = new self($wallet, $user);
-
- return Helper::render($mail, $type);
- }
-}
diff --git a/src/app/Mail/NegativeBalanceSuspended.php b/src/app/Mail/NegativeBalanceSuspended.php
deleted file mode 100644
index b83d5d17..00000000
--- a/src/app/Mail/NegativeBalanceSuspended.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-
-namespace App\Mail;
-
-use App\Jobs\WalletCheck;
-use App\Tenant;
-use App\User;
-use App\Utils;
-use App\Wallet;
-use Illuminate\Bus\Queueable;
-use Illuminate\Mail\Mailable;
-use Illuminate\Queue\SerializesModels;
-
-class NegativeBalanceSuspended extends Mailable
-{
- use Queueable;
- use SerializesModels;
-
- /** @var \App\Wallet A wallet with a negative balance */
- protected $wallet;
-
- /** @var \App\User A wallet controller to whom the email is being sent */
- protected $user;
-
-
- /**
- * Create a new message instance.
- *
- * @param \App\Wallet $wallet A wallet
- * @param \App\User $user An email recipient
- *
- * @return void
- */
- public function __construct(Wallet $wallet, User $user)
- {
- $this->wallet = $wallet;
- $this->user = $user;
- }
-
- /**
- * Build the message.
- *
- * @return $this
- */
- public function build()
- {
- $threshold = WalletCheck::threshold($this->wallet, WalletCheck::THRESHOLD_DELETE);
- $appName = Tenant::getConfig($this->user->tenant_id, 'app.name');
- $supportUrl = Tenant::getConfig($this->user->tenant_id, 'app.support_url');
-
- $subject = \trans('mail.negativebalancesuspended-subject', ['site' => $appName]);
-
- $this->view('emails.html.negative_balance_suspended')
- ->text('emails.plain.negative_balance_suspended')
- ->subject($subject)
- ->with([
- 'site' => $appName,
- 'subject' => $subject,
- 'username' => $this->user->name(true),
- 'supportUrl' => Utils::serviceUrl($supportUrl, $this->user->tenant_id),
- 'walletUrl' => Utils::serviceUrl('/wallet', $this->user->tenant_id),
- 'date' => $threshold->toDateString(),
- ]);
-
- return $this;
- }
-
- /**
- * Render the mail template with fake data
- *
- * @param string $type Output format ('html' or 'text')
- *
- * @return string HTML or Plain Text output
- */
- public static function fakeRender(string $type = 'html'): string
- {
- $wallet = new Wallet();
- $user = new User();
-
- $mail = new self($wallet, $user);
-
- return Helper::render($mail, $type);
- }
-}
diff --git a/src/app/Mail/SuspendedDebtor.php b/src/app/Mail/SuspendedDebtor.php
deleted file mode 100644
index 0840b935..00000000
--- a/src/app/Mail/SuspendedDebtor.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-
-namespace App\Mail;
-
-use App\Tenant;
-use App\User;
-use App\Utils;
-use Illuminate\Bus\Queueable;
-use Illuminate\Mail\Mailable;
-use Illuminate\Queue\SerializesModels;
-
-class SuspendedDebtor extends Mailable
-{
- use Queueable;
- use SerializesModels;
-
- /** @var \App\User A suspended user (account) */
- protected $account;
-
-
- /**
- * Create a new message instance.
- *
- * @param \App\User $account A suspended user (account)
- *
- * @return void
- */
- public function __construct(User $account)
- {
- $this->account = $account;
- }
-
- /**
- * Build the message.
- *
- * @return $this
- */
- public function build()
- {
- $appName = Tenant::getConfig($this->account->tenant_id, 'app.name');
- $supportUrl = Tenant::getConfig($this->account->tenant_id, 'app.support_url');
- $cancelUrl = Tenant::getConfig($this->account->tenant_id, 'app.kb.account_delete');
-
- $subject = \trans('mail.suspendeddebtor-subject', ['site' => $appName]);
-
- $moreInfoHtml = null;
- $moreInfoText = null;
- if ($moreInfoUrl = Tenant::getConfig($this->account->tenant_id, 'app.kb.account_suspended')) {
- $moreInfoHtml = \trans('mail.more-info-html', ['href' => $moreInfoUrl]);
- $moreInfoText = \trans('mail.more-info-text', ['href' => $moreInfoUrl]);
- }
-
- $this->view('emails.html.suspended_debtor')
- ->text('emails.plain.suspended_debtor')
- ->subject($subject)
- ->with([
- 'site' => $appName,
- 'subject' => $subject,
- 'username' => $this->account->name(true),
- 'cancelUrl' => $cancelUrl,
- 'supportUrl' => Utils::serviceUrl($supportUrl, $this->account->tenant_id),
- 'walletUrl' => Utils::serviceUrl('/wallet', $this->account->tenant_id),
- 'moreInfoHtml' => $moreInfoHtml,
- 'moreInfoText' => $moreInfoText,
- 'days' => 14 // TODO: Configurable
- ]);
-
- return $this;
- }
-
- /**
- * Render the mail template with fake data
- *
- * @param string $type Output format ('html' or 'text')
- *
- * @return string HTML or Plain Text output
- */
- public static function fakeRender(string $type = 'html'): string
- {
- $user = new User();
-
- $mail = new self($user);
-
- return Helper::render($mail, $type);
- }
-}
diff --git a/src/resources/lang/en/mail.php b/src/resources/lang/en/mail.php
index 6ee4b9eb..62a3fc80 100644
--- a/src/resources/lang/en/mail.php
+++ b/src/resources/lang/en/mail.php
@@ -1,123 +1,102 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Mail Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used in mail/sms messages sent by the app.
*/
'header' => "Dear :name,",
'footer1' => "Best regards,",
'footer2' => "Your :site Team",
'more-info-html' => "See <a href=\":href\">here</a> for more information.",
'more-info-text' => "See :href for more information.",
'degradedaccountreminder-subject' => ":site Reminder: Your account is free",
'degradedaccountreminder-body1' => "Thanks for sticking around, we remind you your account is a free "
. "account and restricted to receiving email, and use of the web client and cockpit only.",
'degradedaccountreminder-body2' => "This leaves you with an ideal account to use for account registration with third parties "
. "and password resets, notifications or even just subscriptions to newsletters and the like.",
'degradedaccountreminder-body3' => "To regain functionality such as sending email, calendars, address books, phone synchronization "
. "and voice & video conferencing, log on to the cockpit and make sure you have a positive account balance.",
'degradedaccountreminder-body4' => "You can also delete your account there, making sure your data disappears from our systems.",
'degradedaccountreminder-body5' => "Thank you for your consideration!",
'negativebalance-subject' => ":site Payment Required",
'negativebalance-body' => "This is a notification to let you know that your :site account balance has run into the negative and requires your attention. "
. "Consider setting up an automatic payment to avoid messages like this in the future.",
'negativebalance-body-ext' => "Settle up to keep your account running:",
'negativebalancereminder-subject' => ":site Payment Reminder",
'negativebalancereminder-body' => "It has probably skipped your attention that you are behind on paying for your :site account. "
. "Consider setting up an automatic payment to avoid messages like this in the future.",
'negativebalancereminder-body-ext' => "Settle up to keep your account running:",
- 'negativebalancereminder-body-warning' => "Please, be aware that your account will be suspended "
- . "if your account balance is not settled by :date.",
'negativebalancereminderdegrade-body-warning' => "Please, be aware that your account will be degraded "
. "if your account balance is not settled by :date.",
'negativebalancedegraded-subject' => ":site Account Degraded",
'negativebalancedegraded-body' => "Your :site account has been degraded for having a negative balance for too long. "
. "Consider setting up an automatic payment to avoid messages like this in the future.",
'negativebalancedegraded-body-ext' => "Settle up now to undegrade your account:",
- 'negativebalancesuspended-subject' => ":site Account Suspended",
- 'negativebalancesuspended-body' => "Your :site account has been suspended for having a negative balance for too long. "
- . "Consider setting up an automatic payment to avoid messages like this in the future.",
- 'negativebalancesuspended-body-ext' => "Settle up now to unsuspend your account:",
- 'negativebalancesuspended-body-warning' => "Please, be aware that your account and all its data will be deleted "
- . "if your account balance is not settled by :date.",
-
- 'negativebalancebeforedelete-subject' => ":site Final Warning",
- 'negativebalancebeforedelete-body' => "This is a final reminder to settle your :site account balance. "
- . "Your account and all its data will be deleted if your account balance is not settled by :date.",
- 'negativebalancebeforedelete-body-ext' => "Settle up now to keep your account:",
-
'passwordreset-subject' => ":site Password Reset",
'passwordreset-body1' => "Someone recently asked to change your :site password.",
'passwordreset-body2' => "If this was you, use this verification code to complete the process:",
'passwordreset-body3' => "You can also click the link below:",
'passwordreset-body4' => "If you did not make such a request, you can either ignore this message or get in touch with us about this incident.",
'passwordexpiration-subject' => ":site password expires on :date",
'passwordexpiration-body' => "Your password will expire on :date. You can change it here:",
'paymentmandatedisabled-subject' => ":site Auto-payment Problem",
'paymentmandatedisabled-body' => "Your :site account balance is negative "
. "and the configured amount for automatically topping up the balance does not cover "
. "the costs of subscriptions consumed.",
'paymentmandatedisabled-body-ext' => "Charging you multiple times for the same amount in short succession "
. "could lead to issues with the payment provider. "
. "In order to not cause any problems, we suspended auto-payment for your account. "
. "To resolve this issue, login to your account settings and adjust your auto-payment amount.",
'paymentfailure-subject' => ":site Payment Failed",
'paymentfailure-body' => "Something went wrong with auto-payment for your :site account.\n"
. "We tried to charge you via your preferred payment method, but the charge did not go through.",
'paymentfailure-body-ext' => "In order to not cause any further issues, we suspended auto-payment for your account. "
. "To resolve this issue, login to your account settings at",
'paymentfailure-body-rest' => "There you can pay manually for your account and "
. "change your auto-payment settings.",
'paymentsuccess-subject' => ":site Payment Succeeded",
'paymentsuccess-body' => "The auto-payment for your :site account went through without issues. "
. "You can check your new account balance and more details here:",
'support' => "Special circumstances? Something is wrong with a charge?\n"
. ":site Support is here to help.",
'signupcode-subject' => ":site Registration",
'signupcode-body1' => "This is your verification code for the :site registration process:",
'signupcode-body2' => "You can also click the link below to continue the registration process:",
'signupinvitation-subject' => ":site Invitation",
'signupinvitation-header' => "Hi,",
'signupinvitation-body1' => "You have been invited to join :site. Click the link below to sign up.",
'signupinvitation-body2' => "",
- 'suspendeddebtor-subject' => ":site Account Suspended",
- 'suspendeddebtor-body' => "You have been behind on paying for your :site account "
- . "for over :days days. Your account has been suspended.",
- 'suspendeddebtor-middle' => "Settle up now to reactivate your account.",
- 'suspendeddebtor-cancel' => "Don't want to be our customer anymore? "
- . "Here is how you can cancel your account:",
-
'trialend-subject' => ":site: Your trial phase has ended",
'trialend-intro' => "We hope you enjoyed the 30 days of free :site trial."
. " Your subscriptions become active after the first month of use and the fee is due after another month.",
'trialend-kb' => "You can read about how to pay the subscription fee in this knowledge base article:",
'trialend-body1' => "You can leave :site at any time, there is no contractual minimum period"
. " and your account will NOT be deleted automatically."
. " You can delete your account via the red [Delete account] button in your profile."
. " This will end your subscription and delete all relevant data.",
'trialend-body2' => "THIS OPERATION IS IRREVERSIBLE!",
'trialend-body3' => "When data is deleted it can not be recovered."
. " Please make sure that you have saved all data that you need before pressing the red button."
. " Do not hesitate to contact Support with any questions or concerns.",
];
diff --git a/src/resources/lang/fr/mail.php b/src/resources/lang/fr/mail.php
index bafbb111..59fe8da1 100644
--- a/src/resources/lang/fr/mail.php
+++ b/src/resources/lang/fr/mail.php
@@ -1,108 +1,87 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Mail Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used in mail/sms messages sent by the app.
*/
'header' => "Salut :name,",
'footer1' => "Meilleures salutations,",
'footer2' => "Votre :site Équipe",
'more-info-html' => "Cliquez <a href=\":href\">ici</a> pour plus d'information.",
'more-info-text' => "Cliquez :href pour plus d'information.",
'degradedaccountreminder-subject' => "Rappel du :site: Votre compte est gratuit",
'degradedaccountreminder-body1' => "Merci de ne pas quitter le site, nous vous rappelons que votre compte est gratuit."
. " et limité à la réception d'emails, et à l'utilisation du client web et du cockpit uniquement.",
'degradedaccountreminder-body2' => "Vous disposez ainsi d'un compte idéal à employer pour l'enregistrement de comptes auprès de tiers"
. " et les réinitialisations de mot de passe, les notifications ou même simplement les souscriptions aux newsletters et autres.",
'degradedaccountreminder-body3' => "Pour récupérer les fonctionnalités telles que l'envoi de e-mail, les calendriers, les carnets d'adresses et la synchronisation des téléphones"
. " et les voix et vidéoconférences, connectez-vous au cockpit et assurez-vous que le solde de votre compte est positif.",
'degradedaccountreminder-body4' => "Vous pouvez également y supprimer votre compte, afin que vos données disparaissent de nos systèmes.",
'degradedaccountreminder-body5' => "Nous apprécions votre collaboration!",
'negativebalance-subject' => ":site Paiement Requis",
'negativebalance-body' => "C'est une notification pour vous informer que votre :site le solde du compte est en négatif et nécessite votre attention."
. " Veillez à mettre en place un auto-paiement pour éviter de tel avertissement comme celui-ci dans le future.",
'negativebalance-body-ext' => "Régler votre compte pour le maintenir en fontion:",
'negativebalancereminder-subject' => ":site Rappel de Paiement",
'negativebalancereminder-body' => "Vous n'avez peut-être pas rendu compte que vous êtes en retard avec votre paiement pour :site compte."
. " Veillez à mettre en place un auto-paiement pour éviter de tel avertissement comme celui-ci dans le future.",
'negativebalancereminder-body-ext' => "Régler votre compte pour le maintenir en fontion:",
- 'negativebalancereminder-body-warning' => "Soyez conscient que votre compte sera suspendu si le"
- . " solde de votre compte n'est réglé avant le :date.",
-
- 'negativebalancesuspended-subject' => ":site Compte Suspendu",
- 'negativebalancesuspended-body' => "Votre :site compte a été suspendu à la suite d'un solde négatif pendant trop longtemps."
- . " Veillez nvisager de mettre en place un auto-paiement pour éviter de tel avertissement comme celui-ci dans le future.",
- 'negativebalancesuspended-body-ext' => "Régler votre compte pour le maintenir en fontion:",
- 'negativebalancesuspended-body-warning' => "Veuillez vous assurer que votre compte et toutes ses données seront supprimés"
- . " si le solde de votre compte n'est pas réglé avant le :date.",
-
- 'negativebalancebeforedelete-subject' => ":site Dernier Avertissement",
- 'negativebalancebeforedelete-body' => "Ceci-ci est le dernier rappel pour régler votre :site solde de compte."
- . " votre compte et toutes ses données seront supprimés si le solde de votre compte nest pas régler avant le :date.",
- 'negativebalancebeforedelete-body-ext' => "Régler votre compte immédiatement:",
'negativebalancereminderdegrade-body-warning' => "Veuillez noter que votre compte sera dégradé"
. " si le solde de votre compte n'est pas réglé avant le :date.",
'negativebalancedegraded-subject' => ":site de Compte Dégradé",
'negativebalancedegraded-body' => "Votre compte :site a été dégradé pour avoir un solde négatif depuis trop longtemps."
. " Envisagez de mettre en place un paiement automatique pour éviter des messages comme celui-ci à l'avenir.",
'negativebalancedegraded-body-ext' => "Réglez maintenant pour rétablir votre compte:",
'passwordreset-subject' => ":site Réinitialisation du mot de passe",
'passwordreset-body1' => "Quelqu'un a récemment demandé de changer votre :site mot de passe.",
'passwordreset-body2' => "Si vous êtes dans ce cas, veuillez utiliser ce code de vérification pour terminer le processus:",
'passwordreset-body3' => "Vous pourrez également cliquer sur le lien ci-dessous:",
'passwordreset-body4' => "si vous n'avez pas fait une telle demande, vous pouvez soit ignorer ce message, soit prendre contact avec nous au sujet de cet incident.",
'paymentmandatedisabled-subject' => ":site Problème d'auto-paiement",
'paymentmandatedisabled-body' => "Votre :site solde du compte est négatif"
. " et le montant configuré pour le rechargement automatique du solde ne suffit pas"
. " le coût des abonnements consommés.",
'paymentmandatedisabled-body-ext' => "En vous facturant plusieurs fois le même monant dans un court laps de temps"
. " peut entraîner des problêmes avec le fournisseur du service de paiement."
. " Pour éviter tout problème, nous avons suspendu l'auto-paiement pour votre compte."
. " Pour resourdre le problème,veuillez vous connecter aux paramètres de votre compte et modifier le montant d'auto-paiement.",
'paymentfailure-subject' => ":site Paiement Echoué",
'paymentfailure-body' => "Un problème est survenu avec l'auto-paiement pour votre :site account.\n"
. "Nous avons tenté de vous facturer via votre méthode de paiement choisie, mais le chargement n'a pas été effectué.",
'paymentfailure-body-ext' => "Pour éviter tout problème supplémentaire, nous avons suspendu l'auto-paiement sur votre compte."
. " Pour resourdre le problème,veuillez vous connecter aux paramètres de votre compte au",
'paymentfailure-body-rest' => "Vous y trouverez la possibilité de payer manuellement votre compte et"
. " de modifier vos paramètres d'auto-paiement.",
'paymentsuccess-subject' => ":site Paiement Effectué",
'paymentsuccess-body' => "L'auto-paiement pour votre :site le compte s'est exécuté sans problème. "
. "Vous pouvez contrôler le solde de votre nouveau compte et obtenir plus de détails ici:",
'support' => "Cas particulier? Il y a un probléme avec une charge?\n"
. ":site Le support reste à votre disposition.",
'signupcode-subject' => ":site Enregistrement",
'signupcode-body1' => "Voici votre code de vérification pour le :site registration process:",
'signupcode-body2' => "Vous pouvez également continuer avec le processus d'enregistrement en cliquant sur le lien ci-dessous:",
'signupinvitation-subject' => ":site Invitation",
'signupinvitation-header' => "Salut,",
'signupinvitation-body1' => "Vous êtes invité à joindre :site. Cliquez sur le lien ci-dessous pour vous inscrire.",
'signupinvitation-body2' => "",
- 'suspendeddebtor-subject' => ":site Compte Suspendu",
- 'suspendeddebtor-body' => "Vous êtes en retard avec le paiement de votre :site compte"
- . " pour plus de :days jours. Votre compte est suspendu.",
- 'suspendeddebtor-middle' => "Réglez immédiatement pour réactiver votre compte.",
- 'suspendeddebtor-cancel' => "Vous ne souhaitez plus être notre client?"
- . " Voici la démarche à suivre pour annuler votre compte:",
-
];
diff --git a/src/resources/views/emails/html/negative_balance_before_delete.blade.php b/src/resources/views/emails/html/negative_balance_before_delete.blade.php
deleted file mode 100644
index ee5b5476..00000000
--- a/src/resources/views/emails/html/negative_balance_before_delete.blade.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
- <head>
- <meta charset="utf-8">
- </head>
- <body>
- <p>{{ __('mail.header', ['name' => $username]) }}</p>
-
- <p>{{ __('mail.negativebalancebeforedelete-body', ['site' => $site, 'date' => $date]) }}</p>
- <p>{{ __('mail.negativebalancebeforedelete-body-ext', ['site' => $site]) }}</p>
- <p><a href="{{ $walletUrl }}">{{ $walletUrl }}</a></p>
-
-@if ($supportUrl)
- <p>{{ __('mail.support', ['site' => $site]) }}</p>
- <p><a href="{{ $supportUrl }}">{{ $supportUrl }}</a></p>
-@endif
-
- <p>{{ __('mail.footer1') }}</p>
- <p>{{ __('mail.footer2', ['site' => $site]) }}</p>
- </body>
-</html>
diff --git a/src/resources/views/emails/html/negative_balance_reminder.blade.php b/src/resources/views/emails/html/negative_balance_reminder.blade.php
deleted file mode 100644
index 876bd023..00000000
--- a/src/resources/views/emails/html/negative_balance_reminder.blade.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
- <head>
- <meta charset="utf-8">
- </head>
- <body>
- <p>{{ __('mail.header', ['name' => $username]) }}</p>
-
- <p>{{ __('mail.negativebalancereminder-body', ['site' => $site]) }}</p>
- <p>{{ __('mail.negativebalancereminder-body-ext', ['site' => $site]) }}</p>
- <p><a href="{{ $walletUrl }}">{{ $walletUrl }}</a></p>
- <p><b>{{ __('mail.negativebalancereminder-body-warning', ['site' => $site, 'date' => $date]) }}</b></p>
-
-@if ($supportUrl)
- <p>{{ __('mail.support', ['site' => $site]) }}</p>
- <p><a href="{{ $supportUrl }}">{{ $supportUrl }}</a></p>
-@endif
-
- <p>{{ __('mail.footer1') }}</p>
- <p>{{ __('mail.footer2', ['site' => $site]) }}</p>
- </body>
-</html>
diff --git a/src/resources/views/emails/html/negative_balance_suspended.blade.php b/src/resources/views/emails/html/negative_balance_suspended.blade.php
deleted file mode 100644
index 6fde9c19..00000000
--- a/src/resources/views/emails/html/negative_balance_suspended.blade.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html>
-<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
- <head>
- <meta charset="utf-8">
- </head>
- <body>
- <p>{{ __('mail.header', ['name' => $username]) }}</p>
-
- <p>{{ __('mail.negativebalancesuspended-body', ['site' => $site]) }}</p>
- <p>{{ __('mail.negativebalancesuspended-body-ext', ['site' => $site]) }}</p>
- <p><a href="{{ $walletUrl }}">{{ $walletUrl }}</a></p>
- <p><b>{{ __('mail.negativebalancesuspended-body-warning', ['site' => $site, 'date' => $date]) }}</b></p>
-
-@if ($supportUrl)
- <p>{{ __('mail.support', ['site' => $site]) }}</p>
- <p><a href="{{ $supportUrl }}">{{ $supportUrl }}</a></p>
-@endif
-
- <p>{{ __('mail.footer1') }}</p>
- <p>{{ __('mail.footer2', ['site' => $site]) }}</p>
- </body>
-</html>
diff --git a/src/resources/views/emails/html/suspended_debtor.blade.php b/src/resources/views/emails/html/suspended_debtor.blade.php
deleted file mode 100644
index 61453a0a..00000000
--- a/src/resources/views/emails/html/suspended_debtor.blade.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
- <head>
- <meta charset="utf-8">
- </head>
- <body>
- <p>{{ __('mail.header', ['name' => $username]) }}</p>
-
- <p>{{ __('mail.suspendeddebtor-body', ['site' => $site, 'days' => $days]) }} {!! $moreInfoHtml !!}</p>
- <p>{{ __('mail.suspendeddebtor-middle') }}</p>
- <p><a href="{{ $walletUrl }}">{{ $walletUrl }}</a></p>
-
-@if ($supportUrl)
- <p>{{ __('mail.support', ['site' => $site]) }}</p>
- <p><a href="{{ $supportUrl }}">{{ $supportUrl }}</a></p>
-@endif
-@if ($cancelUrl)
- <p>{{ __('mail.suspendeddebtor-cancel') }}</p>
- <p><a href="{{ $cancelUrl }}">{{ $cancelUrl }}</a></p>
-@endif
-
- <p>{{ __('mail.footer1') }}</p>
- <p>{{ __('mail.footer2', ['site' => $site]) }}</p>
- </body>
-</html>
diff --git a/src/resources/views/emails/plain/negative_balance_before_delete.blade.php b/src/resources/views/emails/plain/negative_balance_before_delete.blade.php
deleted file mode 100644
index 29a76169..00000000
--- a/src/resources/views/emails/plain/negative_balance_before_delete.blade.php
+++ /dev/null
@@ -1,17 +0,0 @@
-{!! __('mail.header', ['name' => $username]) !!}
-
-{!! __('mail.negativebalancebeforedelete-body', ['site' => $site, 'date' => $date]) !!}
-
-{!! __('mail.negativebalancebeforedelete-body-ext', ['site' => $site]) !!}
-
-{!! $walletUrl !!}
-
-@if ($supportUrl)
-{!! __('mail.support', ['site' => $site]) !!}
-
-{!! $supportUrl !!}
-@endif
-
---
-{!! __('mail.footer1') !!}
-{!! __('mail.footer2', ['site' => $site]) !!}
diff --git a/src/resources/views/emails/plain/negative_balance_reminder.blade.php b/src/resources/views/emails/plain/negative_balance_reminder.blade.php
deleted file mode 100644
index 6be4f048..00000000
--- a/src/resources/views/emails/plain/negative_balance_reminder.blade.php
+++ /dev/null
@@ -1,19 +0,0 @@
-{!! __('mail.header', ['name' => $username]) !!}
-
-{!! __('mail.negativebalancereminder-body', ['site' => $site]) !!}
-
-{!! __('mail.negativebalancereminder-body-ext', ['site' => $site]) !!}
-
-{!! $walletUrl !!}
-
-{!! __('mail.negativebalancereminder-body-warning', ['site' => $site, 'date' => $date]) !!}
-
-@if ($supportUrl)
-{!! __('mail.support', ['site' => $site]) !!}
-
-{!! $supportUrl !!}
-@endif
-
---
-{!! __('mail.footer1') !!}
-{!! __('mail.footer2', ['site' => $site]) !!}
diff --git a/src/resources/views/emails/plain/negative_balance_suspended.blade.php b/src/resources/views/emails/plain/negative_balance_suspended.blade.php
deleted file mode 100644
index e9049897..00000000
--- a/src/resources/views/emails/plain/negative_balance_suspended.blade.php
+++ /dev/null
@@ -1,19 +0,0 @@
-{!! __('mail.header', ['name' => $username]) !!}
-
-{!! __('mail.negativebalancesuspended-body', ['site' => $site]) !!}
-
-{!! __('mail.negativebalancesuspended-body-ext', ['site' => $site]) !!}
-
-{!! $walletUrl !!}
-
-{!! __('mail.negativebalancesuspended-body-warning', ['site' => $site, 'date' => $date]) !!}
-
-@if ($supportUrl)
-{!! __('mail.support', ['site' => $site]) !!}
-
-{!! $supportUrl !!}
-@endif
-
---
-{!! __('mail.footer1') !!}
-{!! __('mail.footer2', ['site' => $site]) !!}
diff --git a/src/resources/views/emails/plain/suspended_debtor.blade.php b/src/resources/views/emails/plain/suspended_debtor.blade.php
deleted file mode 100644
index c760dc75..00000000
--- a/src/resources/views/emails/plain/suspended_debtor.blade.php
+++ /dev/null
@@ -1,23 +0,0 @@
-{!! __('mail.header', ['name' => $username]) !!}
-
-{!! __('mail.suspendeddebtor-body', ['site' => $site, 'days' => $days]) !!} {!! $moreInfoText !!}
-
-{!! __('mail.suspendeddebtor-middle') !!}
-
-{!! $walletUrl !!}
-
-@if ($supportUrl)
-{!! __('mail.support', ['site' => $site]) !!}
-
-{!! $supportUrl !!}
-@endif
-@if ($cancelUrl)
-
-{!! __('mail.suspendeddebtor-cancel') !!}
-
-{!! $cancelUrl !!}
-@endif
-
---
-{!! __('mail.footer1') !!}
-{!! __('mail.footer2', ['site' => $site]) !!}
diff --git a/src/tests/Feature/Jobs/WalletCheckTest.php b/src/tests/Feature/Jobs/WalletCheckTest.php
index 2822d81b..0c483e47 100644
--- a/src/tests/Feature/Jobs/WalletCheckTest.php
+++ b/src/tests/Feature/Jobs/WalletCheckTest.php
@@ -1,401 +1,305 @@
<?php
namespace Tests\Feature\Jobs;
use App\Jobs\WalletCheck;
use App\User;
use App\Wallet;
use Carbon\Carbon;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
class WalletCheckTest extends TestCase
{
/**
* {@inheritDoc}
*/
public function setUp(): void
{
parent::setUp();
Carbon::setTestNow(Carbon::createFromDate(2022, 02, 02));
$this->deleteTestUser('wallet-check@kolabnow.com');
}
/**
* {@inheritDoc}
*/
public function tearDown(): void
{
$this->deleteTestUser('wallet-check@kolabnow.com');
parent::tearDown();
}
/**
* Test job handle, initial negative-balance notification
*/
public function testHandleInitial(): void
{
Mail::fake();
$user = $this->prepareTestUser($wallet);
$now = Carbon::now();
$wallet->balance = 0;
$wallet->save();
$job = new WalletCheck($wallet);
$job->handle();
Mail::assertNothingSent();
// Balance is negative now
$wallet->balance = -100;
$wallet->save();
$job = new WalletCheck($wallet);
$job->handle();
Mail::assertNothingSent();
// Balance turned negative 2 hours ago, expect mail sent
$wallet->setSetting('balance_negative_since', $now->subHours(2)->toDateTimeString());
$wallet->setSetting('balance_warning_initial', null);
$job = new WalletCheck($wallet);
$job->handle();
// Assert the mail was sent to the user's email, but not to his external email
Mail::assertSent(\App\Mail\NegativeBalance::class, 1);
Mail::assertSent(\App\Mail\NegativeBalance::class, function ($mail) use ($user) {
return $mail->hasTo($user->email) && !$mail->hasCc('external@test.com');
});
// Run the job again to make sure the notification is not sent again
Mail::fake();
$job = new WalletCheck($wallet);
$job->handle();
Mail::assertNothingSent();
// Test the migration scenario where a negative wallet has no balance_negative_since set yet
Mail::fake();
$wallet->setSetting('balance_negative_since', null);
$wallet->setSetting('balance_warning_initial', null);
$job = new WalletCheck($wallet);
$job->handle();
// Assert the mail was sent to the user's email, but not to his external email
Mail::assertSent(\App\Mail\NegativeBalance::class, 1);
Mail::assertSent(\App\Mail\NegativeBalance::class, function ($mail) use ($user) {
return $mail->hasTo($user->email) && !$mail->hasCc('external@test.com');
});
$wallet->refresh();
$today_regexp = '/' . Carbon::now()->toDateString() . ' [0-9]{2}:[0-9]{2}:[0-9]{2}/';
$this->assertMatchesRegularExpression($today_regexp, $wallet->getSetting('balance_negative_since'));
$this->assertMatchesRegularExpression($today_regexp, $wallet->getSetting('balance_warning_initial'));
+
+ // Test suspended user - no mail sent
+ Mail::fake();
+ $wallet->owner->suspend();
+ $wallet->setSetting('balance_warning_initial', null);
+
+ $job = new WalletCheck($wallet);
+ $job->handle();
+
+ Mail::assertNothingSent();
}
/**
* Test job handle, top-up before reminder notification
*
* @depends testHandleInitial
*/
public function testHandleBeforeReminder(): void
{
Mail::fake();
$user = $this->prepareTestUser($wallet);
$now = Carbon::now();
// Balance turned negative 7-1 days ago
$wallet->setSetting('balance_negative_since', $now->subDays(7 - 1)->toDateTimeString());
$job = new WalletCheck($wallet);
$res = $job->handle();
Mail::assertNothingSent();
// TODO: Test that it actually executed the topUpWallet()
$this->assertSame(WalletCheck::THRESHOLD_BEFORE_REMINDER, $res);
- $this->assertFalse($user->fresh()->isSuspended());
}
/**
* Test job handle, reminder notification
*
* @depends testHandleBeforeReminder
*/
public function testHandleReminder(): void
{
Mail::fake();
$user = $this->prepareTestUser($wallet);
$now = Carbon::now();
// Balance turned negative 7+1 days ago, expect mail sent
$wallet->setSetting('balance_negative_since', $now->subDays(7 + 1)->toDateTimeString());
$job = new WalletCheck($wallet);
$job->handle();
// Assert the mail was sent to the user's email and to his external email
Mail::assertSent(\App\Mail\NegativeBalanceReminderDegrade::class, 1);
Mail::assertSent(\App\Mail\NegativeBalanceReminderDegrade::class, function ($mail) use ($user) {
return $mail->hasTo($user->email) && $mail->hasCc('external@test.com');
});
// Run the job again to make sure the notification is not sent again
Mail::fake();
$job = new WalletCheck($wallet);
$job->handle();
Mail::assertNothingSent();
- }
-
- /**
- * Test job handle, top-up wallet before account suspending
- *
- * @depends testHandleReminder
- */
-/*
- public function testHandleBeforeSuspended(): void
- {
- Mail::fake();
-
- $user = $this->prepareTestUser($wallet);
- $now = Carbon::now();
-
- // Balance turned negative 7+14-1 days ago
- $days = 7 + 14 - 1;
- $wallet->setSetting('balance_negative_since', $now->subDays($days)->toDateTimeString());
-
- $job = new WalletCheck($wallet);
- $res = $job->handle();
-
- Mail::assertNothingSent();
-
- // TODO: Test that it actually executed the topUpWallet()
- $this->assertSame(WalletCheck::THRESHOLD_BEFORE_SUSPEND, $res);
- $this->assertFalse($user->fresh()->isSuspended());
- }
-*/
- /**
- * Test job handle, account suspending
- *
- * @depends testHandleBeforeSuspended
- */
-/*
- public function testHandleSuspended(): void
- {
- Mail::fake();
-
- $user = $this->prepareTestUser($wallet);
- $now = Carbon::now();
-
- // Balance turned negative 7+14+1 days ago, expect mail sent
- $days = 7 + 14 + 1;
- $wallet->setSetting('balance_negative_since', $now->subDays($days)->toDateTimeString());
-
- $job = new WalletCheck($wallet);
- $job->handle();
-
- // Assert the mail was sent to the user's email, but not to his external email
- Mail::assertSent(\App\Mail\NegativeBalanceSuspended::class, 1);
- Mail::assertSent(\App\Mail\NegativeBalanceSuspended::class, function ($mail) use ($user) {
- return $mail->hasTo($user->email) && $mail->hasCc('external@test.com');
- });
-
- // Check that it has been suspended
- $this->assertTrue($user->fresh()->isSuspended());
-
- // TODO: Test that group account members/domain are also being suspended
-
- // Run the job again to make sure the notification is not sent again
- Mail::fake();
- $job = new WalletCheck($wallet);
- $job->handle();
-
- Mail::assertNothingSent();
- }
-*/
- /**
- * Test job handle, final warning before delete
- *
- * @depends testHandleSuspended
- */
-/*
- public function testHandleBeforeDelete(): void
- {
- Mail::fake();
-
- $user = $this->prepareTestUser($wallet);
- $now = Carbon::now();
-
- // Balance turned negative 7+14+21-3+1 days ago, expect mail sent
- $days = 7 + 14 + 21 - 3 + 1;
- $wallet->setSetting('balance_negative_since', $now->subDays($days)->toDateTimeString());
-
- $job = new WalletCheck($wallet);
- $job->handle();
- // Assert the mail was sent to the user's email, and his external email
- Mail::assertSent(\App\Mail\NegativeBalanceBeforeDelete::class, 1);
- Mail::assertSent(\App\Mail\NegativeBalanceBeforeDelete::class, function ($mail) use ($user) {
- return $mail->hasTo($user->email) && $mail->hasCc('external@test.com');
- });
-
- // Check that it has not been deleted yet
- $this->assertFalse($user->fresh()->isDeleted());
-
- // Run the job again to make sure the notification is not sent again
+ // Test suspended user - no mail sent
Mail::fake();
- $job = new WalletCheck($wallet);
- $job->handle();
-
- Mail::assertNothingSent();
- }
-*/
- /**
- * Test job handle, account delete
- *
- * @depends testHandleBeforeDelete
- */
-/*
- public function testHandleDelete(): void
- {
- Mail::fake();
-
- $user = $this->prepareTestUser($wallet);
- $now = Carbon::now();
-
- $this->assertFalse($user->isDeleted());
- $this->assertCount(7, $user->entitlements()->get());
-
- // Balance turned negative 7+14+21+1 days ago, expect mail sent
- $days = 7 + 14 + 21 + 1;
- $wallet->setSetting('balance_negative_since', $now->subDays($days)->toDateTimeString());
+ $wallet->owner->suspend();
+ $wallet->setSetting('balance_warning_reminder', null);
$job = new WalletCheck($wallet);
$job->handle();
Mail::assertNothingSent();
-
- // Check that it has not been deleted
- $this->assertTrue($user->fresh()->trashed());
- $this->assertCount(0, $user->entitlements()->get());
-
- // TODO: Test it deletes all members of the group account
}
-*/
/**
* Test job handle, account degrade
*
* @depends testHandleReminder
*/
public function testHandleDegrade(): void
{
Mail::fake();
$user = $this->prepareTestUser($wallet);
$now = Carbon::now();
$this->assertFalse($user->isDegraded());
// Balance turned negative 7+7+1 days ago, expect mail sent
$days = 7 + 7 + 1;
$wallet->setSetting('balance_negative_since', $now->subDays($days)->toDateTimeString());
$job = new WalletCheck($wallet);
$job->handle();
// Assert the mail was sent to the user's email, and his external email
Mail::assertSent(\App\Mail\NegativeBalanceDegraded::class, 1);
Mail::assertSent(\App\Mail\NegativeBalanceDegraded::class, function ($mail) use ($user) {
return $mail->hasTo($user->email) && $mail->hasCc('external@test.com');
});
// Check that it has been degraded
$this->assertTrue($user->fresh()->isDegraded());
+
+ // Test suspended user - no mail sent
+ Mail::fake();
+ $wallet->owner->suspend();
+ $wallet->owner->undegrade();
+
+ $job = new WalletCheck($wallet);
+ $job->handle();
+
+ Mail::assertNothingSent();
}
/**
* Test job handle, periodic reminder to a degraded account
*
* @depends testHandleDegrade
*/
public function testHandleDegradeReminder(): void
{
Mail::fake();
$user = $this->prepareTestUser($wallet);
$user->update(['status' => $user->status | User::STATUS_DEGRADED]);
$now = Carbon::now();
$this->assertTrue($user->isDegraded());
// Test degraded_last_reminder not set
$wallet->setSetting('degraded_last_reminder', null);
$job = new WalletCheck($wallet);
$res = $job->handle();
Mail::assertNothingSent();
$_last = Wallet::find($wallet->id)->getSetting('degraded_last_reminder');
$this->assertSame(Carbon::now()->toDateTimeString(), $_last);
$this->assertSame(WalletCheck::THRESHOLD_DEGRADE_REMINDER, $res);
// Test degraded_last_reminder set, but 14 days didn't pass yet
$last = $now->copy()->subDays(10);
$wallet->setSetting('degraded_last_reminder', $last->toDateTimeString());
$job = new WalletCheck($wallet);
$res = $job->handle();
Mail::assertNothingSent();
$_last = $wallet->fresh()->getSetting('degraded_last_reminder');
$this->assertSame(WalletCheck::THRESHOLD_DEGRADE_REMINDER, $res);
$this->assertSame($last->toDateTimeString(), $_last);
// Test degraded_last_reminder set, and 14 days passed
$wallet->setSetting('degraded_last_reminder', $now->copy()->subDays(14)->setSeconds(0));
$job = new WalletCheck($wallet);
$res = $job->handle();
// Assert the mail was sent to the user's email, and his external email
Mail::assertSent(\App\Mail\DegradedAccountReminder::class, 1);
Mail::assertSent(\App\Mail\DegradedAccountReminder::class, function ($mail) use ($user) {
- return $mail->hasTo($user->email) && $mail->hasCc('external@test.com');
+ return $mail->hasTo($user->email) && !$mail->hasCc('external@test.com');
});
$_last = $wallet->fresh()->getSetting('degraded_last_reminder');
$this->assertSame(Carbon::now()->toDateTimeString(), $_last);
$this->assertSame(WalletCheck::THRESHOLD_DEGRADE_REMINDER, $res);
+
+ // Test suspended user - no mail sent
+ Mail::fake();
+ $wallet->owner->suspend();
+ $wallet->owner->undegrade();
+ $wallet->setSetting('degraded_last_reminder', null);
+
+ $job = new WalletCheck($wallet);
+ $job->handle();
+
+ Mail::assertNothingSent();
}
/**
* A helper to prepare a user for tests
*/
private function prepareTestUser(&$wallet)
{
$status = User::STATUS_ACTIVE | User::STATUS_LDAP_READY | User::STATUS_IMAP_READY;
$user = $this->getTestUser('wallet-check@kolabnow.com', ['status' => $status]);
$user->setSetting('external_email', 'external@test.com');
$wallet = $user->wallets()->first();
$package = \App\Package::withObjectTenantContext($user)->where('title', 'kolab')->first();
$user->assignPackage($package);
$wallet->balance = -100;
$wallet->save();
return $user;
}
}
diff --git a/src/tests/Unit/Mail/NegativeBalanceBeforeDeleteTest.php b/src/tests/Unit/Mail/NegativeBalanceBeforeDeleteTest.php
deleted file mode 100644
index 3385b0ab..00000000
--- a/src/tests/Unit/Mail/NegativeBalanceBeforeDeleteTest.php
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-
-namespace Tests\Unit\Mail;
-
-use App\Jobs\WalletCheck;
-use App\Mail\NegativeBalanceBeforeDelete;
-use App\User;
-use App\Wallet;
-use Tests\TestCase;
-
-class NegativeBalanceBeforeDeleteTest extends TestCase
-{
- /**
- * {@inheritDoc}
- */
- public function setUp(): void
- {
- parent::setUp();
-
- \App\TenantSetting::truncate();
- }
-
- /**
- * {@inheritDoc}
- */
- public function tearDown(): void
- {
- \App\TenantSetting::truncate();
-
- parent::tearDown();
- }
-
- /**
- * Test email content
- */
- public function testBuild(): void
- {
- $user = $this->getTestUser('ned@kolab.org');
- $wallet = $user->wallets->first();
- $wallet->balance = -100;
- $wallet->save();
-
- $threshold = WalletCheck::threshold($wallet, WalletCheck::THRESHOLD_DELETE);
-
- \config([
- 'app.support_url' => 'https://kolab.org/support',
- ]);
-
- $mail = $this->renderMail(new NegativeBalanceBeforeDelete($wallet, $user));
-
- $html = $mail['html'];
- $plain = $mail['plain'];
-
- $walletUrl = \App\Utils::serviceUrl('/wallet');
- $walletLink = sprintf('<a href="%s">%s</a>', $walletUrl, $walletUrl);
- $supportUrl = \config('app.support_url');
- $supportLink = sprintf('<a href="%s">%s</a>', $supportUrl, $supportUrl);
- $appName = $user->tenant->title;
-
- $this->assertSame("$appName Final Warning", $mail['subject']);
-
- $this->assertStringStartsWith('<!DOCTYPE html>', $html);
- $this->assertTrue(strpos($html, $user->name(true)) > 0);
- $this->assertTrue(strpos($html, $walletLink) > 0);
- $this->assertTrue(strpos($html, $supportLink) > 0);
- $this->assertTrue(strpos($html, "This is a final reminder to settle your $appName") > 0);
- $this->assertTrue(strpos($html, $threshold->toDateString()) > 0);
- $this->assertTrue(strpos($html, "$appName Support") > 0);
- $this->assertTrue(strpos($html, "$appName Team") > 0);
-
- $this->assertStringStartsWith('Dear ' . $user->name(true), $plain);
- $this->assertTrue(strpos($plain, $walletUrl) > 0);
- $this->assertTrue(strpos($plain, $supportUrl) > 0);
- $this->assertTrue(strpos($plain, "This is a final reminder to settle your $appName") > 0);
- $this->assertTrue(strpos($plain, $threshold->toDateString()) > 0);
- $this->assertTrue(strpos($plain, "$appName Support") > 0);
- $this->assertTrue(strpos($plain, "$appName Team") > 0);
-
- // Test with user that is not the same tenant as in .env
- $user = $this->getTestUser('user@sample-tenant.dev-local');
- $tenant = $user->tenant;
- $wallet = $user->wallets->first();
- $wallet->balance = -100;
- $wallet->save();
-
- $threshold = WalletCheck::threshold($wallet, WalletCheck::THRESHOLD_DELETE);
-
- $tenant->setSettings([
- 'app.support_url' => 'https://test.org/support',
- 'app.public_url' => 'https://test.org',
- ]);
-
- $mail = $this->renderMail(new NegativeBalanceBeforeDelete($wallet, $user));
-
- $html = $mail['html'];
- $plain = $mail['plain'];
-
- $walletUrl = 'https://test.org/wallet';
- $walletLink = sprintf('<a href="%s">%s</a>', $walletUrl, $walletUrl);
- $supportUrl = 'https://test.org/support';
- $supportLink = sprintf('<a href="%s">%s</a>', $supportUrl, $supportUrl);
-
- $this->assertSame("{$tenant->title} Final Warning", $mail['subject']);
-
- $this->assertStringStartsWith('<!DOCTYPE html>', $html);
- $this->assertTrue(strpos($html, $user->name(true)) > 0);
- $this->assertTrue(strpos($html, $walletLink) > 0);
- $this->assertTrue(strpos($html, $supportLink) > 0);
- $this->assertTrue(strpos($html, "This is a final reminder to settle your {$tenant->title}") > 0);
- $this->assertTrue(strpos($html, $threshold->toDateString()) > 0);
- $this->assertTrue(strpos($html, "{$tenant->title} Support") > 0);
- $this->assertTrue(strpos($html, "{$tenant->title} Team") > 0);
-
- $this->assertStringStartsWith('Dear ' . $user->name(true), $plain);
- $this->assertTrue(strpos($plain, $walletUrl) > 0);
- $this->assertTrue(strpos($plain, $supportUrl) > 0);
- $this->assertTrue(strpos($plain, "This is a final reminder to settle your {$tenant->title}") > 0);
- $this->assertTrue(strpos($plain, $threshold->toDateString()) > 0);
- $this->assertTrue(strpos($plain, "{$tenant->title} Support") > 0);
- $this->assertTrue(strpos($plain, "{$tenant->title} Team") > 0);
- }
-}
diff --git a/src/tests/Unit/Mail/NegativeBalanceReminderTest.php b/src/tests/Unit/Mail/NegativeBalanceReminderTest.php
deleted file mode 100644
index 9a669d77..00000000
--- a/src/tests/Unit/Mail/NegativeBalanceReminderTest.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-namespace Tests\Unit\Mail;
-
-use App\Jobs\WalletCheck;
-use App\Mail\NegativeBalanceReminder;
-use App\User;
-use App\Wallet;
-use Tests\TestCase;
-
-class NegativeBalanceReminderTest extends TestCase
-{
- /**
- * Test email content
- */
- public function testBuild(): void
- {
- $user = $this->getTestUser('ned@kolab.org');
- $wallet = $user->wallets->first();
- $wallet->balance = -100;
- $wallet->save();
-
- $threshold = WalletCheck::threshold($wallet, WalletCheck::THRESHOLD_SUSPEND);
-
- \config([
- 'app.support_url' => 'https://kolab.org/support',
- ]);
-
- $mail = $this->renderMail(new NegativeBalanceReminder($wallet, $user));
-
- $html = $mail['html'];
- $plain = $mail['plain'];
-
- $walletUrl = \App\Utils::serviceUrl('/wallet');
- $walletLink = sprintf('<a href="%s">%s</a>', $walletUrl, $walletUrl);
- $supportUrl = \config('app.support_url');
- $supportLink = sprintf('<a href="%s">%s</a>', $supportUrl, $supportUrl);
- $appName = $user->tenant->title;
-
- $this->assertSame("$appName Payment Reminder", $mail['subject']);
-
- $this->assertStringStartsWith('<!DOCTYPE html>', $html);
- $this->assertTrue(strpos($html, $user->name(true)) > 0);
- $this->assertTrue(strpos($html, $walletLink) > 0);
- $this->assertTrue(strpos($html, $supportLink) > 0);
- $this->assertTrue(strpos($html, "you are behind on paying for your $appName account") > 0);
- $this->assertTrue(strpos($html, $threshold->toDateString()) > 0);
- $this->assertTrue(strpos($html, "$appName Support") > 0);
- $this->assertTrue(strpos($html, "$appName Team") > 0);
-
- $this->assertStringStartsWith('Dear ' . $user->name(true), $plain);
- $this->assertTrue(strpos($plain, $walletUrl) > 0);
- $this->assertTrue(strpos($plain, $supportUrl) > 0);
- $this->assertTrue(strpos($plain, "you are behind on paying for your $appName account") > 0);
- $this->assertTrue(strpos($plain, $threshold->toDateString()) > 0);
- $this->assertTrue(strpos($plain, "$appName Support") > 0);
- $this->assertTrue(strpos($plain, "$appName Team") > 0);
- }
-}
diff --git a/src/tests/Unit/Mail/NegativeBalanceSuspendedTest.php b/src/tests/Unit/Mail/NegativeBalanceSuspendedTest.php
deleted file mode 100644
index 5a3cd110..00000000
--- a/src/tests/Unit/Mail/NegativeBalanceSuspendedTest.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-namespace Tests\Unit\Mail;
-
-use App\Jobs\WalletCheck;
-use App\Mail\NegativeBalanceSuspended;
-use App\User;
-use App\Wallet;
-use Tests\TestCase;
-
-class NegativeBalanceSuspendedTest extends TestCase
-{
- /**
- * Test email content
- */
- public function testBuild(): void
- {
- $user = $this->getTestUser('ned@kolab.org');
- $wallet = $user->wallets->first();
- $wallet->balance = -100;
- $wallet->save();
-
- $threshold = WalletCheck::threshold($wallet, WalletCheck::THRESHOLD_DELETE);
-
- \config([
- 'app.support_url' => 'https://kolab.org/support',
- ]);
-
- $mail = $this->renderMail(new NegativeBalanceSuspended($wallet, $user));
-
- $html = $mail['html'];
- $plain = $mail['plain'];
-
- $walletUrl = \App\Utils::serviceUrl('/wallet');
- $walletLink = sprintf('<a href="%s">%s</a>', $walletUrl, $walletUrl);
- $supportUrl = \config('app.support_url');
- $supportLink = sprintf('<a href="%s">%s</a>', $supportUrl, $supportUrl);
- $appName = $user->tenant->title;
-
- $this->assertSame("$appName Account Suspended", $mail['subject']);
-
- $this->assertStringStartsWith('<!DOCTYPE html>', $html);
- $this->assertTrue(strpos($html, $user->name(true)) > 0);
- $this->assertTrue(strpos($html, $walletLink) > 0);
- $this->assertTrue(strpos($html, $supportLink) > 0);
- $this->assertTrue(strpos($html, "Your $appName account has been suspended") > 0);
- $this->assertTrue(strpos($html, $threshold->toDateString()) > 0);
- $this->assertTrue(strpos($html, "$appName Support") > 0);
- $this->assertTrue(strpos($html, "$appName Team") > 0);
-
- $this->assertStringStartsWith('Dear ' . $user->name(true), $plain);
- $this->assertTrue(strpos($plain, $walletUrl) > 0);
- $this->assertTrue(strpos($plain, $supportUrl) > 0);
- $this->assertTrue(strpos($plain, "Your $appName account has been suspended") > 0);
- $this->assertTrue(strpos($plain, $threshold->toDateString()) > 0);
- $this->assertTrue(strpos($plain, "$appName Support") > 0);
- $this->assertTrue(strpos($plain, "$appName Team") > 0);
- }
-}
diff --git a/src/tests/Unit/Mail/SuspendedDebtorTest.php b/src/tests/Unit/Mail/SuspendedDebtorTest.php
deleted file mode 100644
index 320402cb..00000000
--- a/src/tests/Unit/Mail/SuspendedDebtorTest.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-namespace Tests\Unit\Mail;
-
-use App\Mail\SuspendedDebtor;
-use App\User;
-use Tests\TestCase;
-
-class SuspendedDebtorTest extends TestCase
-{
- /**
- * Test email content
- */
- public function testBuild(): void
- {
- $user = new User();
-
- \config([
- 'app.support_url' => 'https://kolab.org/support',
- 'app.kb.account_suspended' => 'https://kb.kolab.org/account-suspended',
- 'app.kb.account_delete' => 'https://kb.kolab.org/account-delete',
- ]);
-
- $mail = $this->renderMail(new SuspendedDebtor($user));
-
- $html = $mail['html'];
- $plain = $mail['plain'];
-
- $walletUrl = \App\Utils::serviceUrl('/wallet');
- $walletLink = sprintf('<a href="%s">%s</a>', $walletUrl, $walletUrl);
- $supportUrl = \config('app.support_url');
- $supportLink = sprintf('<a href="%s">%s</a>', $supportUrl, $supportUrl);
- $deleteUrl = \config('app.kb.account_delete');
- $deleteLink = sprintf('<a href="%s">%s</a>', $deleteUrl, $deleteUrl);
- $moreUrl = \config('app.kb.account_suspended');
- $moreLink = sprintf('<a href="%s">here</a>', $moreUrl);
- $appName = \config('app.name');
-
- $this->assertSame("$appName Account Suspended", $mail['subject']);
-
- $this->assertStringStartsWith('<!DOCTYPE html>', $html);
- $this->assertTrue(strpos($html, $user->name(true)) > 0);
- $this->assertTrue(strpos($html, $walletLink) > 0);
- $this->assertTrue(strpos($html, $supportLink) > 0);
- $this->assertTrue(strpos($html, $deleteLink) > 0);
- $this->assertTrue(strpos($html, "You have been behind on paying for your $appName account") > 0);
- $this->assertTrue(strpos($html, "over 14 days") > 0);
- $this->assertTrue(strpos($html, "See $moreLink for more information") > 0);
- $this->assertTrue(strpos($html, "$appName Support") > 0);
- $this->assertTrue(strpos($html, "$appName Team") > 0);
-
- $this->assertStringStartsWith('Dear ' . $user->name(true), $plain);
- $this->assertTrue(strpos($plain, $walletUrl) > 0);
- $this->assertTrue(strpos($plain, $supportUrl) > 0);
- $this->assertTrue(strpos($plain, $deleteUrl) > 0);
- $this->assertTrue(strpos($plain, "You have been behind on paying for your $appName account") > 0);
- $this->assertTrue(strpos($plain, "over 14 days") > 0);
- $this->assertTrue(strpos($plain, "See $moreUrl for more information") > 0);
- $this->assertTrue(strpos($plain, "$appName Support") > 0);
- $this->assertTrue(strpos($plain, "$appName Team") > 0);
- }
-}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Nov 20, 12:43 PM (6 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
387153
Default Alt Text
(74 KB)

Event Timeline