diff --git a/app/Factory/CloneQuoteToInvoiceFactory.php b/app/Factory/CloneQuoteToInvoiceFactory.php index e0987fc3fed9..8376d1fdd93b 100644 --- a/app/Factory/CloneQuoteToInvoiceFactory.php +++ b/app/Factory/CloneQuoteToInvoiceFactory.php @@ -28,14 +28,14 @@ class CloneQuoteToInvoiceFactory unset($quote_array['hashed_id']); unset($quote_array['invoice_id']); unset($quote_array['id']); - + foreach($quote_array as $key => $value) $invoice->{$key} = $value; + $invoice->status_id = Invoice::STATUS_DRAFT; $invoice->due_date = null; $invoice->partial_due_date = null; $invoice->number = null; - $invoice->status_id = null; return $invoice; diff --git a/app/Filters/QuoteFilters.php b/app/Filters/QuoteFilters.php index 47259be2b85d..417bdc9470ca 100644 --- a/app/Filters/QuoteFilters.php +++ b/app/Filters/QuoteFilters.php @@ -82,6 +82,11 @@ class QuoteFilters extends QueryFilters }); } + public function number($number = '') + { + return $this->builder->where('number', 'like', '%'.$number.'%'); + } + /** * Sorts the list based on $sort * diff --git a/app/Http/Controllers/ClientPortal/InvitationController.php b/app/Http/Controllers/ClientPortal/InvitationController.php index 08f86168960e..fe06f648af7a 100644 --- a/app/Http/Controllers/ClientPortal/InvitationController.php +++ b/app/Http/Controllers/ClientPortal/InvitationController.php @@ -41,7 +41,7 @@ class InvitationController extends Controller if ((bool)$invitation->contact->client->getSetting('enable_client_portal_password') !== false) { $this->middleware('auth:contact'); } else { - auth()->guard('contact')->login($invitation->contact, false); + auth()->guard('contact')->login($invitation->contact, true); } if (!request()->has('silent')) { diff --git a/app/Http/Controllers/ClientPortal/SwitchCompanyController.php b/app/Http/Controllers/ClientPortal/SwitchCompanyController.php index aa9c3d17a81f..22b40a7fb389 100644 --- a/app/Http/Controllers/ClientPortal/SwitchCompanyController.php +++ b/app/Http/Controllers/ClientPortal/SwitchCompanyController.php @@ -23,13 +23,13 @@ class SwitchCompanyController extends Controller public function __invoke(string $contact) { - $client_contact = ClientContact::query() - ->where('user_id', auth()->user()->id) + + $client_contact = ClientContact::where('email', auth()->user()->email) ->where('id', $this->transformKeys($contact)) ->first(); Auth::guard('contact')->login($client_contact, true); - return back(); + return redirect('/client/dashboard'); } } diff --git a/app/Http/Controllers/MigrationController.php b/app/Http/Controllers/MigrationController.php index 66c01fba4301..07fc187fd3cf 100644 --- a/app/Http/Controllers/MigrationController.php +++ b/app/Http/Controllers/MigrationController.php @@ -366,7 +366,7 @@ class MigrationController extends BaseController return; } - StartMigration::dispatch(base_path("storage/app/public/$migration_file"), $user, $company); + StartMigration::dispatch(base_path("storage/app/public/$migration_file"), $user, $company)->delay(now()->addSeconds(60)); return response()->json([ '_id' => Str::uuid(), diff --git a/app/Http/ViewComposers/PortalComposer.php b/app/Http/ViewComposers/PortalComposer.php index 67c12c19d149..a9d8a64e40c7 100644 --- a/app/Http/ViewComposers/PortalComposer.php +++ b/app/Http/ViewComposers/PortalComposer.php @@ -49,7 +49,8 @@ class PortalComposer $data['company'] = auth()->user()->company; $data['client'] = auth()->user()->client; $data['settings'] = auth()->user()->client->getMergedSettings(); - $data['multiple_contacts'] = ClientContact::where('email', auth('contact')->user()->email)->get(); + + $data['multiple_contacts'] = ClientContact::where('email', auth('contact')->user()->email)->whereNotNull('email')->distinct('company_id')->get(); return $data; } diff --git a/app/Jobs/Mail/EntityPaidMailer.php b/app/Jobs/Mail/EntityPaidMailer.php index 44bfe3021bcc..a2175f2043c2 100644 --- a/app/Jobs/Mail/EntityPaidMailer.php +++ b/app/Jobs/Mail/EntityPaidMailer.php @@ -55,8 +55,12 @@ class EntityPaidMailer extends BaseMailerJob implements ShouldQueue { info("entity paid mailer"); //Set DB + // MultiDB::setDb($this->company->db); + if($this->company->company_users->first()->is_migrating) + return true; + //if we need to set an email driver do it now $this->setMailDriver($this->payment->client->getSetting('email_sending_method')); diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index c01f2bc85d5c..426b386a0888 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -31,6 +31,7 @@ use App\Libraries\MultiDB; use App\Mail\MigrationCompleted; use App\Mail\MigrationFailed; use App\Models\Client; +use App\Models\ClientContact; use App\Models\ClientGatewayToken; use App\Models\Company; use App\Models\CompanyGateway; @@ -147,7 +148,7 @@ class Import implements ShouldQueue * @return void * @throws \Exception */ - public function handle() + public function handle() :bool { set_time_limit(0); @@ -156,7 +157,6 @@ class Import implements ShouldQueue if (! in_array($key, $this->available_imports)) { //throw new ResourceNotAvailableForMigration("Resource {$key} is not available for migration."); info("Resource {$key} is not available for migration."); - continue; } @@ -170,6 +170,8 @@ class Import implements ShouldQueue Mail::to($this->user)->send(new MigrationCompleted()); info('Completedπππππ at '.now()); + + return true; } /** @@ -368,7 +370,9 @@ class Import implements ShouldQueue unset($modified_contacts[$key]['id']); } - $contact_repository->save($modified_contacts, $client); + $saveable_contacts['contacts'] = $modified_contacts; + + $contact_repository->save($saveable_contacts, $client); } $key = "clients_{$resource['id']}"; diff --git a/app/Jobs/Util/StartMigration.php b/app/Jobs/Util/StartMigration.php index e38343ec68ed..2373540e112c 100644 --- a/app/Jobs/Util/StartMigration.php +++ b/app/Jobs/Util/StartMigration.php @@ -74,6 +74,9 @@ class StartMigration implements ShouldQueue */ public function handle() { + + set_time_limit(0); + MultiDB::setDb($this->company->db); auth()->login($this->user, false); @@ -96,7 +99,7 @@ class StartMigration implements ShouldQueue $zip->close(); if (app()->environment() == 'testing') { - return; + return true; } $this->company->setMigration(true); @@ -110,6 +113,9 @@ class StartMigration implements ShouldQueue $data = json_decode(file_get_contents($file), 1); Import::dispatchNow($data, $this->company, $this->user); + + $this->company->setMigration(false); + } catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) { $this->company->setMigration(false); @@ -119,6 +125,11 @@ class StartMigration implements ShouldQueue info($e->getMessage()); } } + + //always make sure we unset the migration as running + + + return true; } public function failed($exception = null) diff --git a/app/Jobs/Util/SubscriptionHandler.php b/app/Jobs/Util/SubscriptionHandler.php index 974350323355..bbc28d6dbccb 100644 --- a/app/Jobs/Util/SubscriptionHandler.php +++ b/app/Jobs/Util/SubscriptionHandler.php @@ -37,18 +37,27 @@ class SubscriptionHandler implements ShouldQueue * * @return void */ - public function handle() + public function handle() :bool { + + if(!$this->entity->company || $this->entity->company->company_users->first()->is_migrating) + return true; + + info("i got past the check"); + $subscriptions = Subscription::where('company_id', $this->entity->company_id) ->where('event_id', $this->event_id) ->get(); if(!$subscriptions || $subscriptions->count() == 0) - return; + return true; $subscriptions->each(function($subscription) { $this->process($subscription); }); + + return true; + } private function process($subscription) diff --git a/app/Listeners/Payment/PaymentNotification.php b/app/Listeners/Payment/PaymentNotification.php index 6c664faa66ce..039b02e75dfb 100644 --- a/app/Listeners/Payment/PaymentNotification.php +++ b/app/Listeners/Payment/PaymentNotification.php @@ -48,6 +48,9 @@ class PaymentNotification implements ShouldQueue /*User notifications*/ foreach ($payment->company->company_users as $company_user) { + if($company_user->is_migrating) + return true; + $user = $company_user->user; $methods = $this->findUserEntityNotificationType($payment, $company_user, ['all_notifications']); diff --git a/app/Models/Company.php b/app/Models/Company.php index f71eb5491900..4194cd827280 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -406,9 +406,13 @@ class Company extends BaseModel public function setMigration($status) { - $this->company_users->each(function ($cu) use ($status) { + $company_users = CompanyUser::where('company_id', $this->id)->get(); + + foreach($company_users as $cu) + { $cu->is_migrating=$status; $cu->save(); - }); + } + } } diff --git a/app/Repositories/ClientContactRepository.php b/app/Repositories/ClientContactRepository.php index 5c83eb01fad5..443f8cef56b8 100644 --- a/app/Repositories/ClientContactRepository.php +++ b/app/Repositories/ClientContactRepository.php @@ -24,6 +24,7 @@ class ClientContactRepository extends BaseRepository { public function save(array $data, Client $client) : void { + if (isset($data['contacts'])) { $contacts = collect($data['contacts']); } else { @@ -66,17 +67,20 @@ class ClientContactRepository extends BaseRepository } $update_contact->save(); + }); - - //always made sure we have one blank contact to maintain state - if ($contacts->count() == 0) { + if ($client->contacts->count() == 0) { + + info("no contacts found"); + $new_contact = ClientContactFactory::create($client->company_id, $client->user_id); $new_contact->client_id = $client->id; $new_contact->contact_key = Str::random(40); $new_contact->is_primary = true; $new_contact->save(); } + } } diff --git a/app/Services/Quote/ConvertQuote.php b/app/Services/Quote/ConvertQuote.php index 6a53e28cc674..597e57dae741 100644 --- a/app/Services/Quote/ConvertQuote.php +++ b/app/Services/Quote/ConvertQuote.php @@ -10,10 +10,10 @@ class ConvertQuote private $client; private $invoice_repo; - public function __construct($client, InvoiceRepository $invoice_repo) + public function __construct($client) { $this->client = $client; - $this->invoice_repo = $invoice_repo; + $this->invoice_repo = new InvoiceRepository(); } /** @@ -23,9 +23,19 @@ class ConvertQuote public function run($quote) { $invoice = CloneQuoteToInvoiceFactory::create($quote, $quote->user_id, $quote->company_id); - $this->invoice_repo->save([], $invoice); + $invoice = $this->invoice_repo->save([], $invoice); + $invoice->fresh(); + + $invoice->service() + ->markSent() + ->createInvitations() + ->save(); + + $quote->invoice_id = $invoice->id; + $quote->save(); + // maybe should return invoice here - return $quote; + return $invoice; } } diff --git a/app/Services/Quote/QuoteService.php b/app/Services/Quote/QuoteService.php index 9356721a8f87..b9d9b0ebdc70 100644 --- a/app/Services/Quote/QuoteService.php +++ b/app/Services/Quote/QuoteService.php @@ -21,6 +21,8 @@ class QuoteService { protected $quote; + public $invoice; + public function __construct($quote) { $this->quote = $quote; @@ -38,17 +40,28 @@ class QuoteService public function markApproved() { $mark_approved = new MarkApproved($this->quote->client); - $this->quote = $mark_approved->run($this->quote); if ($this->quote->client->getSetting('auto_convert_quote') === true) { - $convert_quote = new ConvertQuote($this->quote->client); - $this->quote = $convert_quote->run($this->quote); + $this->convert(); } return $this; } + public function convert() :QuoteService + { + if($this->quote->invoice_id) + return $this; + + $convert_quote = new ConvertQuote($this->quote->client); + $this->invoice = $convert_quote->run($this->quote); + + $this->quote->fresh(); + + return $this; + } + public function getQuotePdf($contact = null) { $get_invoice_pdf = new GetQuotePdf(); @@ -101,8 +114,7 @@ class QuoteService $invoice = null; if ($this->quote->client->getSetting('auto_convert_quote')) { - $invoice = $this->convertToInvoice(); - $this->linkInvoiceToQuote($invoice)->save(); + $this->convert(); } if ($this->quote->client->getSetting('auto_archive_quote')) { @@ -113,32 +125,16 @@ class QuoteService return $this; } - /** - * Where we convert a quote to an invoice we link the two entities via the invoice_id parameter on the quote table - * @param object $invoice The Invoice object - * @return object QuoteService - */ - public function linkInvoiceToQuote($invoice) :QuoteService - { - $this->quote->invoice_id = $invoice->id; - - return $this; - } - public function convertToInvoice() :Invoice { - $invoice = CloneQuoteToInvoiceFactory::create($this->quote, $this->quote->user_id); - $invoice->status_id = Invoice::STATUS_SENT; - $invoice->due_date = null; - $invoice->number = null; - $invoice->save(); + //to prevent circular references we need to explicit call this here. + $mark_approved = new MarkApproved($this->quote->client); + $this->quote = $mark_approved->run($this->quote); - return $invoice->service() - ->markSent() - ->createInvitations() - ->save(); + $this->convert(); + return $this->invoice; } /** @@ -148,6 +144,7 @@ class QuoteService public function save() : ?Quote { $this->quote->save(); + return $this->quote; } } diff --git a/app/Transformers/QuoteTransformer.php b/app/Transformers/QuoteTransformer.php index 673804bdf4d4..c01af6fed651 100644 --- a/app/Transformers/QuoteTransformer.php +++ b/app/Transformers/QuoteTransformer.php @@ -81,7 +81,7 @@ class QuoteTransformer extends EntityTransformer 'client_id' => (string) $this->encodePrimaryKey($quote->client_id), 'status_id' => (string)$quote->status_id, 'design_id' => (string) $this->encodePrimaryKey($quote->design_id), - 'invoice_id' => (string)$quote->invoice_id, + 'invoice_id' => (string)$this->encodePrimaryKey($quote->invoice_id), 'updated_at' => (int)$quote->updated_at, 'archived_at' => (int)$quote->deleted_at, 'created_at' => (int)$quote->created_at, diff --git a/cypress.json b/cypress.json index dec602eece9a..a7564dda0f15 100644 --- a/cypress.json +++ b/cypress.json @@ -1,4 +1,4 @@ { "video": false, - "baseUrl": "http://127.0.0.1:8002/" + "baseUrl": "http://ninja.test:8000/" } diff --git a/resources/views/portal/ninja2020/profile/index.blade.php b/resources/views/portal/ninja2020/profile/index.blade.php index db77d80a9cab..3a7ce9549df8 100644 --- a/resources/views/portal/ninja2020/profile/index.blade.php +++ b/resources/views/portal/ninja2020/profile/index.blade.php @@ -124,7 +124,7 @@