diff --git a/app/Events/General/EntityWasEmailed.php b/app/Events/General/EntityWasEmailed.php new file mode 100644 index 0000000000..b051500aad --- /dev/null +++ b/app/Events/General/EntityWasEmailed.php @@ -0,0 +1,40 @@ +invitation = $invitation; + $this->company = $company; + $this->event_vars = $event_vars; + $this->template = $template; + } +} diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index 9dfda61a7c..b09b3788a4 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -32,6 +32,7 @@ use App\Events\Credit\CreditWasCreated; use App\Events\Credit\CreditWasUpdated; use App\Transformers\CreditTransformer; use Illuminate\Support\Facades\Storage; +use App\Events\General\EntityWasEmailed; use App\Services\Template\TemplateAction; use App\Http\Requests\Credit\BulkCreditRequest; use App\Http\Requests\Credit\EditCreditRequest; @@ -640,10 +641,28 @@ class CreditController extends BaseController case 'email': case 'send_email': + $credit->service()->markSent()->save(); + $credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) { - EmailEntity::dispatch($invitation->withoutRelations(), $credit->company->db, 'credit'); + + $mo = new \App\Services\Email\EmailObject(); + $mo->entity_id = $credit->id; + $mo->entity_class = \App\Models\Credit::class; + $mo->invitation_id = $invitation->id; + $mo->client_id = $invitation->contact->client_id ?? null; + $mo->vendor_id = $invitation->contact->vendor_id ?? null; + $mo->settings = $invitation->contact->client->getMergedSettings(); + $mo->email_template_body = 'email_template_credit'; + $mo->email_template_subject = 'email_subject_credit'; + + \App\Services\Email\Email::dispatch($mo, $invitation->company); + + $credit->entityEmailEvent($invitation, 'credit', 'credit'); + }); + event(new EntityWasEmailed($credit->invitations->first(), $credit->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'credit')); + if (! $bulk) { return response()->json(['message' => 'email sent'], 200); } diff --git a/app/Http/Controllers/EmailController.php b/app/Http/Controllers/EmailController.php index f6c20dfe38..7bda71fd29 100644 --- a/app/Http/Controllers/EmailController.php +++ b/app/Http/Controllers/EmailController.php @@ -11,7 +11,6 @@ namespace App\Http\Controllers; -use App\DataMapper\InvoiceSync; use App\Utils\Ninja; use App\Models\Quote; use App\Models\Credit; @@ -19,6 +18,7 @@ use App\Models\Invoice; use App\Models\Webhook; use App\Models\PurchaseOrder; use App\Services\Email\Email; +use App\DataMapper\InvoiceSync; use App\Utils\Traits\MakesHash; use App\Models\RecurringInvoice; use App\Services\Email\EmailObject; @@ -27,6 +27,7 @@ use App\Transformers\QuoteTransformer; use Illuminate\Mail\Mailables\Address; use App\Events\Credit\CreditWasEmailed; use App\Transformers\CreditTransformer; +use App\Events\General\EntityWasEmailed; use App\Transformers\InvoiceTransformer; use App\Http\Requests\Email\SendEmailRequest; use App\Jobs\PurchaseOrder\PurchaseOrderEmail; @@ -80,7 +81,7 @@ class EmailController extends BaseController } - $entity_obj->invitations->each(function ($invitation) use ($entity_obj, $mo) { + $entity_obj->invitations->each(function ($invitation) use ($entity_obj, $mo, $template) { if (! $invitation->contact->trashed() && $invitation->contact->email) { $entity_obj->service()->markSent()->save(); @@ -89,6 +90,8 @@ class EmailController extends BaseController $mo->vendor_id = $invitation->contact->vendor_id ?? null; Email::dispatch($mo, $invitation->company); + $entity_obj->entityEmailEvent($invitation, $template, $template); + } }); @@ -102,7 +105,7 @@ class EmailController extends BaseController $this->entity_transformer = InvoiceTransformer::class; if ($entity_obj->invitations->count() >= 1) { - $entity_obj->entityEmailEvent($entity_obj->invitations->first(), $template, $template); + event(new EntityWasEmailed($entity_obj->invitations->first(), $entity_obj->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'invoice')); $entity_obj->sendEvent(Webhook::EVENT_SENT_INVOICE, "client"); } } @@ -112,7 +115,7 @@ class EmailController extends BaseController $this->entity_transformer = QuoteTransformer::class; if ($entity_obj->invitations->count() >= 1) { - $entity_obj->entityEmailEvent($entity_obj->invitations->first(), $template); + event(new EntityWasEmailed($entity_obj->invitations->first(), $entity_obj->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'invoice')); $entity_obj->sendEvent(Webhook::EVENT_SENT_QUOTE, "client"); } } @@ -122,7 +125,7 @@ class EmailController extends BaseController $this->entity_transformer = CreditTransformer::class; if ($entity_obj->invitations->count() >= 1) { - event(new CreditWasEmailed($entity_obj->invitations->first(), $entity_obj->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'credit')); + event(new EntityWasEmailed($entity_obj->invitations->first(), $entity_obj->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), 'invoice')); $entity_obj->sendEvent(Webhook::EVENT_SENT_CREDIT, "client"); } } diff --git a/app/Jobs/Mail/NinjaMailer.php b/app/Jobs/Mail/NinjaMailer.php index f46485d3cb..acfe1ec1e5 100644 --- a/app/Jobs/Mail/NinjaMailer.php +++ b/app/Jobs/Mail/NinjaMailer.php @@ -49,7 +49,6 @@ class NinjaMailer extends Mailable $ninja_mailable->text($this->mail_obj->text_view, $this->mail_obj->data); } - nlog($this->mail_obj); if (property_exists($this->mail_obj, 'bcc')) { $ninja_mailable->bcc($this->mail_obj->bcc); } diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php index a78861f221..e2e2342e6d 100644 --- a/app/Jobs/Mail/NinjaMailerJob.php +++ b/app/Jobs/Mail/NinjaMailerJob.php @@ -535,7 +535,7 @@ class NinjaMailerJob implements ShouldQueue if ($sending_user == "0") { $user = $this->company->owner(); } else { - $user = User::find($this->decodePrimaryKey($sending_user)); + $user = User::withTrashed()->find($this->decodePrimaryKey($sending_user)); } return $user; diff --git a/app/Listeners/General/EntityEmailedNotification.php b/app/Listeners/General/EntityEmailedNotification.php new file mode 100644 index 0000000000..df52ba89a1 --- /dev/null +++ b/app/Listeners/General/EntityEmailedNotification.php @@ -0,0 +1,96 @@ +entity_string = match(get_class($invitation)) { + InvoiceInvitation::class => 'invoice', + CreditInvitation::class => 'credit', + QuoteInvitation::class => 'quote', + PurchaseOrderInvitation::class => 'purchase_order', + }; + + return $this; + + } + /** + * Handle the event. + * + * @param object $event + * @return void + */ + public function handle($event) + { + MultiDB::setDb($event->company->db); + + $first_notification_sent = true; + + $this->resolveEntityString($event->invitation); + + $entity = $event->invitation->{$this->entity_string}->fresh(); + $entity->last_sent_date = now(); + $entity->saveQuietly(); + + /* We loop through each user and determine whether they need to be notified */ + foreach ($event->invitation->company->company_users as $company_user) { + /* The User */ + $user = $company_user->user; + + /* Returns an array of notification methods */ + $methods = $this->findUserNotificationTypes($event->invitation, $company_user, $this->entity_string, ['all_notifications', "{$this->entity_string}_sent", "{$this->entity_string}_sent_all", "{$this->entity_string}_sent_user"]); + + /* If one of the methods is email then we fire the EntitySentMailer */ + if (($key = array_search('mail', $methods)) !== false) { + unset($methods[$key]); + + $nmo = new NinjaMailerObject(); + $nmo->mailable = new NinjaMailer((new EntitySentObject($event->invitation, $this->entity_string, $event->template, $company_user->portalType()))->build()); + $nmo->company = $event->invitation->company; + $nmo->settings = $event->invitation->company->settings; + $nmo->to_user = $user; + + (new NinjaMailerJob($nmo))->handle(); + + $nmo = null; + /* This prevents more than one notification being sent */ + $first_notification_sent = false; + } + + } + } +} diff --git a/app/Listeners/Invoice/InvoiceEmailedNotification.php b/app/Listeners/Invoice/InvoiceEmailedNotification.php index 3eadc9d554..79985580e4 100644 --- a/app/Listeners/Invoice/InvoiceEmailedNotification.php +++ b/app/Listeners/Invoice/InvoiceEmailedNotification.php @@ -37,7 +37,7 @@ class InvoiceEmailedNotification implements ShouldQueue */ public function handle($event) { - nlog($event->template); + // nlog($event->template); MultiDB::setDb($event->company->db); diff --git a/app/Listeners/Mail/MailSentListener.php b/app/Listeners/Mail/MailSentListener.php index 4c18eaa544..a37aba40c0 100644 --- a/app/Listeners/Mail/MailSentListener.php +++ b/app/Listeners/Mail/MailSentListener.php @@ -42,7 +42,7 @@ class MailSentListener */ public function handle(MessageSent $event) { - + try { $message_id = $event->sent->getMessageId(); diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 8fd6a20492..102193a233 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -277,6 +277,8 @@ class Activity extends StaticModel public const E_EXPENSE_CREATED = 148; + public const EMAIL_CREDIT = 149; + protected $casts = [ 'is_system' => 'boolean', 'updated_at' => 'timestamp', diff --git a/app/Models/Credit.php b/app/Models/Credit.php index 3bdd3629ba..d2810574ca 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -11,6 +11,7 @@ namespace App\Models; +use App\Utils\Ninja; use App\Utils\Number; use Laravel\Scout\Searchable; use Illuminate\Support\Carbon; @@ -20,6 +21,7 @@ use Illuminate\Support\Facades\App; use App\Utils\Traits\MakesReminders; use App\Services\Credit\CreditService; use App\Services\Ledger\LedgerService; +use App\Events\Credit\CreditWasEmailed; use App\Utils\Traits\MakesInvoiceValues; use Laracasts\Presenter\PresentableTrait; use App\Models\Presenters\CreditPresenter; @@ -430,4 +432,24 @@ class Credit extends BaseModel return ctrans('texts.sent'); } } + + /** + * entityEmailEvent + * + * Translates the email type into an activity + notification + * that matches. + */ + public function entityEmailEvent($invitation, $reminder_template) + { + + switch ($reminder_template) { + case 'credit': + event(new CreditWasEmailed($invitation, $invitation->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null), $reminder_template)); + break; + + default: + // code... + break; + } + } } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index bbec7198f4..52c0b762c9 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -89,6 +89,7 @@ use App\Events\Credit\CreditWasArchived; use App\Events\Credit\CreditWasRestored; use App\Events\Design\DesignWasArchived; use App\Events\Design\DesignWasRestored; +use App\Events\General\EntityWasEmailed; use App\Events\Invoice\InvoiceWasViewed; use App\Events\Misc\InvitationWasViewed; use App\Events\Payment\PaymentWasVoided; @@ -137,10 +138,13 @@ use App\Events\Vendor\VendorContactLoggedIn; use App\Listeners\Quote\QuoteViewedActivity; use App\Listeners\User\ArchivedUserActivity; use App\Listeners\User\RestoredUserActivity; +use App\Events\Invoice\InvoiceAutoBillFailed; use App\Events\Quote\QuoteReminderWasEmailed; use App\Events\Statement\StatementWasEmailed; +use App\Listeners\Credit\CreditEmailActivity; use App\Listeners\Quote\QuoteApprovedWebhook; use App\Listeners\Quote\QuoteDeletedActivity; +use App\Events\Invoice\InvoiceAutoBillSuccess; use App\Listeners\Credit\CreditViewedActivity; use App\Listeners\Invoice\InvoicePaidActivity; use App\Listeners\Payment\PaymentNotification; @@ -155,8 +159,6 @@ use App\Listeners\Activity\TaskUpdatedActivity; use App\Listeners\Invoice\InvoiceEmailActivity; use App\Listeners\SendVerificationNotification; use App\Events\Credit\CreditWasEmailedAndFailed; -use App\Events\Invoice\InvoiceAutoBillFailed; -use App\Events\Invoice\InvoiceAutoBillSuccess; use App\Listeners\Activity\CreatedQuoteActivity; use App\Listeners\Activity\DeleteClientActivity; use App\Listeners\Activity\DeleteCreditActivity; @@ -216,6 +218,7 @@ use App\Listeners\Quote\QuoteReminderEmailActivity; use App\Events\PurchaseOrder\PurchaseOrderWasViewed; use App\Events\Subscription\SubscriptionWasArchived; use App\Events\Subscription\SubscriptionWasRestored; +use App\Listeners\General\EntityEmailedNotification; use App\Events\PurchaseOrder\PurchaseOrderWasCreated; use App\Events\PurchaseOrder\PurchaseOrderWasDeleted; use App\Events\PurchaseOrder\PurchaseOrderWasEmailed; @@ -240,6 +243,8 @@ use App\Events\RecurringQuote\RecurringQuoteWasArchived; use App\Events\RecurringQuote\RecurringQuoteWasRestored; use App\Listeners\Activity\SubscriptionArchivedActivity; use App\Listeners\Activity\SubscriptionRestoredActivity; +use App\Listeners\Invoice\InvoiceAutoBillFailedActivity; +use App\Listeners\Invoice\InvoiceAutoBillSuccessActivity; use App\Listeners\Invoice\InvoiceFailedEmailNotification; use App\Events\RecurringExpense\RecurringExpenseWasCreated; use App\Events\RecurringExpense\RecurringExpenseWasDeleted; @@ -252,8 +257,6 @@ use App\Events\RecurringExpense\RecurringExpenseWasArchived; use App\Events\RecurringExpense\RecurringExpenseWasRestored; use App\Events\RecurringInvoice\RecurringInvoiceWasArchived; use App\Events\RecurringInvoice\RecurringInvoiceWasRestored; -use App\Listeners\Invoice\InvoiceAutoBillFailedActivity; -use App\Listeners\Invoice\InvoiceAutoBillSuccessActivity; use App\Listeners\PurchaseOrder\CreatePurchaseOrderActivity; use App\Listeners\PurchaseOrder\PurchaseOrderViewedActivity; use App\Listeners\PurchaseOrder\UpdatePurchaseOrderActivity; @@ -392,7 +395,8 @@ class EventServiceProvider extends ServiceProvider CreditWasEmailedAndFailed::class => [ ], CreditWasEmailed::class => [ - CreditEmailedNotification::class, + CreditEmailActivity::class, + // CreditEmailedNotification::class, ], CreditWasMarkedSent::class => [ ], @@ -414,6 +418,9 @@ class EventServiceProvider extends ServiceProvider ], DesignWasRestored::class => [ ], + EntityWasEmailed::class => [ + EntityEmailedNotification::class, + ], ExpenseWasCreated::class => [ CreatedExpenseActivity::class, ], @@ -453,7 +460,7 @@ class EventServiceProvider extends ServiceProvider ], InvoiceWasEmailed::class => [ InvoiceEmailActivity::class, - InvoiceEmailedNotification::class, + // InvoiceEmailedNotification::class, ], InvoiceWasEmailedAndFailed::class => [ InvoiceEmailFailedActivity::class, @@ -461,7 +468,7 @@ class EventServiceProvider extends ServiceProvider ], InvoiceReminderWasEmailed::class => [ InvoiceReminderEmailActivity::class, - InvoiceEmailedNotification::class, + // InvoiceEmailedNotification::class, ], InvoiceWasDeleted::class => [ InvoiceDeletedActivity::class, @@ -499,7 +506,7 @@ class EventServiceProvider extends ServiceProvider ], PurchaseOrderWasEmailed::class => [ PurchaseOrderEmailActivity::class, - PurchaseOrderEmailedNotification::class, + // PurchaseOrderEmailedNotification::class, ], PurchaseOrderWasRestored::class => [ PurchaseOrderRestoredActivity::class, diff --git a/app/Repositories/ActivityRepository.php b/app/Repositories/ActivityRepository.php index 7828f1243e..79c0e43974 100644 --- a/app/Repositories/ActivityRepository.php +++ b/app/Repositories/ActivityRepository.php @@ -66,7 +66,9 @@ class ActivityRepository extends BaseRepository $activity->save(); //rate limiter - $this->createBackup($entity, $activity); + if(!in_array($fields->activity_type_id, [Activity::EMAIL_INVOICE, Activity::EMAIL_CREDIT, Activity::EMAIL_QUOTE, Activity::EMAIL_PURCHASE_ORDER])){ + $this->createBackup($entity, $activity); + } } /** diff --git a/app/Services/Pdf/Purify.php b/app/Services/Pdf/Purify.php index b5c87b67ce..5ce983f8b1 100644 --- a/app/Services/Pdf/Purify.php +++ b/app/Services/Pdf/Purify.php @@ -244,7 +244,6 @@ class Purify $html = str_replace('%24', '$', $html); libxml_use_internal_errors(true); libxml_disable_entity_loader(true); -// nlog("pre purify => {$html}"); $document = new \DOMDocument(); @$document->loadHTML(htmlspecialchars_decode(htmlspecialchars($html, ENT_QUOTES, 'UTF-8'))); diff --git a/lang/en/texts.php b/lang/en/texts.php index cb4d3b769c..b86ac2c135 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5487,6 +5487,8 @@ $lang = array( 'enable_public_notifications_help' => 'Enable real-time notifications from Invoice Ninja.', 'navigate' => 'Navigate', 'calculate_taxes_warning' => 'This action will enable line item taxes and disable total taxes. Any open invoices may be recalculated with the new settings!', + 'activity_149' => ':user emailed credit :credit for :client to :contact', + ); return $lang;