mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-11 05:32:39 +01:00
Merge pull request #6375 from turbo124/v5-develop
dispatchNow inside email entity
This commit is contained in:
commit
26fa363ea3
@ -218,7 +218,7 @@ class PreviewController extends BaseController
|
||||
|
||||
/* Catch all in case migration doesn't pass back a valid design */
|
||||
if(!$design)
|
||||
$design = Design::find(2);
|
||||
$design = \App\Models\Design::find(2);
|
||||
|
||||
if ($design->is_custom) {
|
||||
$options = [
|
||||
|
@ -74,9 +74,9 @@ class PaymentWebhookRequest extends Request
|
||||
{
|
||||
// For testing purposes we'll slow down the webhook processing by 2 seconds
|
||||
// to make sure webhook request doesn't came before our processing.
|
||||
if (app()->environment() !== 'production') {
|
||||
//if (app()->environment() !== 'production') {
|
||||
sleep(2);
|
||||
}
|
||||
//}
|
||||
|
||||
// Some gateways, like Checkout, we can dynamically pass payment hash,
|
||||
// which we will resolve here and get payment information from it.
|
||||
|
@ -119,7 +119,7 @@ class EmailEntity implements ShouldQueue
|
||||
$nmo->reminder_template = $this->reminder_template;
|
||||
$nmo->entity = $this->entity;
|
||||
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
NinjaMailerJob::dispatchNow($nmo);
|
||||
|
||||
/* Mark entity sent */
|
||||
$this->entity->service()->markSent()->save();
|
||||
|
@ -86,14 +86,14 @@ class SendRecurring implements ShouldQueue
|
||||
$this->recurring_invoice->save();
|
||||
|
||||
//Admin notification for recurring invoice sent.
|
||||
if ($invoice->invitations->count() >= 1) {
|
||||
if ($invoice->invitations->count() >= 1 ) {
|
||||
$invoice->entityEmailEvent($invoice->invitations->first(), 'invoice', 'email_template_invoice');
|
||||
}
|
||||
|
||||
nlog("Invoice {$invoice->number} created");
|
||||
|
||||
$invoice->invitations->each(function ($invitation) use ($invoice) {
|
||||
if ($invitation->contact && strlen($invitation->contact->email) >=1) {
|
||||
if ($invitation->contact && strlen($invitation->contact->email) >=1 && $invoice->client->getSetting('auto_email_invoice')) {
|
||||
|
||||
try{
|
||||
EmailEntity::dispatch($invitation, $invoice->company);
|
||||
|
@ -35,11 +35,14 @@ use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule;
|
||||
use App\Http\ValidationRules\ValidUserForCompany;
|
||||
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||
use App\Jobs\Company\CreateCompanyToken;
|
||||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
use App\Jobs\Ninja\CheckCompanyData;
|
||||
use App\Jobs\Ninja\CompanySizeCheck;
|
||||
use App\Jobs\Util\VersionCheck;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Mail\MigrationCompleted;
|
||||
use App\Mail\Migration\StripeConnectMigration;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
@ -87,6 +90,7 @@ use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
@ -244,6 +248,10 @@ class Import implements ShouldQueue
|
||||
|
||||
// $this->fixData();
|
||||
try{
|
||||
App::forgetInstance('translator');
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
Mail::to($this->user->email, $this->user->name())
|
||||
->send(new MigrationCompleted($this->company, implode("<br>",$check_data)));
|
||||
}
|
||||
@ -1381,9 +1389,21 @@ class Import implements ShouldQueue
|
||||
$modified['fees_and_limits'] = $this->cleanFeesAndLimits($modified['fees_and_limits']);
|
||||
}
|
||||
|
||||
/* On Hosted platform we need to advise Stripe users to connect with Stripe Connect */
|
||||
if(Ninja::isHosted() && $modified['gateway_key'] == 'd14dd26a37cecc30fdd65700bfb55b23'){
|
||||
|
||||
$nmo = new NinjaMailerObject;
|
||||
$nmo->mailable = new StripeConnectMigration($this->company);
|
||||
$nmo->company = $this->company;
|
||||
$nmo->settings = $this->company->settings;
|
||||
$nmo->to_user = $this->user;
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
|
||||
$modified['gateway_key'] = 'd14dd26a47cecc30fdd65700bfb67b34';
|
||||
$modified['fees_and_limits'] = [];
|
||||
|
||||
//why do we set this to a blank array?
|
||||
//$modified['fees_and_limits'] = [];
|
||||
|
||||
}
|
||||
|
||||
$company_gateway = CompanyGateway::create($modified);
|
||||
|
55
app/Mail/Migration/StripeConnectMigration.php
Normal file
55
app/Mail/Migration/StripeConnectMigration.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?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://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Mail\Migration;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class StripeConnectMigration extends Mailable
|
||||
{
|
||||
// use Queueable, SerializesModels;
|
||||
|
||||
public $company;
|
||||
|
||||
public $settings;
|
||||
|
||||
public $logo;
|
||||
|
||||
public $whitelabel;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($company)
|
||||
{
|
||||
$this->company = $company;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$this->settings = $this->company->settings;
|
||||
$this->logo = $this->company->present()->logo();
|
||||
$this->whitelabel = $this->company->account->isPaid();
|
||||
|
||||
return $this->from(config('mail.from.address'), config('mail.from.name'))
|
||||
->subject(ctrans('texts.stripe_connect_migration_title'))
|
||||
->view('email.migration.stripe_connect');
|
||||
}
|
||||
}
|
@ -15,7 +15,11 @@ use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\FeesAndLimits;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Presenters\ClientPresenter;
|
||||
use App\Models\Project;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Task;
|
||||
use App\Services\Client\ClientService;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
@ -153,6 +157,16 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
return $this->hasMany(ClientGatewayToken::class);
|
||||
}
|
||||
|
||||
public function expenses()
|
||||
{
|
||||
return $this->hasMany(Expense::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function projects()
|
||||
{
|
||||
return $this->hasMany(Project::class)->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the specific payment token per
|
||||
* gateway - per payment method.
|
||||
@ -217,6 +231,16 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
return $this->hasMany(Invoice::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function quotes()
|
||||
{
|
||||
return $this->hasMany(Quote::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function tasks()
|
||||
{
|
||||
return $this->hasMany(Task::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function recurring_invoices()
|
||||
{
|
||||
return $this->hasMany(RecurringInvoice::class)->withTrashed();
|
||||
@ -774,7 +798,7 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->hasMany(Payment::class);
|
||||
return $this->hasMany(Payment::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function timezone_offset()
|
||||
|
@ -125,7 +125,7 @@ class ActivityRepository extends BaseRepository
|
||||
|
||||
$design = Design::find($entity_design_id);
|
||||
|
||||
if(!$entity->invitations()->exists()){
|
||||
if(!$entity->invitations()->exists() || !$design){
|
||||
nlog("No invitations for entity {$entity->id} - {$entity->number}");
|
||||
return;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace App\Services\Client;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Services\Client\Merge;
|
||||
use App\Services\Client\PaymentMethod;
|
||||
use App\Utils\Number;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
@ -77,6 +78,13 @@ class ClientService
|
||||
return (new PaymentMethod($this->client, $amount))->run();
|
||||
}
|
||||
|
||||
public function merge(Client $mergable_client)
|
||||
{
|
||||
$this->client = (new Merge($this->client, $mergable_client))->run();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function save() :Client
|
||||
{
|
||||
$this->client->save();
|
||||
|
102
app/Services/Client/Merge.php
Normal file
102
app/Services/Client/Merge.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?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://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Client;
|
||||
|
||||
use App\Factory\CompanyLedgerFactory;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Client;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\CompanyLedger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Services\AbstractService;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class Merge extends AbstractService
|
||||
{
|
||||
public $client;
|
||||
|
||||
public $mergable_client;
|
||||
|
||||
public function __construct(Client $client, Client $mergable_client)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->mergable_client = $mergable_client;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
|
||||
$this->client->balance += $this->mergable_client->balance;
|
||||
$this->client->paid_to_date += $this->mergable_client->paid_to_date;
|
||||
$this->client->save();
|
||||
|
||||
$this->updateLedger($this->mergable_client->balance);
|
||||
|
||||
$this->mergable_client->activities()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->contacts()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->gateway_tokens()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->credits()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->expenses()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->invoices()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->payments()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->projects()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->quotes()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->recurring_invoices()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->tasks()->update(['client_id' => $this->client->id]);
|
||||
$this->mergable_client->documents()->update(['documentable_id' => $this->client->id]);
|
||||
|
||||
/* Loop through contacts an only merge distinct contacts by email */
|
||||
$this->mergable_client->contacts->each(function ($contact){
|
||||
|
||||
$exist = $this->client->contacts->contains(function ($client_contact) use($contact){
|
||||
return $client_contact->email == $contact->email;
|
||||
});
|
||||
|
||||
if($exist)
|
||||
{
|
||||
$contact->delete();
|
||||
$contact->save();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$this->mergable_client->forceDelete();
|
||||
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
private function updateLedger($adjustment)
|
||||
{
|
||||
$balance = 0;
|
||||
|
||||
$company_ledger = CompanyLedger::whereClientId($this->client->id)
|
||||
->orderBy('id', 'DESC')
|
||||
->first();
|
||||
|
||||
if ($company_ledger) {
|
||||
$balance = $company_ledger->balance;
|
||||
}
|
||||
|
||||
$company_ledger = CompanyLedgerFactory::create($this->client->company_id, $this->client->user_id);
|
||||
$company_ledger->client_id = $this->client->id;
|
||||
$company_ledger->adjustment = $adjustment;
|
||||
$company_ledger->notes = "Balance update after merging " . $this->mergable_client->present()->name();
|
||||
$company_ledger->balance = $balance + $adjustment;
|
||||
$company_ledger->activity_id = Activity::UPDATE_CLIENT;
|
||||
$company_ledger->save();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -39,7 +39,7 @@ class UserService
|
||||
$nmo->to_user = $this->user;
|
||||
$nmo->settings = $company->settings;
|
||||
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
NinjaMailerJob::dispatch($nmo, true);
|
||||
|
||||
Ninja::registerNinjaUser($this->user);
|
||||
|
||||
|
@ -4287,6 +4287,8 @@ $LANG = array(
|
||||
'company_deleted' => 'Company deleted',
|
||||
'company_deleted_body' => 'Company [ :company ] was deleted by :user',
|
||||
'back_to' => 'Back to :url',
|
||||
'stripe_connect_migration_title' => 'Connect your Stripe Account',
|
||||
'stripe_connect_migration_desc' => 'Invoice Ninja v5 uses Stripe Connect to link your Stripe account to Invoice Ninja. This provides an additional layer of security for your account. Now that you data has migrated, you will need to Authorize Stripe to accept payments in v5.<br><br>To do this, navigate to Settings > Online Payments > Configure Gateways. Click on Stripe Connect and then under Settings click Setup Gateway. This will take you to Stripe to authorize Invoice Ninja and on your return your account will be successfully linked!',
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -1,6 +1,7 @@
|
||||
@component('email.template.admin', ['logo' => $logo, 'settings' => $settings])
|
||||
<div class="center">
|
||||
<h1>{{ ctrans('texts.max_companies') }}</h1>
|
||||
|
||||
<p>{{ ctrans('texts.max_companies_desc') }}</p>
|
||||
</div>
|
||||
@endcomponent
|
||||
|
7
resources/views/email/migration/stripe_connect.blade.php
Normal file
7
resources/views/email/migration/stripe_connect.blade.php
Normal file
@ -0,0 +1,7 @@
|
||||
@component('email.template.admin', ['logo' => $logo, 'settings' => $settings])
|
||||
<div class="center">
|
||||
<h1>{{ ctrans('texts.stripe_connect_migration_title') }}</h1>
|
||||
|
||||
<p>{{ ctrans('texts.stripe_connect_migration_desc') }}</p>
|
||||
</div>
|
||||
@endcomponent
|
180
tests/Feature/Client/ClientMergeTest.php
Normal file
180
tests/Feature/Client/ClientMergeTest.php
Normal file
@ -0,0 +1,180 @@
|
||||
<?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://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Client;
|
||||
|
||||
use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Http\Livewire\CreditsTable;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Company;
|
||||
use App\Models\Credit;
|
||||
use App\Models\User;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Livewire\Livewire;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClientMergeTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
use AppSetup;
|
||||
|
||||
private $user;
|
||||
|
||||
private $company;
|
||||
|
||||
private $account;
|
||||
|
||||
public $client;
|
||||
|
||||
private $primary_contact;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = Factory::create();
|
||||
$this->buildCache(true);
|
||||
}
|
||||
|
||||
public function testSearchingForContacts()
|
||||
{
|
||||
|
||||
$account = Account::factory()->create();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
'email' => $this->faker->safeEmail
|
||||
]);
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $account->id
|
||||
]);
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id
|
||||
]);
|
||||
|
||||
$this->primary_contact = ClientContact::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_primary' => 1,
|
||||
]);
|
||||
|
||||
ClientContact::factory()->count(2)->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
]);
|
||||
|
||||
ClientContact::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
'email' => 'search@gmail.com'
|
||||
]);
|
||||
|
||||
|
||||
$this->assertEquals(4, $this->client->contacts->count());
|
||||
$this->assertTrue($this->client->contacts->contains(function ($contact) {
|
||||
return $contact->email == 'search@gmail.com';
|
||||
}));
|
||||
|
||||
$this->assertFalse($this->client->contacts->contains(function ($contact) {
|
||||
return $contact->email == 'false@gmail.com';
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
public function testMergeClients()
|
||||
{
|
||||
|
||||
$account = Account::factory()->create();
|
||||
|
||||
$user = User::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
'email' => $this->faker->safeEmail
|
||||
]);
|
||||
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $account->id
|
||||
]);
|
||||
|
||||
$client = Client::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'company_id' => $company->id
|
||||
]);
|
||||
|
||||
$primary_contact = ClientContact::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $company->id,
|
||||
'is_primary' => 1,
|
||||
]);
|
||||
|
||||
ClientContact::factory()->count(2)->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $company->id,
|
||||
]);
|
||||
|
||||
ClientContact::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $company->id,
|
||||
'email' => 'search@gmail.com'
|
||||
]);
|
||||
//4contacts
|
||||
|
||||
$mergable_client = Client::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'company_id' => $company->id
|
||||
]);
|
||||
|
||||
$primary_contact = ClientContact::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $mergable_client->id,
|
||||
'company_id' => $company->id,
|
||||
'is_primary' => 1,
|
||||
]);
|
||||
|
||||
ClientContact::factory()->count(2)->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $mergable_client->id,
|
||||
'company_id' => $company->id,
|
||||
]);
|
||||
|
||||
ClientContact::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
'client_id' => $mergable_client->id,
|
||||
'company_id' => $company->id,
|
||||
'email' => 'search@gmail.com'
|
||||
]);
|
||||
//4 contacts
|
||||
|
||||
$this->assertEquals(4, $client->contacts->count());
|
||||
$this->assertEquals(4, $mergable_client->contacts->count());
|
||||
|
||||
$client = $client->service()->merge($mergable_client)->save();
|
||||
|
||||
// nlog($client->contacts->fresh()->toArray());
|
||||
// $this->assertEquals(7, $client->fresh()->contacts->count());
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user