Merge pull request #5821 from turbo124/v5-develop

Refactor reminders
This commit is contained in:
David Bomba 2021-05-26 12:37:46 +10:00 committed by GitHub
commit 60fddcdedf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 200 additions and 167 deletions

View File

@ -65,7 +65,7 @@ class CheckData extends Command
/**
* @var string
*/
protected $name = 'ninja:check-data';
protected $signature = 'ninja:check-data {--database=} {--fix=}';
/**
* @var string

View File

@ -46,7 +46,7 @@ class Kernel extends ConsoleKernel
$schedule->job(new VersionCheck)->daily();
$schedule->command('ninja:check-data')->daily()->withoutOverlapping();
$schedule->command('ninja:check-data --database=db-ninja-01')->daily()->withoutOverlapping();
$schedule->job(new ReminderJob)->daily()->withoutOverlapping();
@ -65,6 +65,7 @@ class Kernel extends ConsoleKernel
$schedule->job(new AdjustEmailQuota)->daily()->withoutOverlapping();
$schedule->job(new SendFailedEmails)->daily()->withoutOverlapping();
$schedule->command('ninja:check-data --database=db-ninja-02')->daily()->withoutOverlapping();
}

View File

@ -142,7 +142,7 @@ class AccountController extends BaseController
*/
public function store(CreateAccountRequest $request)
{
$account = CreateAccount::dispatchNow($request->all());
$account = CreateAccount::dispatchNow($request->all(), $request->getClientIp());
if (! ($account instanceof Account)) {
return $account;

View File

@ -45,9 +45,6 @@ class UpdateUserRequest extends Request
{
$input = $this->all();
// if (isset($input['company_user']) && ! auth()->user()->isAdmin()) {
// unset($input['company_user']);
// }
$this->replace($input);
}

View File

@ -60,12 +60,6 @@ class UniqueUserRule implements Rule
*/
private function checkIfEmailExists($email) : bool
{
$current_db = config('database.default');
$result = MultiDB::checkUserEmailExists($email);
MultiDB::setDb($current_db);
return $result;
return MultiDB::checkUserEmailExists($email);
}
}

View File

@ -20,6 +20,7 @@ use Illuminate\Contracts\Validation\Rule;
*/
class AttachableUser implements Rule
{
public $message;
public function __construct()
{
@ -39,7 +40,7 @@ class AttachableUser implements Rule
*/
public function message()
{
return "Cannot add the same user to the same company";
return $this->message;
}
/**
@ -63,9 +64,16 @@ class AttachableUser implements Rule
->where('company_id', auth()->user()->company()->id)
->exists();
if($user_already_attached)
//If the user is already attached or isn't link to this account - return false
if($user_already_attached) {
$this->message = ctrans('texts.user_duplicate_error');
return false;
}
if($user->account_id != auth()->user()->account_id){
$this->message = ctrans('texts.user_cross_linked_error');
return false;
}
return true;
}

View File

@ -26,14 +26,7 @@ class ValidUserForCompany implements Rule
*/
public function passes($attribute, $value)
{
$current_db = config('database.default');
$result = MultiDB::checkUserAndCompanyCoExist($value, auth()->user()->company()->company_key, auth()->user()->company()->id);
MultiDB::setDb($current_db);
return $result;
return MultiDB::checkUserAndCompanyCoExist($value, auth()->user()->company()->company_key, auth()->user()->company()->id);
}
/**

View File

@ -42,9 +42,12 @@ class CreateAccount
protected $request;
public function __construct(array $sp660339)
protected $client_ip;
public function __construct(array $sp660339, $client_ip)
{
$this->request = $sp660339;
$this->client_ip = $client_ip;
}
public function handle()
@ -113,7 +116,7 @@ class CreateAccount
private function processSettings($settings)
{
if(Ninja::isHosted() && Cache::get('currencies') && $data = unserialize(@file_get_contents('http://www.geoplugin.net/php.gp?ip=' . request()->getClientIp())))
if(Ninja::isHosted() && Cache::get('currencies') && $data = unserialize(@file_get_contents('http://www.geoplugin.net/php.gp?ip=' . $this->client_ip)))
{
$currency_code = strtolower($data['geoplugin_currencyCode']);

View File

@ -423,7 +423,8 @@ class Import implements ShouldQueue
$rules = [
'*.first_name' => ['string'],
'*.last_name' => ['string'],
'*.email' => ['distinct'],
//'*.email' => ['distinct'],
'*.email' => ['distinct', 'email', new ValidUserForCompany(), new AttachableUser()],
];
// if (config('ninja.db.multi_db_enabled')) {

View File

@ -68,7 +68,7 @@ class ReminderJob implements ShouldQueue
event(new InvoiceWasEmailed($invoice->invitations->first(), $invoice->company, Ninja::eventVars(), $reminder_template));
}
$invoice->setReminder();
$invoice->service()->setReminder()->save();
} else {
$invoice->next_send_date = null;

View File

@ -106,8 +106,8 @@ class MultiDB
$current_db = config('database.default');
foreach (self::$dbs as $db) {
if (User::on($db)->where(['email' => $email])->get()->count() >= 1) { // if user already exists, validation will fail
if (Company::on($db)->where(['company_key' => $company_key])->get()->count() >= 1) {
if (User::on($db)->where(['email' => $email])->exists()) {
if (Company::on($db)->where(['company_key' => $company_key])->exists()) {
self::setDb($current_db);
return true;
} else {

View File

@ -39,10 +39,6 @@ class CompanyObserver
if(Ninja::isHosted() && $company->portal_mode == 'domain' && $company->isDirty('portal_domain'))
{
nlog('company observer - updated');
nlog($company->portal_domain);
nlog($company->getOriginal('portal_domain'));
//fire event to build new custom portal domain
\Modules\Admin\Jobs\Domain\CustomDomain::dispatch($company->getOriginal('portal_domain'), $company)->onQueue('domain');
}

View File

@ -52,6 +52,9 @@ class InvoiceObserver
WebhookHandler::dispatch(Webhook::EVENT_UPDATE_INVOICE, $invoice, $invoice->company);
}
// if($invoice->isDirty('date') || $invoice->isDirty('due_date'))
// $invoice->service()->setReminder()->save();
// UnlinkFile::dispatchNow(config('filesystems.default'), $invoice->client->invoice_filepath() . $invoice->numberFormatter().'.pdf');
}

View File

@ -169,10 +169,14 @@ class BaseRepository
*/
protected function alternativeSave($data, $model)
{
if (array_key_exists('client_id', $data)) //forces the client_id if it doesn't exist
//forces the client_id if it doesn't exist
if(array_key_exists('client_id', $data))
$model->client_id = $data['client_id'];
//pickup changes here to recalculate reminders
if($model instanceof Invoice && ($model->isDirty('date') || $model->isDirty('due_date')))
$model->service()->setReminder()->save();
$client = Client::where('id', $model->client_id)->withTrashed()->first();
$state = [];
@ -189,7 +193,7 @@ class BaseRepository
$data = array_merge($company_defaults, $data);
}
$tmp_data = $data; //preserves the $data arrayss
$tmp_data = $data; //preserves the $data array
/* We need to unset some variable as we sometimes unguard the model */
if (isset($tmp_data['invitations']))

View File

@ -21,6 +21,7 @@ use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Task;
use App\Services\Client\ClientService;
use App\Services\Invoice\UpdateReminder;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use Illuminate\Support\Carbon;
@ -245,6 +246,13 @@ class InvoiceService
return $this;
}
public function setReminder($settings = null)
{
$this->invoice = (new UpdateReminder($this->invoice, $settings))->run();
return $this;
}
public function setStatus($status)
{
$this->invoice->status_id = $status;

View File

@ -46,10 +46,9 @@ class MarkSent extends AbstractService
->setDueDate()
->updateBalance($this->invoice->amount)
->deletePdf()
->setReminder()
->save();
$this->invoice->setReminder();
$this->client->service()->updateBalance($this->invoice->balance)->save();
$this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance, "Invoice {$this->invoice->number} marked as sent.");

View File

@ -0,0 +1,131 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Invoice;
use App\Models\Invoice;
use App\Services\AbstractService;
use Carbon\Carbon;
class UpdateReminder extends AbstractService
{
public $invoice;
public $settings;
public function __construct(Invoice $invoice, $settings = null)
{
$this->invoice = $invoice;
$this->settings = $settings;
}
public function run()
{
if (! $this->settings) {
$this->settings = $this->invoice->client->getMergedSettings();
}
if (! $this->invoice->isPayable()) {
$this->invoice->next_send_date = null;
$this->invoice->save();
return $this->invoice; //exit early
}
$date_collection = collect();
if (is_null($this->invoice->reminder1_sent) &&
$this->settings->schedule_reminder1 == 'after_invoice_date' &&
$this->settings->num_days_reminder1 > 0) {
$reminder_date = Carbon::parse($this->invoice->date)->addDays($this->settings->num_days_reminder1);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
if (is_null($this->invoice->reminder1_sent) &&
$this->settings->schedule_reminder1 == 'before_due_date' &&
$this->settings->num_days_reminder1 > 0) {
$reminder_date = Carbon::parse($this->invoice->due_date)->subDays($this->settings->num_days_reminder1);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
if (is_null($this->invoice->reminder1_sent) &&
$this->settings->schedule_reminder1 == 'after_due_date' &&
$this->settings->num_days_reminder1 > 0) {
$reminder_date = Carbon::parse($this->invoice->due_date)->addDays($this->settings->num_days_reminder1);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
if (is_null($this->invoice->reminder2_sent) &&
$this->settings->schedule_reminder2 == 'after_invoice_date' &&
$this->settings->num_days_reminder2 > 0) {
$reminder_date = Carbon::parse($this->invoice->date)->addDays($this->settings->num_days_reminder2);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
if (is_null($this->invoice->reminder2_sent) &&
$this->settings->schedule_reminder2 == 'before_due_date' &&
$this->settings->num_days_reminder2 > 0) {
$reminder_date = Carbon::parse($this->invoice->due_date)->subDays($this->settings->num_days_reminder2);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
if (is_null($this->invoice->reminder2_sent) &&
$this->settings->schedule_reminder2 == 'after_due_date' &&
$this->settings->num_days_reminder2 > 0) {
$reminder_date = Carbon::parse($this->invoice->due_date)->addDays($this->settings->num_days_reminder2);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
if (is_null($this->invoice->reminder3_sent) &&
$this->settings->schedule_reminder3 == 'after_invoice_date' &&
$this->settings->num_days_reminder3 > 0) {
$reminder_date = Carbon::parse($this->invoice->date)->addDays($this->settings->num_days_reminder3);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
if (is_null($this->invoice->reminder3_sent) &&
$this->settings->schedule_reminder3 == 'before_due_date' &&
$this->settings->num_days_reminder3 > 0) {
$reminder_date = Carbon::parse($this->invoice->due_date)->subDays($this->settings->num_days_reminder3);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
if (is_null($this->invoice->reminder3_sent) &&
$this->settings->schedule_reminder3 == 'after_due_date' &&
$this->settings->num_days_reminder3 > 0) {
$reminder_date = Carbon::parse($this->invoice->due_date)->addDays($this->settings->num_days_reminder3);
if ($reminder_date->gt(Carbon::parse($this->invoice->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d'));
}
$this->invoice->next_send_date = $date_collection->sort()->first();
return $this->invoice;
}
}

View File

@ -19,115 +19,6 @@ use Illuminate\Support\Carbon;
*/
trait MakesReminders
{
public function setReminder($settings = null)
{
if (! $settings) {
$settings = $this->client->getMergedSettings();
}
if (! $this->isPayable()) {
$this->next_send_date = null;
$this->save();
return; //exit early
}
$date_collection = collect();
if (is_null($this->reminder1_sent) &&
$settings->schedule_reminder1 == 'after_invoice_date' &&
$settings->num_days_reminder1 > 0) {
$reminder_date = Carbon::parse($this->date)->addDays($settings->num_days_reminder1);
nlog("reminder 1 = after invoice date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('after_invoice_date pushed to collection');
}
if (is_null($this->reminder1_sent) &&
$settings->schedule_reminder1 == 'before_due_date' &&
$settings->num_days_reminder1 > 0) {
$reminder_date = Carbon::parse($this->due_date)->subDays($settings->num_days_reminder1);
nlog("reminder 1 = before_due_date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('before_due_date pushed to collection');
}
if (is_null($this->reminder1_sent) &&
$settings->schedule_reminder1 == 'after_due_date' &&
$settings->num_days_reminder1 > 0) {
$reminder_date = Carbon::parse($this->due_date)->addDays($settings->num_days_reminder1);
nlog("reminder 1 = after_due_date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('after_due_date pushed to collection');
}
if (is_null($this->reminder2_sent) &&
$settings->schedule_reminder2 == 'after_invoice_date' &&
$settings->num_days_reminder2 > 0) {
$reminder_date = Carbon::parse($this->date)->addDays($settings->num_days_reminder2);
nlog("reminder 2 = after_invoice_date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('after_invoice_date pushed to collection');
}
if (is_null($this->reminder2_sent) &&
$settings->schedule_reminder2 == 'before_due_date' &&
$settings->num_days_reminder2 > 0) {
$reminder_date = Carbon::parse($this->due_date)->subDays($settings->num_days_reminder2);
nlog("reminder 2 = before_due_date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('before_due_date pushed to collection');
}
if (is_null($this->reminder2_sent) &&
$settings->schedule_reminder2 == 'after_due_date' &&
$settings->num_days_reminder2 > 0) {
$reminder_date = Carbon::parse($this->due_date)->addDays($settings->num_days_reminder2);
nlog("reminder 2 = after_due_date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('after_due_date pushed to collection');
}
if (is_null($this->reminder3_sent) &&
$settings->schedule_reminder3 == 'after_invoice_date' &&
$settings->num_days_reminder3 > 0) {
$reminder_date = Carbon::parse($this->date)->addDays($settings->num_days_reminder3);
nlog("reminder 3 = after_invoice_date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('after_invoice_date pushed to collection');
}
if (is_null($this->reminder3_sent) &&
$settings->schedule_reminder3 == 'before_due_date' &&
$settings->num_days_reminder3 > 0) {
$reminder_date = Carbon::parse($this->due_date)->subDays($settings->num_days_reminder3);
nlog("reminder 3 = before_due_date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('before_due_date pushed to collection');
}
if (is_null($this->reminder3_sent) &&
$settings->schedule_reminder3 == 'after_due_date' &&
$settings->num_days_reminder3 > 0) {
$reminder_date = Carbon::parse($this->due_date)->addDays($settings->num_days_reminder3);
nlog("reminder 3 = after_due_date = {$reminder_date}");
if ($reminder_date->gt(Carbon::parse($this->next_send_date)));
$date_collection->push($reminder_date->format('Y-m-d')); nlog('after_due_date pushed to collection');
}
$this->next_send_date = $date_collection->sort()->first();
$this->save();
}
public function inReminderWindow($schedule_reminder, $num_days_reminder)
{
@ -195,10 +86,8 @@ trait MakesReminders
private function addTimeInterval($date, $endless_reminder_frequency_id) :?Carbon
{
if (!$date) {
if (!$date)
return null;
}
switch ($endless_reminder_frequency_id) {
case RecurringInvoice::FREQUENCY_WEEKLY:

View File

@ -4252,6 +4252,8 @@ $LANG = array(
'contact_details' => 'Contact Details',
'download_backup_subject' => 'Your company backup is ready for download',
'account_passwordless_login' => 'Account passwordless login',
'user_duplicate_error' => 'Cannot add the same user to the same company',
'user_cross_linked_error' => 'User exists but cannot be crossed linked to multiple accounts',
);
return $LANG;

View File

@ -7,7 +7,11 @@
<p>Looks like your migration failed. Here's the error message:</p>
<pre>
@if(Ninja::isHosted())
There was a problem with your migration, please send us an email contact@invoiceninja.com
@else
{!! $exception->getMessage() !!}
{!! $content !!}
@endif
</pre>
@endcomponent

View File

@ -75,7 +75,7 @@ class ReminderTest extends TestCase
$this->company->settings = $settings;
$this->invoice->service()->markSent();
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->assertEquals($this->invoice->next_send_date, Carbon::now()->addDays(7)->format('Y-m-d'));
@ -102,7 +102,7 @@ class ReminderTest extends TestCase
$this->company->settings = $settings;
$this->invoice->service()->markSent();
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->invoice->fresh();
@ -132,7 +132,7 @@ class ReminderTest extends TestCase
$this->company->settings = $settings;
$this->invoice->service()->markSent();
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->invoice->fresh();

View File

@ -19,13 +19,11 @@ use Tests\TestCase;
/**
* @test
* @covers App\Utils\Traits\MakesReminders
*/
class CheckRemindersTest extends TestCase
{
use MockAccountData;
use DatabaseTransactions;
use MakesReminders;
public function setUp() :void
{
@ -51,8 +49,10 @@ class CheckRemindersTest extends TestCase
$settings->num_days_reminder3 = 1;
$this->company->settings = $settings;
$this->company->save();
$this->invoice->service()->markSent();
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->assertEquals(0, Carbon::now()->addDays(7)->diffInDays($this->invoice->next_send_date));
}
@ -75,7 +75,7 @@ class CheckRemindersTest extends TestCase
$this->company->settings = $settings;
$this->invoice->service()->markSent()->setStatus(Invoice::STATUS_PAID);
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->assertEquals($this->invoice->next_send_date, null);
}
@ -98,7 +98,7 @@ class CheckRemindersTest extends TestCase
$this->company->settings = $settings;
$this->invoice->service()->markSent();
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->assertEquals(0, Carbon::parse($this->invoice->due_date)->subDays(29)->diffInDays($this->invoice->next_send_date));
}
@ -118,7 +118,7 @@ class CheckRemindersTest extends TestCase
$this->company->settings = $settings;
$this->invoice->service()->markSent();
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->assertEquals(0, Carbon::parse($this->invoice->due_date)->addDays(1)->diffInDays($this->invoice->next_send_date));
}
@ -141,7 +141,7 @@ class CheckRemindersTest extends TestCase
$this->company->settings = $settings;
$this->invoice->service()->markSent();
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->assertEquals($this->invoice->next_send_date, null);
}
@ -164,7 +164,7 @@ class CheckRemindersTest extends TestCase
$this->company->settings = $settings;
$this->invoice->service()->markSent();
$this->invoice->setReminder($settings);
$this->invoice->service()->setReminder($settings)->save();
$this->assertEquals($this->invoice->next_send_date, null);
}

View File

@ -192,10 +192,10 @@ trait MockAccountData
if (! $user) {
$user = User::factory()->create([
'account_id' => $this->account->id,
'confirmation_code' => $this->createDbHash(config('database.default')),
'email' => 'user@example.com',
]);
'account_id' => $this->account->id,
'confirmation_code' => $this->createDbHash(config('database.default')),
'email' => 'user@example.com',
]);
}
$user->password = Hash::make('ALongAndBriliantPassword');