From 24aa73c3598ac19560c4956ff371d6dd5d136e3f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 19 Jan 2023 17:20:31 +1100 Subject: [PATCH 1/5] Fixes for notifications --- .../RecurringInvoiceController.php | 24 +-- app/Jobs/Inventory/AdjustProductInventory.php | 19 +- app/Services/Invoice/InvoiceService.php | 2 +- .../Traits/Notifications/UserNotifies.php | 34 ++-- tests/Feature/Notify/NotificationTest.php | 183 ++++++++++++++++++ 5 files changed, 230 insertions(+), 32 deletions(-) create mode 100644 tests/Feature/Notify/NotificationTest.php diff --git a/app/Http/Controllers/ClientPortal/RecurringInvoiceController.php b/app/Http/Controllers/ClientPortal/RecurringInvoiceController.php index d610d4515f82..037444c3e9e5 100644 --- a/app/Http/Controllers/ClientPortal/RecurringInvoiceController.php +++ b/app/Http/Controllers/ClientPortal/RecurringInvoiceController.php @@ -51,6 +51,7 @@ class RecurringInvoiceController extends Controller * * @param ShowRecurringInvoiceRequest $request * @param RecurringInvoice $recurring_invoice + * * @return Factory|View */ public function show(ShowRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice) @@ -60,20 +61,24 @@ class RecurringInvoiceController extends Controller ]); } + /** + * Handle the request cancellation notification + * + * @param RequestCancellationRequest $request [description] + * @param RecurringInvoice $recurring_invoice [description] + * + * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse + */ public function requestCancellation(RequestCancellationRequest $request, RecurringInvoice $recurring_invoice) { - nlog('outside cancellation'); if ($recurring_invoice->subscription?->allow_cancellation) { - nlog('inside the cancellation'); $nmo = new NinjaMailerObject; - $nmo->mailable = (new NinjaMailer((new ClientContactRequestCancellationObject($recurring_invoice, auth()->user()))->build())); + $nmo->mailable = (new NinjaMailer((new ClientContactRequestCancellationObject($recurring_invoice, auth()->user(), false))->build())); $nmo->company = $recurring_invoice->company; $nmo->settings = $recurring_invoice->company->settings; - // $notifiable_users = $this->filterUsersByPermissions($recurring_invoice->company->company_users, $recurring_invoice, ['recurring_cancellation']); - $recurring_invoice->company->company_users->each(function ($company_user) use ($nmo) { $methods = $this->findCompanyUserNotificationType($company_user, ['recurring_cancellation', 'all_notifications']); @@ -86,15 +91,6 @@ class RecurringInvoiceController extends Controller } }); - // $notifiable_users->each(function ($company_user) use($nmo){ - - // $nmo->to_user = $company_user->user; - // NinjaMailerJob::dispatch($nmo); - - // }); - - //$recurring_invoice->user->notify(new ClientContactRequestCancellation($recurring_invoice, auth()->user())); - return $this->render('recurring_invoices.cancellation.index', [ 'invoice' => $recurring_invoice, ]); diff --git a/app/Jobs/Inventory/AdjustProductInventory.php b/app/Jobs/Inventory/AdjustProductInventory.php index 7846a5ffdc28..79b796398838 100644 --- a/app/Jobs/Inventory/AdjustProductInventory.php +++ b/app/Jobs/Inventory/AdjustProductInventory.php @@ -19,6 +19,7 @@ use App\Mail\Admin\InventoryNotificationObject; use App\Models\Company; use App\Models\Invoice; use App\Models\Product; +use App\Utils\Traits\Notifications\UserNotifies; use App\Utils\Traits\NumberFormatter; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -29,7 +30,7 @@ use Illuminate\Queue\SerializesModels; class AdjustProductInventory implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies; public Company $company; @@ -146,8 +147,22 @@ class AdjustProductInventory implements ShouldQueue $nmo->mailable = new NinjaMailer((new InventoryNotificationObject($product, $notification_level))->build()); $nmo->company = $this->company; $nmo->settings = $this->company->settings; + + // $product->company_users->each(function ($cu) use($product, $nmo){ + + // if($this->checkNotificationExists($cu, $product, ['inventory_all', 'inventory_user'])) + // { + + // $nmo->to_user = $cu->user; + // (new NinjaMailerJob($nmo))->handle(); + + // } + + // }); + $nmo->to_user = $this->company->owner(); - NinjaMailerJob::dispatch($nmo); + (new NinjaMailerJob($nmo))->handle(); + } } diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 0fcb71899d71..d3698908bd86 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -526,7 +526,7 @@ class InvoiceService $this->invoice->exchange_rate = $this->invoice->client->currency()->exchange_rate; } - if ($settings->auto_bill_standard_invoices) { + if ($this->invoice->client->getSetting('auto_bill_standard_invoices')) { $this->invoice->auto_bill_enabled = true; } diff --git a/app/Utils/Traits/Notifications/UserNotifies.php b/app/Utils/Traits/Notifications/UserNotifies.php index 1a4baabe7081..d4fd338971b1 100644 --- a/app/Utils/Traits/Notifications/UserNotifies.php +++ b/app/Utils/Traits/Notifications/UserNotifies.php @@ -15,6 +15,7 @@ use App\Models\Client; use App\Models\Credit; use App\Models\Invoice; use App\Models\Payment; +use App\Models\Product; use App\Models\PurchaseOrder; use App\Models\Quote; @@ -41,7 +42,7 @@ trait UserNotifies } //if a user owns this record or is assigned to it, they are attached the permission for notification. - if ($invitation->{$entity_name}->user_id == $company_user->_user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id) { + if ($invitation->{$entity_name}->user_id == $company_user->user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id) { $required_permissions = $this->addSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); } else { $required_permissions = $this->removeSpecialUserPermissionForEntity($invitation->{$entity_name}, $required_permissions); @@ -67,7 +68,7 @@ trait UserNotifies return []; } - if ($entity->user_id == $company_user->_user_id || $entity->assigned_user_id == $company_user->user_id) { + if ($entity->user_id == $company_user->user_id || $entity->assigned_user_id == $company_user->user_id) { $required_permissions = $this->addSpecialUserPermissionForEntity($entity, $required_permissions); } else { $required_permissions = $this->removeSpecialUserPermissionForEntity($entity, $required_permissions); @@ -87,22 +88,18 @@ trait UserNotifies switch ($entity) { case $entity instanceof Payment || $entity instanceof Client: //we pass client also as this is the proxy for Payment Failures (ie, there is no payment) return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'payment_failure_user', 'payment_success_user']); - break; case $entity instanceof Invoice: return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'invoice_created_user', 'invoice_sent_user', 'invoice_viewed_user', 'invoice_late_user']); - break; case $entity instanceof Quote: return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'quote_created_user', 'quote_sent_user', 'quote_viewed_user', 'quote_approved_user', 'quote_expired_user']); - break; case $entity instanceof Credit: return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'credit_created_user', 'credit_sent_user', 'credit_viewed_user']); - break; case $entity instanceof PurchaseOrder: return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'purchase_order_created_user', 'purchase_order_sent_user', 'purchase_order_viewed_user']); - break; + case $entity instanceof Product: + return array_merge($required_permissions, ['all_notifications', 'all_user_notifications', 'inventory_user', 'inventory_all']); default: return []; - break; } } @@ -113,19 +110,16 @@ trait UserNotifies switch ($entity) { case $entity instanceof Payment || $entity instanceof Client: //we pass client also as this is the proxy for Payment Failures (ie, there is no payment) return array_diff($required_permissions, ['all_user_notifications', 'payment_failure_user', 'payment_success_user']); - break; case $entity instanceof Invoice: return array_diff($required_permissions, ['all_user_notifications', 'invoice_created_user', 'invoice_sent_user', 'invoice_viewed_user', 'invoice_late_user']); - break; case $entity instanceof Quote: return array_diff($required_permissions, ['all_user_notifications', 'quote_created_user', 'quote_sent_user', 'quote_viewed_user', 'quote_approved_user', 'quote_expired_user']); - break; case $entity instanceof Credit: return array_diff($required_permissions, ['all_user_notifications', 'credit_created_user', 'credit_sent_user', 'credit_viewed_user']); - break; case $entity instanceof PurchaseOrder: return array_diff($required_permissions, ['all_user_notifications', 'purchase_order_created_user', 'purchase_order_sent_user', 'purchase_order_viewed_user']); - break; + case $entity instanceof Product: + return array_diff($required_permissions, ['all_user_notifications', 'inventory_user']); default: // code... break; @@ -165,13 +159,23 @@ trait UserNotifies }); } - private function checkNotificationExists($company_user, $entity, $required_notification) + /** + * Underrated method right here, last ones + * are always the best + * + * @param CompanyUser $company_user + * @param Invoice | Quote | Credit | PurchaseOrder | Product $entity + * @param array $required_notification + * + * @return bool + */ + private function checkNotificationExists($company_user, $entity, $required_notification): bool { /* Always make sure we push the `all_notificaitons` into the mix */ array_push($required_notification, 'all_notifications'); /* Selectively add the all_user if the user is associated with the entity */ - if ($entity->user_id == $company_user->_user_id || $entity->assigned_user_id == $company_user->user_id) { + if ($entity->user_id == $company_user->user_id || $entity->assigned_user_id == $company_user->user_id) { array_push($required_notification, 'all_user_notifications'); } diff --git a/tests/Feature/Notify/NotificationTest.php b/tests/Feature/Notify/NotificationTest.php new file mode 100644 index 000000000000..f82b105ad01e --- /dev/null +++ b/tests/Feature/Notify/NotificationTest.php @@ -0,0 +1,183 @@ +withoutMiddleware( + ThrottleRequests::class + ); + + $this->makeTestData(); + } + + public function testNotificationFound() + { + $notifications = new \stdClass; + $notifications->email = ["inventory_all"]; + + $this->user->company_users()->where('company_id', $this->company->id)->update(['notifications' => (array)$notifications]); + + $this->assertTrue(property_exists($this->cu->notifications,'email')); + + $p = Product::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id + ]); + + $notification_users = $this->filterUsersByPermissions($this->company->company_users, $p, ['inventory_all']); + $this->assertCount(1, $notification_users->toArray()); + + $notification_users = $this->filterUsersByPermissions($this->company->company_users, $p, ['inventory_user']); + $this->assertCount(0, $notification_users->toArray()); + + $notification_users = $this->filterUsersByPermissions($this->company->company_users, $p, ['inventory_user','invalid notification']); + $this->assertCount(0, $notification_users->toArray()); + + } + + public function testAllNotificationsFires() + { + $notifications = new \stdClass; + $notifications->email = ["all_notifications"]; + + $p = Product::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id + ]); + + $this->user->company_users()->where('company_id', $this->company->id)->update(['notifications' => (array)$notifications]); + + $notification_users = $this->filterUsersByPermissions($this->company->company_users, $p, ['inventory_all']); + $this->assertCount(1, $notification_users->toArray()); + + } + + public function testAllNotificationsFiresForUser() + { + $notifications = new \stdClass; + $notifications->email = ["all_user_notifications"]; + + $p = Product::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id + ]); + + $this->user->company_users()->where('company_id', $this->company->id)->update(['notifications' => (array)$notifications]); + + $notification_users = $this->filterUsersByPermissions($this->company->company_users, $p, ['all_user_notifications']); + $this->assertCount(1, $notification_users->toArray()); + + } + + + public function testAllNotificationsDoesNotFiresForUser() + { + $u = User::factory()->create([ + 'account_id' => $this->account->id, + 'email' => $this->faker->safeEmail(), + 'confirmation_code' => uniqid("st",true), + ]); + + $company_token = new CompanyToken; + $company_token->user_id = $u->id; + $company_token->company_id = $this->company->id; + $company_token->account_id = $this->account->id; + $company_token->name = 'test token'; + $company_token->token = Str::random(64); + $company_token->is_system = true; + $company_token->save(); + + $u->companies()->attach($this->company->id, [ + 'account_id' => $this->account->id, + 'is_owner' => 1, + 'is_admin' => 1, + 'is_locked' => 0, + 'notifications' => CompanySettings::notificationDefaults(), + 'settings' => null, + ]); + + $p = Product::factory()->create([ + 'user_id' => $u->id, + 'company_id' => $this->company->id + ]); + + + $notifications = new \stdClass; + $notifications->email = ["all_user_notifications"]; + $this->user->company_users()->where('company_id', $this->company->id)->update(['notifications' => (array)$notifications]); + + $methods = $this->findUserEntityNotificationType($p, $this->cu, ['all_user_notifications']); + $this->assertCount(0, $methods); + + $methods = $this->findUserEntityNotificationType($p, $this->cu, ['all_notifications']); + $this->assertCount(0, $methods); + + $notifications = []; + $notifications['email'] = ["all_notifications"]; + + $cu = CompanyUser::where('company_id', $this->company->id)->where('user_id', $this->user->id)->first(); + $cu->notifications = $notifications; + $cu->save(); + + $methods = $this->findUserEntityNotificationType($p, $cu, ["all_notifications"]); + + $this->assertCount(1, $methods); + + $notifications = []; + $notifications['email'] = ["inventory_user"]; + + $cu = CompanyUser::where('company_id', $this->company->id)->where('user_id', $this->user->id)->first(); + $cu->notifications = $notifications; + $cu->save(); + + $methods = $this->findUserEntityNotificationType($p, $cu, ["all_notifications"]); + $this->assertCount(0, $methods); + + $p = Product::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id + ]); + + $methods = $this->findUserEntityNotificationType($p, $cu, []); + + nlog($methods); + + $this->assertCount(1, $methods); + + + } + + +} From c62456b3197d1e96a0671641489487a8e7ac0ddc Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 20 Jan 2023 10:58:24 +1100 Subject: [PATCH 2/5] Minor fixes for import --- app/Jobs/Account/CreateAccount.php | 2 +- app/Jobs/Company/CompanyImport.php | 6 ++++++ app/Jobs/Util/Import.php | 11 +++++++++++ app/Models/Document.php | 5 +++++ app/Policies/DocumentPolicy.php | 9 +++++++++ 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/Jobs/Account/CreateAccount.php b/app/Jobs/Account/CreateAccount.php index 5c35378b8026..169892cf6956 100644 --- a/app/Jobs/Account/CreateAccount.php +++ b/app/Jobs/Account/CreateAccount.php @@ -86,7 +86,7 @@ class CreateAccount $sp794f3f->hosted_company_count = config('ninja.quotas.free.max_companies'); $sp794f3f->account_sms_verified = true; - if(in_array($this->getDomain($this->request['email']), ['givmail.com','yopmail.com','gmail.com', 'hotmail.com', 'outlook.com', 'yahoo.com', 'aol.com', 'mail.ru'])){ + if(in_array($this->getDomain($this->request['email']), ['givmail.com','yopmail.com','gmail.com', 'hotmail.com', 'outlook.com', 'yahoo.com', 'aol.com', 'mail.ru','brand-app.biz','proton.me','ema-sofia.eu'])){ $sp794f3f->account_sms_verified = false; } diff --git a/app/Jobs/Company/CompanyImport.php b/app/Jobs/Company/CompanyImport.php index 03359ef0001a..35fa2167199e 100644 --- a/app/Jobs/Company/CompanyImport.php +++ b/app/Jobs/Company/CompanyImport.php @@ -506,6 +506,12 @@ class CompanyImport implements ShouldQueue } + if(Ninja::isHosted()) + { + $this->company->portal_mode = 'sub_domain'; + $this->company->portal_domain = ''; + } + $this->company->save(); return $this; diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index b2f9dfd33bdb..1b659d5923e8 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -516,6 +516,12 @@ class Import implements ShouldQueue } + if(Ninja::isHosted()) + { + $data['portal_mode'] = 'subdomain'; + $data['portal_domain'] = ''; + } + $data['settings'] = $company_settings; } @@ -564,6 +570,11 @@ class Import implements ShouldQueue TaxRate::reguard(); + if(TaxRate::count() > 0){ + $this->company->enabled_tax_rates = 2; + $this->company->save(); + } + /*Improve memory handling by setting everything to null when we have finished*/ $data = null; $rules = null; diff --git a/app/Models/Document.php b/app/Models/Document.php index 9205fec8b3e6..33c3573bf076 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -101,6 +101,11 @@ class Document extends BaseModel return $this->morphTo(); } + public function user() + { + return $this->belongsTo(User::class)->withTrashed(); + } + public function generateUrl($absolute = false) { $url = Storage::disk($this->disk)->url($this->url); diff --git a/app/Policies/DocumentPolicy.php b/app/Policies/DocumentPolicy.php index 5ac01f5146b8..f6d72b31110d 100644 --- a/app/Policies/DocumentPolicy.php +++ b/app/Policies/DocumentPolicy.php @@ -1,4 +1,13 @@ Date: Fri, 20 Jan 2023 15:17:21 +1100 Subject: [PATCH 3/5] Minor fixes for logging --- app/Console/Commands/CheckData.php | 58 ++++++++++++++++++++-------- app/Providers/AppServiceProvider.php | 11 ++++++ 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index 6033dabcdc32..fd934399fe43 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -28,10 +28,14 @@ use App\Models\Invoice; use App\Models\InvoiceInvitation; use App\Models\Payment; use App\Models\Paymentable; +use App\Models\PurchaseOrder; +use App\Models\PurchaseOrderInvitation; +use App\Models\Quote; use App\Models\QuoteInvitation; use App\Models\RecurringInvoiceInvitation; use App\Models\User; use App\Models\Vendor; +use App\Models\VendorContact; use App\Utils\Ninja; use Exception; use Illuminate\Console\Command; @@ -397,29 +401,49 @@ class CheckData extends Command QuoteInvitation::where('deleted_at',"0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]); CreditInvitation::where('deleted_at',"0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]); - $entities = ['invoice', 'quote', 'credit', 'recurring_invoice']; - foreach($entities as $entity) - { - $table = "{$entity}s"; - $invitation_table = "{$entity}_invitations"; + collect([Invoice::class, Quote::class, Credit::class, PurchaseOrder::class])->each(function ($entity){ - $entities = DB::table($table) - ->leftJoin($invitation_table, function ($join) use($invitation_table, $table, $entity){ - $join->on("{$invitation_table}.{$entity}_id", '=', "{$table}.id"); - // ->whereNull("{$invitation_table}.deleted_at"); - }) - ->groupBy("{$table}.id", "{$table}.user_id", "{$table}.company_id", "{$table}.client_id") - ->havingRaw("count({$invitation_table}.id) = 0") - ->get(["{$table}.id", "{$table}.user_id", "{$table}.company_id", "{$table}.client_id"]); + if($entity::doesntHave('invitations')->count() > 0) + { + $entity::doesntHave('invitations')->cursor()->each(function ($entity) { - $this->logMessage($entities->count()." {$table} without any invitations"); + $client_vendor_key = 'client_id'; + $contact_id = 'client_contact_id'; + $contact_class = ClientContact::class; - if ($this->option('fix') == 'true') - $this->fixInvitations($entities, $entity); + $entity_key = \Illuminate\Support\Str::of(class_basename($entity))->snake()->append('_id')->value; + $entity_obj = get_class($entity).'Invitation'; - } + if($entity instanceof PurchaseOrder){ + $client_vendor_key = 'vendor_id'; + $contact_id = 'vendor_contact_id'; + $contact_class = VendorContact::class; + } + + $invitation = new $entity_obj(); + $invitation->company_id = $entity->company_id; + $invitation->user_id = $entity->user_id; + $invitation->{$entity_key} = $entity->id; + $invitation->{$contact_id} = $contact_class::where('company_id', $entity->company_id)->where($client_vendor_key,$entity->{$client_vendor_key})->first()->id; + $invitation->key = Str::random(config('ninja.key_length')); + + $this->logMessage("Add invitation for {$entity_key} - {$entity->id}"); + + try{ + $invitation->save(); + } + catch(\Exception $e){ + $this->logMessage($e->getMessage()); + $invitation = null; + } + + }); + + } + + }); } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 28664dd3b9aa..14a1c388c3d8 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -42,6 +42,17 @@ class AppServiceProvider extends ServiceProvider public function boot() { + // DB::listen(function($query) { + // nlog( + // $query->sql, + // [ + // 'bindings' => $query->bindings, + // 'time' => $query->time + // ] + // ); + // }); + + Relation::morphMap([ 'invoices' => Invoice::class, 'proposals' => Proposal::class, From 784d28ef0f631073c23968d919194728f263fe5a Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 20 Jan 2023 15:55:05 +1100 Subject: [PATCH 4/5] Improve app state by ensuring a invitation is always present for an entity when a contact is deleted --- app/Observers/ClientContactObserver.php | 31 +++++++++ app/Observers/VendorContactObserver.php | 85 +++++++++++++++++++++++++ app/Providers/EventServiceProvider.php | 3 + 3 files changed, 119 insertions(+) create mode 100644 app/Observers/VendorContactObserver.php diff --git a/app/Observers/ClientContactObserver.php b/app/Observers/ClientContactObserver.php index 398db1c8a2f5..2e98506958af 100644 --- a/app/Observers/ClientContactObserver.php +++ b/app/Observers/ClientContactObserver.php @@ -12,6 +12,9 @@ namespace App\Observers; use App\Models\ClientContact; +use App\Models\InvoiceInvitation; +use App\Models\QuoteInvitation; +use App\Models\RecurringInvoiceInvitation; class ClientContactObserver { @@ -45,10 +48,38 @@ class ClientContactObserver */ public function deleted(ClientContact $clientContact) { + $client_contact_id = $clientContact->id; + $clientContact->invoice_invitations()->delete(); $clientContact->quote_invitations()->delete(); $clientContact->credit_invitations()->delete(); $clientContact->recurring_invoice_invitations()->delete(); + + //ensure entity state is preserved + + InvoiceInvitation::withTrashed()->where('client_contact_id', 1)->cursor()->each(function ($invite){ + + if($invite->invoice()->doesnthave('invitations')) + $invite->invoice->service()->createInvitations(); + + }); + + + QuoteInvitation::withTrashed()->where('client_contact_id', 1)->cursor()->each(function ($invite){ + + if($invite->invoice()->doesnthave('invitations')) + $invite->quote->service()->createInvitations(); + + }); + + RecurringInvoiceInvitation::withTrashed()->where('client_contact_id', 1)->cursor()->each(function ($invite){ + + if($invite->recurring_invoice()->doesnthave('invitations')) + $invite->quote->service()->createInvitations(); + + }); + + } /** diff --git a/app/Observers/VendorContactObserver.php b/app/Observers/VendorContactObserver.php new file mode 100644 index 000000000000..41e9833fa61c --- /dev/null +++ b/app/Observers/VendorContactObserver.php @@ -0,0 +1,85 @@ +id; + + $vendorContact->purchase_order_invitations()->delete(); + + PurchaseOrderInvitation::withTrashed()->where('vendor_contact_id', 1)->cursor()->each(function ($invite){ + + if($invite->purchase_order()->doesnthave('invitations')) + $invite->purchase_order->service()->createInvitations(); + + }); + + + } + + /** + * Handle the vendor contact "restored" event. + * + * @param VendorContact $vendorContact + * @return void + */ + public function restored(VendorContact $vendorContact) + { + + } + + /** + * Handle the vendor contact "force deleted" event. + * + * @param VendorContact $vendorContact + * @return void + */ + public function forceDeleted(VendorContact $vendorContact) + { + // + } +} diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index c176963823ee..00294a6eb2f8 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -241,6 +241,7 @@ use App\Models\Quote; use App\Models\Subscription; use App\Models\Task; use App\Models\User; +use App\Models\VendorContact; use App\Observers\AccountObserver; use App\Observers\ClientContactObserver; use App\Observers\ClientObserver; @@ -257,6 +258,7 @@ use App\Observers\ProposalObserver; use App\Observers\PurchaseOrderObserver; use App\Observers\QuoteObserver; use App\Observers\SubscriptionObserver; +use App\Observers\VendorContactObserver; use App\Observers\TaskObserver; use App\Observers\UserObserver; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; @@ -649,6 +651,7 @@ class EventServiceProvider extends ServiceProvider Quote::observe(QuoteObserver::class); Task::observe(TaskObserver::class); User::observe(UserObserver::class); + VendorContact::observe(VendorContactObserver::class); PurchaseOrder::observe(PurchaseOrderObserver::class); } From 0d11fc174a04700cb941ed158a9fdf989b607396 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 20 Jan 2023 17:18:53 +1100 Subject: [PATCH 5/5] Send payment emails to all contacts on invitation --- app/Services/Payment/SendEmail.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app/Services/Payment/SendEmail.php b/app/Services/Payment/SendEmail.php index 828023381385..93d5b03fc817 100644 --- a/app/Services/Payment/SendEmail.php +++ b/app/Services/Payment/SendEmail.php @@ -32,12 +32,27 @@ class SendEmail */ public function run() { - $this->payment->load('company', 'client.contacts'); + $this->payment->load('company', 'client.contacts','invoices'); $contact = $this->payment->client->contacts()->first(); - if ($contact?->email) - EmailPayment::dispatch($this->payment, $this->payment->company, $contact)->delay(now()->addSeconds(8)); + // if ($contact?->email) + // EmailPayment::dispatch($this->payment, $this->payment->company, $contact)->delay(now()->addSeconds(2)); + + + $this->payment->invoices->sortByDesc('id')->first(function ($invoice){ + + $invoice->invitations->each(function ($invitation) { + + if(!$invitation->contact->trashed() && $invitation->contact->email) { + + EmailPayment::dispatch($this->payment, $this->payment->company, $invitation->contact)->delay(now()->addSeconds(2)); + + } + + }); + + }); } }