mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Adjust email quotas - Hosted plan. (#3663)
* Fixes for invitations not being created in RandomDataSeeder * Resend failed/quota exceeded emails * Queue email tests * Refund a client for a ninja account * Adjust email quotas - hosted plan
This commit is contained in:
parent
a70f42b31e
commit
c503d58505
@ -12,7 +12,9 @@
|
|||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
use App\Jobs\Cron\RecurringInvoicesCron;
|
use App\Jobs\Cron\RecurringInvoicesCron;
|
||||||
|
use App\Jobs\Util\AdjustEmailQuota;
|
||||||
use App\Jobs\Util\ReminderJob;
|
use App\Jobs\Util\ReminderJob;
|
||||||
|
use App\Jobs\Util\SendFailedEmails;
|
||||||
use App\Jobs\Util\VersionCheck;
|
use App\Jobs\Util\VersionCheck;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
@ -43,6 +45,11 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
$schedule->job(new ReminderJob)->daily();
|
$schedule->job(new ReminderJob)->daily();
|
||||||
|
|
||||||
|
/* Run hosted specific jobs */
|
||||||
|
if(Ninja::isHosted()) {
|
||||||
|
$schedule->json()->daily(new AdjustEmailQuota())->daily;
|
||||||
|
$schedule->job(new SendFailedEmails())->daily();
|
||||||
|
}
|
||||||
/* Run queue's in shared hosting with this*/
|
/* Run queue's in shared hosting with this*/
|
||||||
if (Ninja::isSelfHost()) {
|
if (Ninja::isSelfHost()) {
|
||||||
$schedule->command('queue:work')->everyMinute()->withoutOverlapping();
|
$schedule->command('queue:work')->everyMinute()->withoutOverlapping();
|
||||||
|
37
app/DataMapper/EmailSpooledForSend.php
Normal file
37
app/DataMapper/EmailSpooledForSend.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\DataMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EmailSpooledForSend
|
||||||
|
*
|
||||||
|
* Stubbed class used to store the meta data
|
||||||
|
* for an email that was unable to be sent
|
||||||
|
* for a reason such as:
|
||||||
|
*
|
||||||
|
* - Quota exceeded
|
||||||
|
* - SMTP issues
|
||||||
|
* - Upstream connectivity
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class EmailSpooledForSend
|
||||||
|
{
|
||||||
|
public $entity_name;
|
||||||
|
|
||||||
|
public $invitation_key = '';
|
||||||
|
|
||||||
|
public $reminder_template = '';
|
||||||
|
|
||||||
|
public $subject = '';
|
||||||
|
|
||||||
|
public $body = '';
|
||||||
|
}
|
@ -9,16 +9,16 @@ use League\CommonMark\CommonMarkConverter;
|
|||||||
|
|
||||||
class EmailBuilder
|
class EmailBuilder
|
||||||
{
|
{
|
||||||
protected $subject;
|
public $subject;
|
||||||
protected $body;
|
public $body;
|
||||||
protected $recipients;
|
public $recipients;
|
||||||
protected $attachments;
|
public $attachments;
|
||||||
protected $footer;
|
public $footer;
|
||||||
protected $template_style;
|
public $template_style;
|
||||||
protected $variables = [];
|
public $variables = [];
|
||||||
protected $contact = null;
|
public $contact = null;
|
||||||
protected $view_link;
|
public $view_link;
|
||||||
protected $view_text;
|
public $view_text;
|
||||||
|
|
||||||
private function parseTemplate(string $data, bool $is_markdown = true, $contact = null): string
|
private function parseTemplate(string $data, bool $is_markdown = true, $contact = null): string
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,7 @@ use App\Http\Requests\Company\UpdateCompanyRequest;
|
|||||||
use App\Http\Requests\SignupRequest;
|
use App\Http\Requests\SignupRequest;
|
||||||
use App\Jobs\Company\CreateCompany;
|
use App\Jobs\Company\CreateCompany;
|
||||||
use App\Jobs\Company\CreateCompanyToken;
|
use App\Jobs\Company\CreateCompanyToken;
|
||||||
|
use App\Jobs\Ninja\RefundCancelledAccount;
|
||||||
use App\Jobs\RegisterNewAccount;
|
use App\Jobs\RegisterNewAccount;
|
||||||
use App\Jobs\Util\UploadAvatar;
|
use App\Jobs\Util\UploadAvatar;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
@ -30,6 +31,7 @@ use App\Repositories\CompanyRepository;
|
|||||||
use App\Transformers\AccountTransformer;
|
use App\Transformers\AccountTransformer;
|
||||||
use App\Transformers\CompanyTransformer;
|
use App\Transformers\CompanyTransformer;
|
||||||
use App\Transformers\CompanyUserTransformer;
|
use App\Transformers\CompanyUserTransformer;
|
||||||
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use App\Utils\Traits\Uploadable;
|
use App\Utils\Traits\Uploadable;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
@ -460,15 +462,21 @@ class CompanyController extends BaseController
|
|||||||
public function destroy(DestroyCompanyRequest $request, Company $company)
|
public function destroy(DestroyCompanyRequest $request, Company $company)
|
||||||
{
|
{
|
||||||
$company_count = $company->account->companies->count();
|
$company_count = $company->account->companies->count();
|
||||||
|
$account = $company->account;
|
||||||
|
|
||||||
if ($company_count == 1) {
|
if ($company_count == 1) {
|
||||||
|
|
||||||
$company->company_users->each(function ($company_user) {
|
$company->company_users->each(function ($company_user) {
|
||||||
$company_user->user->forceDelete();
|
$company_user->user->forceDelete();
|
||||||
});
|
});
|
||||||
|
|
||||||
$company->account->delete();
|
if(Ninja::isHosted())
|
||||||
|
RefundCancelledAccount::dispatchNow($account);
|
||||||
|
|
||||||
|
$account->delete();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$account = $company->account;
|
|
||||||
$company_id = $company->id;
|
$company_id = $company->id;
|
||||||
$company->delete();
|
$company->delete();
|
||||||
|
|
||||||
@ -480,11 +488,6 @@ class CompanyController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//@todo delete documents also!!
|
|
||||||
|
|
||||||
//@todo in the hosted version deleting the last
|
|
||||||
//account will trigger an account refund.
|
|
||||||
|
|
||||||
return response()->json(['message' => 'success'], 200);
|
return response()->json(['message' => 'success'], 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ class ShowInvoiceRequest extends Request
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public function authorize() : bool
|
public function authorize() : bool
|
||||||
{info(auth('contact')->user()->client->id);
|
{
|
||||||
info($this->invoice->client_id);
|
|
||||||
return auth('contact')->user()->client->id === $this->invoice->client_id;
|
return auth('contact')->user()->client->id === $this->invoice->client_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ class EmailCredit implements ShouldQueue
|
|||||||
$template_style = $this->credit->client->getSetting('email_style');
|
$template_style = $this->credit->client->getSetting('email_style');
|
||||||
|
|
||||||
$this->credit->invitations->each(function ($invitation) use ($template_style) {
|
$this->credit->invitations->each(function ($invitation) use ($template_style) {
|
||||||
if ($invitation->contact->send && $invitation->contact->email) {
|
if ($invitation->contact->send_email && $invitation->contact->email) {
|
||||||
$message_array = $this->credit->getEmailData('', $invitation->contact);
|
$message_array = $this->credit->getEmailData('', $invitation->contact);
|
||||||
$message_array['title'] = &$message_array['subject'];
|
$message_array['title'] = &$message_array['subject'];
|
||||||
$message_array['footer'] = "Sent to ".$invitation->contact->present()->name();
|
$message_array['footer'] = "Sent to ".$invitation->contact->present()->name();
|
||||||
|
@ -100,7 +100,7 @@ class CreateUbl implements ShouldQueue
|
|||||||
try {
|
try {
|
||||||
return Generator::invoice($ubl_invoice, $invoice->client->getCurrencyCode());
|
return Generator::invoice($ubl_invoice, $invoice->client->getCurrencyCode());
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
info(print_r($exception, 1));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
80
app/Jobs/Ninja/AdjustEmailQuota.php
Normal file
80
app/Jobs/Ninja/AdjustEmailQuota.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
use App\Helpers\Email\InvoiceEmail;
|
||||||
|
use App\Jobs\Invoice\EmailInvoice;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class AdjustEmailQuota implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
const FREE_PLAN_DAILY_QUOTA = 10;
|
||||||
|
const PRO_PLAN_DAILY_QUOTA = 50;
|
||||||
|
const ENTERPRISE_PLAN_DAILY_QUOTA = 200;
|
||||||
|
|
||||||
|
const FREE_PLAN_DAILY_CAP = 20;
|
||||||
|
const PRO_PLAN_DAILY_CAP = 100;
|
||||||
|
const ENTERPRISE_PLAN_DAILY_CAP = 300;
|
||||||
|
|
||||||
|
const DAILY_MULTIPLIER = 1.1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (! config('ninja.db.multi_db_enabled')) {
|
||||||
|
$this->adjust();
|
||||||
|
} else {
|
||||||
|
//multiDB environment, need to
|
||||||
|
foreach (MultiDB::$dbs as $db) {
|
||||||
|
|
||||||
|
MultiDB::setDB($db);
|
||||||
|
|
||||||
|
$this->adjust();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function adjust()
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach(Account::cursor() as $account){
|
||||||
|
//@TODO once we add in the two columns daily_emails_quota daily_emails_sent_
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
78
app/Jobs/Ninja/RefundCancelledAccount.php
Normal file
78
app/Jobs/Ninja/RefundCancelledAccount.php
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Ninja;
|
||||||
|
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
|
class RefundCancelledAccount implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $account;
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Account $account)
|
||||||
|
{
|
||||||
|
$this->account = $account;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
// if free plan, return
|
||||||
|
if(Ninja::isSelfHost() || $this->account->isFreeHostedClient())
|
||||||
|
return;
|
||||||
|
|
||||||
|
$plan_details = $account->getPlanDetails();
|
||||||
|
|
||||||
|
/* Trial user cancelling early.... */
|
||||||
|
if($plan_details['trial_active'])
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Is the plan Active? */
|
||||||
|
if(!$plan_details['active'])
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Refundable client! */
|
||||||
|
|
||||||
|
$plan_start = $plan_details['started'];
|
||||||
|
$plan_expires = $plan_details['expires'];
|
||||||
|
$paid = $plan_details['paid'];
|
||||||
|
$term = $plan_details['term'];
|
||||||
|
|
||||||
|
$refund = $this->calculateRefundAmount($paid, $plan_expires);
|
||||||
|
|
||||||
|
/* Are there any edge cases? */
|
||||||
|
|
||||||
|
//@TODO process refund by refunding directly to the payment_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function calculateRefundAmount($amount, $plan_expires)
|
||||||
|
{
|
||||||
|
$end_date = Carbon::parse($plan_expires);
|
||||||
|
$now = Carbon::now();
|
||||||
|
|
||||||
|
$days_left = $now->diffInDays($end_date);
|
||||||
|
|
||||||
|
$pro_rata_ratio = $days_left / 365;
|
||||||
|
|
||||||
|
$pro_rata_refund = $amount * $pro_rata_ratio;
|
||||||
|
|
||||||
|
return $pro_rata_refund;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
namespace App\Jobs\Util;
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
namespace App\Jobs\Util;
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
namespace App\Jobs\Util;
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
85
app/Jobs/Util/SendFailedEmails.php
Normal file
85
app/Jobs/Util/SendFailedEmails.php
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
use App\Helpers\Email\InvoiceEmail;
|
||||||
|
use App\Jobs\Invoice\EmailInvoice;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class SendFailedEmails implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (! config('ninja.db.multi_db_enabled')) {
|
||||||
|
$this->processEmails();
|
||||||
|
} else {
|
||||||
|
//multiDB environment, need to
|
||||||
|
foreach (MultiDB::$dbs as $db) {
|
||||||
|
|
||||||
|
MultiDB::setDB($db);
|
||||||
|
|
||||||
|
$this->processEmails();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processEmails()
|
||||||
|
{
|
||||||
|
|
||||||
|
//info("process emails");
|
||||||
|
//@todo check that the quota is available for the job
|
||||||
|
|
||||||
|
$email_jobs = SystemLog::where('event_id', SystemLog::EVENT_MAIL_RETRY_QUEUE)->get();
|
||||||
|
|
||||||
|
$email_jobs->each(function($job){
|
||||||
|
|
||||||
|
$job_meta_array = $job->log;
|
||||||
|
|
||||||
|
$invitation = $job_meta_array['entity_name']::where('key', $job_meta_array['invitation_key'])->with('contact')->first();
|
||||||
|
|
||||||
|
if($invitation->invoice){
|
||||||
|
$email_builder = (new InvoiceEmail())->build($invitation, $job_meta_array['reminder_template']);
|
||||||
|
|
||||||
|
if ($invitation->contact->send_email && $invitation->contact->email) {
|
||||||
|
EmailInvoice::dispatch($email_builder, $invitation, $invitation->company);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
namespace App\Jobs\Util;
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
namespace App\Jobs\Util;
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
namespace App\Jobs\Util;
|
namespace App\Jobs\Util;
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ class SystemLog extends Model
|
|||||||
const EVENT_GATEWAY_ERROR = 23;
|
const EVENT_GATEWAY_ERROR = 23;
|
||||||
|
|
||||||
const EVENT_MAIL_SEND = 30;
|
const EVENT_MAIL_SEND = 30;
|
||||||
|
const EVENT_MAIL_RETRY_QUEUE = 31; //we use this to queue emails that are spooled and not sent due to the email queue quota being exceeded.
|
||||||
|
|
||||||
/*Type IDs*/
|
/*Type IDs*/
|
||||||
const TYPE_PAYPAL = 300;
|
const TYPE_PAYPAL = 300;
|
||||||
@ -35,6 +36,9 @@ class SystemLog extends Model
|
|||||||
const TYPE_LEDGER = 302;
|
const TYPE_LEDGER = 302;
|
||||||
const TYPE_FAILURE = 303;
|
const TYPE_FAILURE = 303;
|
||||||
|
|
||||||
|
const TYPE_QUOTA_EXCEEDED = 400;
|
||||||
|
const TYPE_UPSTREAM_FAILURE = 401;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'client_id',
|
'client_id',
|
||||||
'company_id',
|
'company_id',
|
||||||
|
@ -46,7 +46,7 @@ class SendEmail extends AbstractService
|
|||||||
$this->invoice->invitations->each(function ($invitation) {
|
$this->invoice->invitations->each(function ($invitation) {
|
||||||
$email_builder = (new InvoiceEmail())->build($invitation, $this->reminder_template);
|
$email_builder = (new InvoiceEmail())->build($invitation, $this->reminder_template);
|
||||||
|
|
||||||
if ($invitation->contact->send && $invitation->contact->email) {
|
if ($invitation->contact->send_email && $invitation->contact->email) {
|
||||||
EmailInvoice::dispatch($email_builder, $invitation, $invitation->company);
|
EmailInvoice::dispatch($email_builder, $invitation, $invitation->company);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@ class SendEmail
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->quote->invitations->each(function ($invitation) {
|
$this->quote->invitations->each(function ($invitation) {
|
||||||
if ($invitation->contact->send && $invitation->contact->email) {
|
if ($invitation->contact->send_email && $invitation->contact->email) {
|
||||||
$email_builder = (new QuoteEmail())->build($invitation, $reminder_template);
|
$email_builder = (new QuoteEmail())->build($invitation, $reminder_template);
|
||||||
|
|
||||||
EmailQuote::dispatchNow($email_builder, $invitation);
|
EmailQuote::dispatchNow($email_builder, $invitation);
|
||||||
|
@ -20,6 +20,7 @@ $factory->define(App\Models\ClientContact::class, function (Faker $faker) {
|
|||||||
'phone' => $faker->phoneNumber,
|
'phone' => $faker->phoneNumber,
|
||||||
'email_verified_at' => now(),
|
'email_verified_at' => now(),
|
||||||
'email' => $faker->unique()->safeEmail,
|
'email' => $faker->unique()->safeEmail,
|
||||||
|
'send_email' => true,
|
||||||
'password' => bcrypt('password'),
|
'password' => bcrypt('password'),
|
||||||
'remember_token' => \Illuminate\Support\Str::random(10),
|
'remember_token' => \Illuminate\Support\Str::random(10),
|
||||||
'contact_key' => \Illuminate\Support\Str::random(40),
|
'contact_key' => \Illuminate\Support\Str::random(40),
|
||||||
|
@ -144,7 +144,7 @@ class RandomDataSeeder extends Seeder
|
|||||||
/** Invoice Factory */
|
/** Invoice Factory */
|
||||||
factory(\App\Models\Invoice::class, 20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
|
factory(\App\Models\Invoice::class, 20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
|
||||||
|
|
||||||
$invoices = Invoice::cursor();
|
$invoices = Invoice::all();
|
||||||
$invoice_repo = new InvoiceRepository();
|
$invoice_repo = new InvoiceRepository();
|
||||||
|
|
||||||
$invoices->each(function ($invoice) use ($invoice_repo, $user, $company, $client) {
|
$invoices->each(function ($invoice) use ($invoice_repo, $user, $company, $client) {
|
||||||
@ -160,12 +160,12 @@ class RandomDataSeeder extends Seeder
|
|||||||
|
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
|
|
||||||
event(new CreateInvoiceInvitation($invoice));
|
//event(new CreateInvoiceInvitation($invoice));
|
||||||
|
|
||||||
|
$invoice->service()->createInvitations()->markSent()->save();
|
||||||
|
|
||||||
$invoice->ledger()->updateInvoiceBalance($invoice->balance);
|
$invoice->ledger()->updateInvoiceBalance($invoice->balance);
|
||||||
|
|
||||||
$invoice->service()->markSent()->save();
|
|
||||||
|
|
||||||
event(new InvoiceWasMarkedSent($invoice, $company));
|
event(new InvoiceWasMarkedSent($invoice, $company));
|
||||||
|
|
||||||
if (rand(0, 1)) {
|
if (rand(0, 1)) {
|
||||||
|
68
tests/Integration/SendFailedEmailsTest.php
Normal file
68
tests/Integration/SendFailedEmailsTest.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Integration;
|
||||||
|
|
||||||
|
use App\Jobs\Invoice\EmailInvoice;
|
||||||
|
use App\Jobs\Util\SendFailedEmails;
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use Illuminate\Foundation\Testing\Concerns\InteractsWithDatabase;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Queue;
|
||||||
|
use Tests\MockAccountData;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @covers App\Jobs\Util\SendFailedEmails
|
||||||
|
*/
|
||||||
|
class SendFailedEmailsTest extends TestCase
|
||||||
|
{
|
||||||
|
use MockAccountData;
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function setUp() :void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->makeTestData();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testReminderFires()
|
||||||
|
{
|
||||||
|
$invitation = $this->invoice->invitations->first();
|
||||||
|
$reminder_template = $this->invoice->calculateTemplate();
|
||||||
|
|
||||||
|
$sl = [
|
||||||
|
'entity_name' => 'App\Models\InvoiceInvitation',
|
||||||
|
'invitation_key' => $invitation->key,
|
||||||
|
'reminder_template' => $reminder_template,
|
||||||
|
'subject' => '',
|
||||||
|
'body' => '',
|
||||||
|
];
|
||||||
|
|
||||||
|
$system_log = new SystemLog;
|
||||||
|
$system_log->company_id = $this->invoice->company_id;
|
||||||
|
$system_log->client_id = $this->invoice->client_id;
|
||||||
|
$system_log->category_id = SystemLog::CATEGORY_MAIL;
|
||||||
|
$system_log->event_id = SystemLog::EVENT_MAIL_RETRY_QUEUE;
|
||||||
|
$system_log->type_id = SystemLog::TYPE_QUOTA_EXCEEDED;
|
||||||
|
$system_log->log = $sl;
|
||||||
|
$system_log->save();
|
||||||
|
|
||||||
|
$sys_log = SystemLog::where('event_id', SystemLog::EVENT_MAIL_RETRY_QUEUE)->first();
|
||||||
|
|
||||||
|
$this->assertNotNull($sys_log);
|
||||||
|
|
||||||
|
// Queue::fake();
|
||||||
|
SendFailedEmails::dispatch();
|
||||||
|
|
||||||
|
//Queue::assertPushed(SendFailedEmails::class);
|
||||||
|
//Queue::assertPushed(EmailInvoice::class);
|
||||||
|
//$this->expectsJobs(EmailInvoice::class);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -200,7 +200,7 @@ trait MockAccountData
|
|||||||
|
|
||||||
$this->invoice->save();
|
$this->invoice->save();
|
||||||
|
|
||||||
$this->invoice->service()->markSent();
|
$this->invoice->service()->createInvitations()->markSent();
|
||||||
|
|
||||||
$this->quote = factory(\App\Models\Quote::class)->create([
|
$this->quote = factory(\App\Models\Quote::class)->create([
|
||||||
'user_id' => $this->user->id,
|
'user_id' => $this->user->id,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user