mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Ft email (#3326)
* Emails * change to user service * refactor emails * refactor emails * refactor emails * refactor emails * emails * emails * emails * emails * emails * emails * emails * emails * emails * emails * Update EmailPayment.php * Update SendEmail.php * Update SendEmail.php * Update SendEmail.php * Update and rename BuildEmail.php to EmailBuilder.php * Create InvoiceEmail * Create QuoteEmail.php * Rename InvoiceEmail to InvoiceEmail.php * Create PaymentEmail.php * Update SendEmail.php * Update SendEmail.php * Update SendEmail.php * Update SendEmail.php * Update InvoiceEmail.php * Update EmailInvoice.php * Update SendEmail.php * Update TemplateEmail.php * Update EmailBuilder.php * Update InvoiceEmail.php * Update QuoteEmail.php * Update PaymentEmail.php * Update InvoiceEmail.php * Update QuoteEmail.php * Update QuoteInvitation.php * Update EmailQuote.php * Update SendEmail.php * Update SendEmail.php * Update PaymentService.php * Update PaymentEmail.php * Update PaymentEmail.php * Update PaymentEmail.php * Update EmailBuilder.php * Update PaymentEmail.php * Update EmailPayment.php * Update SendEmail.php * Update InvoiceService.php * Update SendEmail.php * Update PaymentService.php * Update SendEmail.php * Update QuoteService.php * Update EmailPayment.php Co-authored-by: David Bomba <turbo124@gmail.com>
This commit is contained in:
parent
7dd6f814ac
commit
f7650d0692
154
app/Helpers/Email/EmailBuilder.php
Normal file
154
app/Helpers/Email/EmailBuilder.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Helpers\Email;
|
||||
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Quote;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
|
||||
abstract class EmailBuilder
|
||||
{
|
||||
protected $subject;
|
||||
protected $body;
|
||||
protected $recipients;
|
||||
protected $attachments;
|
||||
protected $footer;
|
||||
protected $template_style;
|
||||
protected $variables = [];
|
||||
protected $contact = null;
|
||||
|
||||
private function parseTemplate(string $data, bool $is_markdown = true, $contact = null): string
|
||||
{
|
||||
//process variables
|
||||
if (!empty($this->variables)) {
|
||||
$data = str_replace(array_keys($this->variables), array_values($this->variables), $data);
|
||||
}
|
||||
|
||||
//process markdown
|
||||
if ($is_markdown) {
|
||||
//$data = Parsedown::instance()->line($data);
|
||||
|
||||
$converter = new CommonMarkConverter([
|
||||
'html_input' => 'allow',
|
||||
'allow_unsafe_links' => true,
|
||||
]);
|
||||
|
||||
$data = $converter->convertToHtml($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $footer
|
||||
* @return $this
|
||||
*/
|
||||
public function setFooter($footer)
|
||||
{
|
||||
$this->footer = $footer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setVariables($variables)
|
||||
{
|
||||
$this->variables = $variables;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $contact
|
||||
* @return $this
|
||||
*/
|
||||
public function setContact($contact)
|
||||
{
|
||||
$this->contact = $contact;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $subject
|
||||
* @return $this
|
||||
*/
|
||||
public function setSubject($subject)
|
||||
{
|
||||
$this->subject = $this->parseTemplate($subject, false, $this->contact);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $body
|
||||
* @return $this
|
||||
*/
|
||||
public function setBody($body)
|
||||
{
|
||||
$this->parseTemplate($body, true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $template_style
|
||||
* @return $this
|
||||
*/
|
||||
public function setTemplate($template_style)
|
||||
{
|
||||
$this->template_style = $template_style;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAttachments($attachments)
|
||||
{
|
||||
$this->attachments[] = $attachments;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSubject()
|
||||
{
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBody()
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRecipients()
|
||||
{
|
||||
return $this->recipients;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttachments()
|
||||
{
|
||||
return $this->attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFooter()
|
||||
{
|
||||
return $this->footer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTemplate()
|
||||
{
|
||||
return $this->template_style;
|
||||
}
|
||||
}
|
61
app/Helpers/Email/InvoiceEmail.php
Normal file
61
app/Helpers/Email/InvoiceEmail.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: michael.hampton
|
||||
* Date: 14/02/2020
|
||||
* Time: 19:51
|
||||
*/
|
||||
|
||||
namespace App\Helpers\Email;
|
||||
|
||||
|
||||
use App\Models\Invoice;
|
||||
|
||||
class InvoiceEmail extends EmailBuilder
|
||||
{
|
||||
public function build(Invoice $invoice, $reminder_template, $contact = null)
|
||||
{
|
||||
$client = $invoice->client;
|
||||
|
||||
$body_template = $client->getSetting('email_template_' . $reminder_template);
|
||||
|
||||
/* Use default translations if a custom message has not been set*/
|
||||
if (iconv_strlen($body_template) == 0) {
|
||||
$body_template = trans('texts.invoice_message',
|
||||
['amount' => $invoice->present()->amount(), 'company' => $invoice->company->present()->name()], null,
|
||||
$invoice->client->locale());
|
||||
}
|
||||
|
||||
$subject_template = $client->getSetting('email_subject_' . $reminder_template);
|
||||
|
||||
if (iconv_strlen($subject_template) == 0) {
|
||||
if ($reminder_template == 'quote') {
|
||||
$subject_template = trans('texts.invoice_subject',
|
||||
[
|
||||
'number' => $this->invoice->present()->invoice_number(),
|
||||
'company' => $invoice->company->present()->name()
|
||||
],
|
||||
null, $invoice->client->locale());
|
||||
} else {
|
||||
$subject_template = trans('texts.reminder_subject',
|
||||
[
|
||||
'number' => $invoice->present()->invoice_number(),
|
||||
'company' => $invoice->company->present()->name()
|
||||
],
|
||||
null, $invoice->client->locale());
|
||||
}
|
||||
}
|
||||
|
||||
$this->setTemplate($invoice->client->getSetting('email_style'))
|
||||
->setContact($contact)
|
||||
->setVariables($invoice->makeValues($contact))
|
||||
->setSubject($subject_template)
|
||||
->setBody($body_template)
|
||||
->setFooter("<a href='{$invoice->invitations->first()->getLink()}'>Invoice Link</a>");
|
||||
|
||||
if ($client->getSetting('pdf_email_attachment') !== false) {
|
||||
$this->setAttachments($invoice->pdf_file_path());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
43
app/Helpers/Email/PaymentEmail.php
Normal file
43
app/Helpers/Email/PaymentEmail.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: michael.hampton
|
||||
* Date: 14/02/2020
|
||||
* Time: 19:51
|
||||
*/
|
||||
|
||||
namespace App\Helpers\Email;
|
||||
|
||||
use App\Models\Payment;
|
||||
|
||||
|
||||
class EmailPayment extends EmailBuilder
|
||||
{
|
||||
public function build(Payment $payment, $contact = null) {
|
||||
$client = $payment->client;
|
||||
|
||||
$body_template = $client->getSetting('email_template_payment');
|
||||
|
||||
/* Use default translations if a custom message has not been set*/
|
||||
if (iconv_strlen($body_template) == 0) {
|
||||
|
||||
$body_template = trans('texts.payment_message',
|
||||
['amount' => $payment->amount, 'company' => $payment->company->present()->name()], null,
|
||||
$this->client->locale());
|
||||
}
|
||||
|
||||
$subject_template = $client->getSetting('email_subject_payment');
|
||||
|
||||
if (iconv_strlen($subject_template) == 0) {
|
||||
$subject_template = trans('texts.payment_subject',
|
||||
['number' => $payment->number, 'company' => $payment->company->present()->name()], null,
|
||||
$payment->client->locale());
|
||||
}
|
||||
|
||||
$this->setTemplate($payment->client->getSetting('email_style'))
|
||||
->setSubject($subject_template)
|
||||
->setBody($body_template);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
58
app/Helpers/Email/QuoteEmail.php
Normal file
58
app/Helpers/Email/QuoteEmail.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: michael.hampton
|
||||
* Date: 14/02/2020
|
||||
* Time: 19:51
|
||||
*/
|
||||
|
||||
namespace App\Helpers\Email;
|
||||
|
||||
use App\Models\Quote;
|
||||
|
||||
|
||||
class QuoteEmail extends EmailBuilder
|
||||
{
|
||||
|
||||
public function build(Quote $quote, $reminder_template, $contact = null)
|
||||
{
|
||||
$client = $quote->client;
|
||||
$this->template_style = $quote->client->getSetting('email_style');
|
||||
|
||||
$body_template = $client->getSetting('email_template_' . $reminder_template);
|
||||
|
||||
/* Use default translations if a custom message has not been set*/
|
||||
if (iconv_strlen($body_template) == 0) {
|
||||
$body_template = trans('texts.quote_message',
|
||||
['amount' => $quote->amount, 'company' => $quote->company->present()->name()], null,
|
||||
$quote->client->locale());
|
||||
}
|
||||
|
||||
$subject_template = $client->getSetting('email_subject_' . $reminder_template);
|
||||
|
||||
if (iconv_strlen($subject_template) == 0) {
|
||||
if ($reminder_template == 'quote') {
|
||||
$subject_template = trans('texts.quote_subject',
|
||||
['number' => $quote->number, 'company' => $quote->company->present()->name()],
|
||||
null, $quote->client->locale());
|
||||
} else {
|
||||
$subject_template = trans('texts.reminder_subject',
|
||||
['number' => $quote->number, 'company' => $quote->company->present()->name()],
|
||||
null, $quote->client->locale());
|
||||
}
|
||||
}
|
||||
|
||||
$this->setTemplate($quote->client->getSetting('email_style'))
|
||||
->setContact($contact)
|
||||
->setFooter("<a href='{$quote->invitations->first()->getLink()}'>Invoice Link</a>")
|
||||
->setVariables($quote->makeValues($contact))
|
||||
->setSubject($subject_template)
|
||||
->setBody($body_template);
|
||||
|
||||
if ($client->getSetting('pdf_email_attachment') !== false) {
|
||||
$this->attachments = $quote->pdf_file_path();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -1,50 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Invoice;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Helpers\Email\InvoiceEmail;
|
||||
use App\Jobs\Utils\SystemLogger;
|
||||
use App\Mail\TemplateEmail;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\SystemLog;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Symfony\Component\Mime\Test\Constraint\EmailTextBodyContains;
|
||||
|
||||
class EmailInvoice implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $invoice;
|
||||
public $invoice_invitation;
|
||||
|
||||
public $message_array = [];
|
||||
|
||||
private $company;
|
||||
public $email_builder;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
* EmailQuote constructor.
|
||||
* @param BuildEmail $email_builder
|
||||
* @param QuoteInvitation $quote_invitation
|
||||
*/
|
||||
public function __construct(Invoice $invoice, Company $company)
|
||||
public function __construct(InvoiceEmail $email_builder, InvoiceInvitation $invoice_invitation)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
|
||||
$this->company = $company;
|
||||
$this->invoice_invitation = $invoice_invitation;
|
||||
$this->email_builder = $email_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,46 +43,22 @@ class EmailInvoice implements ShouldQueue
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public function handle()
|
||||
{
|
||||
/*Jobs are not multi-db aware, need to set! */
|
||||
MultiDB::setDB($this->company->db);
|
||||
|
||||
$email_builder = $this->email_builder;
|
||||
|
||||
//todo - change runtime config of mail driver if necessary
|
||||
Mail::to($this->invoice_invitation->contact->email, $this->invoice_invitation->contact->present()->name())
|
||||
->send(new TemplateEmail($email_builder,
|
||||
$this->invoice_invitation->contact->user,
|
||||
$this->invoice_invitation->contact->client
|
||||
)
|
||||
);
|
||||
|
||||
$template_style = $this->invoice->client->getSetting('email_style');
|
||||
|
||||
$this->invoice->invitations->each(function ($invitation) use ($template_style) {
|
||||
if ($invitation->contact->send_invoice && $invitation->contact->email) {
|
||||
|
||||
$message_array = $this->invoice->getEmailData('', $invitation->contact);
|
||||
|
||||
$message_array['title'] = &$message_array['subject'];
|
||||
|
||||
//$message_array['footer'] = "Sent to ".$invitation->contact->present()->name();
|
||||
$message_array['footer'] = "<a href='{$invitation->getLink()}'>Invoice Link</a>";
|
||||
|
||||
//change the runtime config of the mail provider here:
|
||||
|
||||
//send message
|
||||
Mail::to($invitation->contact->email, $invitation->contact->present()->name())
|
||||
->send(new TemplateEmail($message_array,
|
||||
$template_style,
|
||||
$invitation->contact->user,
|
||||
$invitation->contact->client));
|
||||
|
||||
if (count(Mail::failures()) > 0) {
|
||||
event(new InvoiceWasEmailedAndFailed($this->invoice, Mail::failures()));
|
||||
|
||||
return $this->logMailError($errors);
|
||||
}
|
||||
|
||||
//fire any events
|
||||
event(new InvoiceWasEmailed($this->invoice));
|
||||
|
||||
//sleep(5);
|
||||
}
|
||||
});
|
||||
if (count(Mail::failures()) > 0) {
|
||||
return $this->logMailError($errors);
|
||||
}
|
||||
}
|
||||
|
||||
private function logMailError($errors)
|
||||
|
@ -1,9 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\Payment;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
|
||||
use App\Events\Payment\PaymentWasEmailed;
|
||||
use App\Events\Payment\PaymentWasEmailedAndFailed;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Helpers\Email\BuildEmail;
|
||||
use App\Jobs\Utils\SystemLogger;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Mail\TemplateEmail;
|
||||
use App\Models\Company;
|
||||
@ -22,21 +26,23 @@ class EmailPayment implements ShouldQueue
|
||||
|
||||
public $payment;
|
||||
|
||||
public $message_array = [];
|
||||
public $email_builder;
|
||||
|
||||
private $contact;
|
||||
|
||||
private $company;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Payment $payment, Company $company)
|
||||
{
|
||||
public function __construct(Payment $payment, $email_builder, $contact)
|
||||
{
|
||||
$this->payment = $payment;
|
||||
$this->email_builder = $email_builder;
|
||||
$this->contact = $contact;
|
||||
}
|
||||
|
||||
$this->company = $company;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
@ -46,37 +52,24 @@ class EmailPayment implements ShouldQueue
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
/*Jobs are not multi-db aware, need to set! */
|
||||
MultiDB::setDB($this->company->db);
|
||||
$email_builder = $this->email_builder;
|
||||
|
||||
//todo - change runtime config of mail driver if necessary
|
||||
if ($this->contact->email) {
|
||||
Mail::to($this->contact->email, $this->contact->present()->name())
|
||||
->send(new TemplateEmail($email_builder, $this->contact->user, $this->contact->customer));
|
||||
|
||||
$template_style = $this->payment->client->getSetting('email_style');
|
||||
if (count(Mail::failures()) > 0) {
|
||||
event(new PaymentWasEmailedAndFailed($this->payment, Mail::failures()));
|
||||
|
||||
$this->payment->client->contacts->each(function ($contact) use ($template_style) {
|
||||
if ($contact->email) {
|
||||
$message_array = $this->payment->getEmailData('', $contact);
|
||||
$message_array['title'] = &$message_array['subject'];
|
||||
$message_array['footer'] = "Sent to ".$contact->present()->name();
|
||||
|
||||
//change the runtime config of the mail provider here:
|
||||
|
||||
//send message
|
||||
Mail::to($contact->email, $contact->present()->name())
|
||||
->send(new TemplateEmail($message_array, $template_style, $contact->user, $contact->client));
|
||||
|
||||
if (count(Mail::failures()) > 0) {
|
||||
event(new PaymentWasEmailedAndFailed($this->payment, Mail::failures()));
|
||||
|
||||
return $this->logMailError($errors);
|
||||
}
|
||||
|
||||
//fire any events
|
||||
event(new PaymentWasEmailed($this->payment));
|
||||
|
||||
//sleep(5);
|
||||
return $this->logMailError($errors);
|
||||
}
|
||||
});
|
||||
|
||||
//fire any events
|
||||
event(new PaymentWasEmailed($this->payment));
|
||||
|
||||
//sleep(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function logMailError($errors)
|
||||
|
@ -1,13 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\Quote;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasEmailed;
|
||||
use App\Events\Invoice\InvoiceWasEmailedAndFailed;
|
||||
use App\Events\Quote\QuoteWasEmailed;
|
||||
use App\Events\Quote\QuoteWasEmailedAndFailed;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Jobs\Utils\SystemLogger;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Mail\TemplateEmail;
|
||||
use App\Models\Company;
|
||||
use App\Models\Quote;
|
||||
use App\Models\QuoteInvitation;
|
||||
use App\Models\SystemLog;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
@ -20,22 +24,19 @@ class EmailQuote implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $quote;
|
||||
public $quote_invitation;
|
||||
|
||||
public $message_array = [];
|
||||
|
||||
private $company;
|
||||
public $email_builder;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
* EmailQuote constructor.
|
||||
* @param BuildEmail $email_builder
|
||||
* @param QuoteInvitation $quote_invitation
|
||||
*/
|
||||
public function __construct(Quote $quote, Company $company)
|
||||
public function __construct($email_builder, QuoteInvitation $quote_invitation)
|
||||
{
|
||||
$this->quote = $quote;
|
||||
|
||||
$this->company = $company;
|
||||
$this->quote_invitation = $quote_invitation;
|
||||
$this->email_builder = $email_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,37 +47,19 @@ class EmailQuote implements ShouldQueue
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
/*Jobs are not multi-db aware, need to set! */
|
||||
MultiDB::setDB($this->company->db);
|
||||
$email_builder = $this->email_builder;
|
||||
|
||||
//todo - change runtime config of mail driver if necessary
|
||||
Mail::to($this->quote_invitation->contact->email, $this->quote_invitation->contact->present()->name())
|
||||
->send(new TemplateEmail($email_builder,
|
||||
$this->quote_invitation->contact->user,
|
||||
$this->quote_invitation->contact->client
|
||||
)
|
||||
);
|
||||
|
||||
$template_style = $this->quote->client->getSetting('email_style');
|
||||
if (count(Mail::failures()) > 0) {
|
||||
return $this->logMailError($errors);
|
||||
}
|
||||
|
||||
$this->quote->invitations->each(function ($invitation) use ($template_style) {
|
||||
if ($invitation->contact->email) {
|
||||
$message_array = $this->quote->getEmailData('', $invitation->contact);
|
||||
$message_array['title'] = &$message_array['subject'];
|
||||
$message_array['footer'] = "<a href='{$invitation->getLink()}'>Quote Link</a>";
|
||||
|
||||
//change the runtime config of the mail provider here:
|
||||
|
||||
//send message
|
||||
Mail::to($invitation->contact->email, $invitation->contact->present()->name())
|
||||
->send(new TemplateEmail($message_array, $template_style, $invitation->contact->user, $invitation->contact->client));
|
||||
|
||||
if (count(Mail::failures()) > 0) {
|
||||
event(new QuoteWasEmailedAndFailed($this->quote, Mail::failures()));
|
||||
|
||||
return $this->logMailError($errors);
|
||||
}
|
||||
|
||||
//fire any events
|
||||
event(new QuoteWasEmailed($this->quote));
|
||||
|
||||
//sleep(5);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function logMailError($errors)
|
||||
|
@ -1,8 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
@ -11,22 +9,16 @@ use Illuminate\Queue\SerializesModels;
|
||||
class TemplateEmail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
private $template; //the template to use
|
||||
|
||||
private $message; //the message array // ['body', 'footer', 'title', 'files']
|
||||
|
||||
private $build_email; //the message array // ['body', 'footer', 'title', 'files']
|
||||
private $user; //the user the email will be sent from
|
||||
private $customer;
|
||||
private $footer;
|
||||
|
||||
private $client;
|
||||
|
||||
|
||||
public function __construct($message, $template, $user, $client)
|
||||
public function __construct($build_email, $user, $customer)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->template = $template;
|
||||
$this->build_email = $build_email;
|
||||
$this->user = $user; //this is inappropriate here, need to refactor 'user' in this context the 'user' could also be the 'system'
|
||||
$this->client = $client;
|
||||
$this->customer = $customer;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,33 +29,32 @@ class TemplateEmail extends Mailable
|
||||
public function build()
|
||||
{
|
||||
/*Alter Run Time Mailer configuration (driver etc etc) to regenerate the Mailer Singleton*/
|
||||
|
||||
//if using a system level template
|
||||
$template_name = 'email.template.'.$this->template;
|
||||
$template_name = 'email.template.' . $this->build_email->getTemplate();
|
||||
|
||||
$settings = $this->client->getMergedSettings();
|
||||
$settings = $this->customer->getMergedSettings();
|
||||
\Log::error(print_r($settings, 1));
|
||||
$company = $this->customer->account;
|
||||
|
||||
$company = $this->client->company;
|
||||
|
||||
$message = $this->from($this->user->email, $this->user->present()->name()) //todo this needs to be fixed to handle the hosted version
|
||||
->subject($this->message['subject'])
|
||||
->text('email.template.plain', ['body' => $this->message['body'], 'footer' => $this->message['footer']])
|
||||
$message = $this->from($this->user->email,
|
||||
$this->user->present()->name())//todo this needs to be fixed to handle the hosted version
|
||||
->subject($this->build_email->getSubject())
|
||||
->text('email.template.plain', ['body' => $this->build_email->getBody(), 'footer' => $this->build_email->getFooter()])
|
||||
->view($template_name, [
|
||||
'body' => $this->message['body'],
|
||||
'footer' => $this->message['footer'],
|
||||
'title' => $this->message['title'],
|
||||
'body' => $this->build_email->getBody(),
|
||||
'footer' => $this->build_email->getFooter(),
|
||||
'title' => $this->build_email->getSubject(),
|
||||
'settings' => $settings,
|
||||
'company' => $company
|
||||
]);
|
||||
|
||||
//conditionally attach files
|
||||
if($settings->pdf_email_attachment !== false && !empty($this->build_email->getAttachments())){
|
||||
|
||||
//conditionally attach files
|
||||
if ($settings->pdf_email_attachment !== false && array_key_exists('files', $this->message)) {
|
||||
foreach ($this->message['files'] as $file) {
|
||||
$message->attach($file);
|
||||
}
|
||||
}
|
||||
foreach($this->build_email->getAttachments() as $file)
|
||||
$message->attach($file);
|
||||
}
|
||||
|
||||
return $message;
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ class Invoice extends BaseModel
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->morphToMany(Payment::class, 'paymentable')->withPivot('amount','refunded')->withTimestamps();;
|
||||
return $this->morphToMany(Payment::class, 'paymentable')->withPivot('amount', 'refunded')->withTimestamps();;
|
||||
}
|
||||
|
||||
public function company_ledger()
|
||||
@ -156,13 +156,14 @@ class Invoice extends BaseModel
|
||||
|
||||
public function credits()
|
||||
{
|
||||
return $this->belongsToMany(Credit::class)->using(Paymentable::class)->withPivot('amount','refunded')->withTimestamps();;
|
||||
return $this->belongsToMany(Credit::class)->using(Paymentable::class)->withPivot('amount',
|
||||
'refunded')->withTimestamps();;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service entry points
|
||||
*/
|
||||
public function service() :InvoiceService
|
||||
public function service(): InvoiceService
|
||||
{
|
||||
return new InvoiceService($this);
|
||||
}
|
||||
@ -192,12 +193,12 @@ class Invoice extends BaseModel
|
||||
*
|
||||
* @return boolean isLocked
|
||||
*/
|
||||
public function isLocked() : bool
|
||||
public function isLocked(): bool
|
||||
{
|
||||
return $this->client->getSetting('lock_sent_invoices');
|
||||
}
|
||||
|
||||
public function isPayable() : bool
|
||||
public function isPayable(): bool
|
||||
{
|
||||
if ($this->status_id == Invoice::STATUS_SENT && $this->is_deleted == false) {
|
||||
return true;
|
||||
@ -212,23 +213,25 @@ class Invoice extends BaseModel
|
||||
}
|
||||
}
|
||||
|
||||
public function isRefundable() : bool
|
||||
public function isRefundable(): bool
|
||||
{
|
||||
|
||||
if($this->is_deleted)
|
||||
if ($this->is_deleted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(($this->amount - $this->balance) == 0)
|
||||
if (($this->amount - $this->balance) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isPartial() : bool
|
||||
public function isPartial(): bool
|
||||
{
|
||||
return $this->status_id >= self::STATUS_PARTIAL;
|
||||
}
|
||||
@ -236,7 +239,7 @@ class Invoice extends BaseModel
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPartial() : bool
|
||||
public function hasPartial(): bool
|
||||
{
|
||||
return ($this->partial && $this->partial > 0) === true;
|
||||
}
|
||||
@ -245,28 +248,28 @@ class Invoice extends BaseModel
|
||||
{
|
||||
switch ($status) {
|
||||
case Invoice::STATUS_DRAFT:
|
||||
return '<h5><span class="badge badge-light">'.ctrans('texts.draft').'</span></h5>';
|
||||
return '<h5><span class="badge badge-light">' . ctrans('texts.draft') . '</span></h5>';
|
||||
break;
|
||||
case Invoice::STATUS_SENT:
|
||||
return '<h5><span class="badge badge-primary">'.ctrans('texts.sent').'</span></h5>';
|
||||
return '<h5><span class="badge badge-primary">' . ctrans('texts.sent') . '</span></h5>';
|
||||
break;
|
||||
case Invoice::STATUS_PARTIAL:
|
||||
return '<h5><span class="badge badge-primary">'.ctrans('texts.partial').'</span></h5>';
|
||||
return '<h5><span class="badge badge-primary">' . ctrans('texts.partial') . '</span></h5>';
|
||||
break;
|
||||
case Invoice::STATUS_PAID:
|
||||
return '<h5><span class="badge badge-success">'.ctrans('texts.paid').'</span></h5>';
|
||||
return '<h5><span class="badge badge-success">' . ctrans('texts.paid') . '</span></h5>';
|
||||
break;
|
||||
case Invoice::STATUS_CANCELLED:
|
||||
return '<h5><span class="badge badge-secondary">'.ctrans('texts.cancelled').'</span></h5>';
|
||||
return '<h5><span class="badge badge-secondary">' . ctrans('texts.cancelled') . '</span></h5>';
|
||||
break;
|
||||
case Invoice::STATUS_OVERDUE:
|
||||
return '<h5><span class="badge badge-danger">'.ctrans('texts.overdue').'</span></h5>';
|
||||
return '<h5><span class="badge badge-danger">' . ctrans('texts.overdue') . '</span></h5>';
|
||||
break;
|
||||
case Invoice::STATUS_UNPAID:
|
||||
return '<h5><span class="badge badge-warning">'.ctrans('texts.unpaid').'</span></h5>';
|
||||
return '<h5><span class="badge badge-warning">' . ctrans('texts.unpaid') . '</span></h5>';
|
||||
break;
|
||||
case Invoice::STATUS_REVERSED:
|
||||
return '<h5><span class="badge badge-info">'.ctrans('texts.reversed').'</span></h5>';
|
||||
return '<h5><span class="badge badge-info">' . ctrans('texts.reversed') . '</span></h5>';
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
@ -306,13 +309,14 @@ class Invoice extends BaseModel
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the template for the invoice
|
||||
*
|
||||
* @return string Either the template view, OR the template HTML string
|
||||
* @todo this needs attention, invoice->settings needs clarification
|
||||
*/
|
||||
public function design() :string
|
||||
public function design(): string
|
||||
{
|
||||
if ($this->client->getSetting('design')) {
|
||||
return File::exists(resource_path($this->client->getSetting('design'))) ? File::get(resource_path($this->client->getSetting('design'))) : File::get(resource_path('views/pdf/design1.blade.php'));
|
||||
@ -346,9 +350,10 @@ class Invoice extends BaseModel
|
||||
|
||||
// $storage_path = 'public/' . $this->client->client_hash . '/invoices/'. $this->number . '.pdf';
|
||||
|
||||
$public_path = $this->client->client_hash . '/invoices/'. $this->number . '.pdf';
|
||||
$public_path = $this->client->client_hash . '/invoices/' . $this->number . '.pdf';
|
||||
|
||||
$storage_path = $this->client->client_hash . '/invoices/' . $this->number . '.pdf';
|
||||
|
||||
$storage_path = 'storage/' . $this->client->client_hash . '/invoices/'. $this->number . '.pdf';
|
||||
|
||||
$disk = config('filesystems.default');
|
||||
|
||||
@ -362,7 +367,7 @@ class Invoice extends BaseModel
|
||||
|
||||
public function pdf_file_path()
|
||||
{
|
||||
$storage_path = 'storage/' . $this->client->client_hash . '/invoices/'. $this->number . '.pdf';
|
||||
$storage_path = 'storage/' . $this->client->client_hash . '/invoices/' . $this->number . '.pdf';
|
||||
|
||||
if (!Storage::exists($storage_path)) {
|
||||
CreateInvoicePdf::dispatchNow($this, $this->company, $this->client->primary_contact()->first());
|
||||
@ -386,8 +391,7 @@ class Invoice extends BaseModel
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Graveyard */
|
||||
/* Graveyard */
|
||||
|
||||
// /**
|
||||
// * Determines if invoice overdue.
|
||||
|
82
app/Models/Presenters/QuotePresenter.php
Normal file
82
app/Models/Presenters/QuotePresenter.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com)
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Models\Presenters;
|
||||
|
||||
use App\Utils\Number;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
|
||||
/**
|
||||
* Class InvoicePresenter
|
||||
*
|
||||
* For convenience and to allow users to easiliy
|
||||
* customise their invoices, we provide all possible
|
||||
* invoice variables to be available from this presenter.
|
||||
*
|
||||
* Shortcuts to other presenters are here to facilitate
|
||||
* a clean UI / UX
|
||||
*
|
||||
* @package App\Models\Presenters
|
||||
*/
|
||||
class QuotePresenter extends EntityPresenter
|
||||
{
|
||||
use MakesDates;
|
||||
|
||||
|
||||
public function amount()
|
||||
{
|
||||
return Number::formatMoney($this->balance, $this->client);
|
||||
}
|
||||
|
||||
public function invoice_number()
|
||||
{
|
||||
if ($this->number != '') {
|
||||
return $this->number;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function clientName()
|
||||
{
|
||||
return $this->client->present()->name();
|
||||
}
|
||||
|
||||
public function address()
|
||||
{
|
||||
return $this->client->present()->address();
|
||||
}
|
||||
|
||||
public function shippingAddress()
|
||||
{
|
||||
return $this->client->present()->shipping_address();
|
||||
}
|
||||
|
||||
public function companyLogo()
|
||||
{
|
||||
return $this->company->logo;
|
||||
}
|
||||
|
||||
public function clientLogo()
|
||||
{
|
||||
return $this->client->logo;
|
||||
}
|
||||
|
||||
public function companyName()
|
||||
{
|
||||
return $this->company->present()->name();
|
||||
}
|
||||
|
||||
public function companyAddress()
|
||||
{
|
||||
return $this->company->present()->address();
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ use App\Helpers\Invoice\InvoiceSumInclusive;
|
||||
use App\Models\Filterable;
|
||||
use App\Services\Quote\QuoteService;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\MakesReminders;
|
||||
use Laracasts\Presenter\PresentableTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
@ -24,6 +26,10 @@ class Quote extends BaseModel
|
||||
use MakesHash;
|
||||
use Filterable;
|
||||
use SoftDeletes;
|
||||
use MakesReminders;
|
||||
use PresentableTrait;
|
||||
|
||||
protected $presenter = 'App\Models\Presenters\QuotePresenter';
|
||||
|
||||
protected $fillable = [
|
||||
'number',
|
||||
|
@ -44,7 +44,7 @@ class QuoteInvitation extends BaseModel
|
||||
*/
|
||||
public function contact()
|
||||
{
|
||||
return $this->belongsTo(ClientContact::class)->withTrashed();
|
||||
return $this->belongsTo(ClientContact::class, 'client_contact_id', 'id')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
|
40
app/Services/Credit/ApplyNumber.php
Normal file
40
app/Services/Credit/ApplyNumber.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Credit;
|
||||
|
||||
use App\Credit;
|
||||
use App\Events\Payment\PaymentWasCreated;
|
||||
use App\Factory\PaymentFactory;
|
||||
use App\Jobs\Customer\UpdateCustomerBalance;
|
||||
use App\Jobs\Customer\UpdateCustomerPaidToDate;
|
||||
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Services\Customer\CustomerService;
|
||||
use App\Services\Payment\PaymentService;
|
||||
use App\Traits\GeneratesCounter;
|
||||
|
||||
class ApplyNumber
|
||||
{
|
||||
use GeneratesCounter;
|
||||
|
||||
private $customer;
|
||||
|
||||
public function __construct($customer)
|
||||
{
|
||||
$this->customer = $customer;
|
||||
}
|
||||
|
||||
public function __invoke($credit)
|
||||
{
|
||||
|
||||
if ($credit->number != '') {
|
||||
return $credit;
|
||||
}
|
||||
|
||||
$credit->number = $this->getNextCreditNumber($this->customer);
|
||||
|
||||
|
||||
return $credit;
|
||||
}
|
||||
}
|
37
app/Services/Credit/CreateInvitations.php
Normal file
37
app/Services/Credit/CreateInvitations.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace App\Services\Credit;
|
||||
|
||||
use App\Factory\CreditInvitationFactory;
|
||||
use App\Models\CreditInvitation;
|
||||
|
||||
class CreateInvitations
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke($credit)
|
||||
{
|
||||
|
||||
$contacts = $credit->customer->contacts;
|
||||
|
||||
$contacts->each(function ($contact) use($credit){
|
||||
$invitation = CreditInvitation::whereCompanyId($credit->account_id)
|
||||
->whereClientContactId($contact->id)
|
||||
->whereCreditId($credit->id)
|
||||
->first();
|
||||
|
||||
if (!$invitation) {
|
||||
$ii = CreditInvitationFactory::create($credit->account_id, $credit->user_id);
|
||||
$ii->credit_id = $credit->id;
|
||||
$ii->client_contact_id = $contact->id;
|
||||
$ii->save();
|
||||
} elseif ($invitation && !$contact->send_credit) {
|
||||
$invitation->delete();
|
||||
}
|
||||
});
|
||||
|
||||
return $credit;
|
||||
}
|
||||
}
|
55
app/Services/Credit/CreditService.php
Normal file
55
app/Services/Credit/CreditService.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
namespace App\Services\Credit;
|
||||
|
||||
use App\Credit;
|
||||
|
||||
class CreditService
|
||||
{
|
||||
protected $credit;
|
||||
|
||||
|
||||
public function __construct($credit)
|
||||
{
|
||||
$this->credit = $credit;
|
||||
|
||||
}
|
||||
|
||||
public function getCreditPdf($contact)
|
||||
{
|
||||
$get_invoice_pdf = new GetCreditPdf();
|
||||
|
||||
return $get_invoice_pdf($this->credit, $contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the invoice number
|
||||
* @return $this InvoiceService object
|
||||
*/
|
||||
public function applyNumber()
|
||||
{
|
||||
$apply_number = new ApplyNumber($this->credit->customer);
|
||||
|
||||
$this->credit = $apply_number($this->credit);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function createInvitations()
|
||||
{
|
||||
$create_invitation = new CreateInvitations();
|
||||
|
||||
$this->invoice = $create_invitation($this->invoice);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the credit
|
||||
* @return Credit object
|
||||
*/
|
||||
public function save() : ?Credit
|
||||
{
|
||||
$this->credit->save();
|
||||
return $this->credit;
|
||||
}
|
||||
}
|
33
app/Services/Credit/GetCreditPdf.php
Normal file
33
app/Services/Credit/GetCreditPdf.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Credit;
|
||||
|
||||
use App\Jobs\Invoice\CreateInvoicePdf;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class GetCreditPdf
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke($credit, $contact = null)
|
||||
{
|
||||
if (!$contact) {
|
||||
$contact = $credit->customer->primary_contact()->first();
|
||||
}
|
||||
|
||||
$path = 'public/' . $credit->customer->id . '/credits/';
|
||||
$file_path = $path . $credit->number . '.pdf';
|
||||
$disk = config('filesystems.default');
|
||||
$file = Storage::disk($disk)->exists($file_path);
|
||||
|
||||
if (!$file) {
|
||||
$file_path = CreateInvoicePdf::dispatchNow($this, $credit->account, $contact);
|
||||
}
|
||||
|
||||
return Storage::disk($disk)->url($file_path);
|
||||
}
|
||||
|
||||
}
|
@ -120,14 +120,12 @@ class InvoiceService
|
||||
return $get_invoice_pdf->run($this->invoice, $contact);
|
||||
}
|
||||
|
||||
public function sendEmail($contact)
|
||||
{
|
||||
$send_email = new SendEmail($this->invoice);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return $send_email->run(null, $contact);
|
||||
}
|
||||
|
||||
public function markViewed()
|
||||
{
|
||||
|
39
app/Services/Invoice/SendEmail.php
Normal file
39
app/Services/Invoice/SendEmail.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Invoice;
|
||||
|
||||
use App\Helpers\Email\InvoiceEmail;
|
||||
use App\Jobs\Invoice\EmailInvoice;
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class SendEmail
|
||||
{
|
||||
|
||||
public $invoice;
|
||||
|
||||
public function __construct($invoice)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the correct template to send
|
||||
* @param string $reminder_template The template name ie reminder1
|
||||
* @return array
|
||||
*/
|
||||
public function run($reminder_template = null, $contact = null): array
|
||||
{
|
||||
if (!$reminder_template) {
|
||||
$reminder_template = $this->invoice->status_id == Invoice::STATUS_DRAFT || Carbon::parse($this->invoice->due_date) > now() ? 'invoice' : $this->invoice->calculateTemplate();
|
||||
}
|
||||
|
||||
$email_builder = (new InvoiceEmail())->build($this->invoice, $reminder_template, $contact);
|
||||
|
||||
$this->invoice->invitations->each(function ($invitation) use ($email_builder) {
|
||||
if ($invitation->contact->send_invoice && $invitation->contact->email) {
|
||||
EmailInvoice::dispatchNow($email_builder, $invitation);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -42,4 +42,11 @@ class PaymentService
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
public function sendEmail($contact = null)
|
||||
{
|
||||
$send_email = new SendEmail($this->payment);
|
||||
|
||||
return $send_email->run(null, $contact);
|
||||
}
|
||||
}
|
||||
|
32
app/Services/Payment/SendEmail.php
Normal file
32
app/Services/Payment/SendEmail.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Payment;
|
||||
|
||||
use App\Helpers\Email\PaymentEmail;
|
||||
use App\Jobs\Payment\EmailPayment;
|
||||
|
||||
class SendEmail
|
||||
{
|
||||
public $payment;
|
||||
|
||||
public function __construct($payment)
|
||||
{
|
||||
$this->payment = $payment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the correct template to send
|
||||
* @param string $reminder_template The template name ie reminder1
|
||||
* @return array
|
||||
*/
|
||||
public function run($contact = null): array
|
||||
{
|
||||
$email_builder = (new PaymentEmail())->build($this->payment, $contact);
|
||||
|
||||
$this->payment->client->contacts->each(function ($contact) use ($email_builder) {
|
||||
if ($contact->send_invoice && $contact->email) {
|
||||
EmailPayment::dispatchNow($this->payment, $email_builder, $contact);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -35,6 +35,20 @@ class QuoteService
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getQuotePdf($contact)
|
||||
{
|
||||
$get_invoice_pdf = new GetQuotePdf();
|
||||
|
||||
return $get_invoice_pdf($this->quote, $contact);
|
||||
}
|
||||
|
||||
public function sendEmail($contact)
|
||||
{
|
||||
$send_email = new SendEmail($this->quote);
|
||||
|
||||
return $send_email->run(null, $contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the invoice number
|
||||
* @return $this InvoiceService object
|
||||
|
40
app/Services/Quote/SendEmail.php
Normal file
40
app/Services/Quote/SendEmail.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Quote;
|
||||
|
||||
use App\Helpers\Email\QuoteEmail;
|
||||
use App\Jobs\Quote\EmailQuote;
|
||||
use App\Models\Quote;
|
||||
|
||||
class SendEmail
|
||||
{
|
||||
|
||||
public $quote;
|
||||
|
||||
public function __construct($quote)
|
||||
{
|
||||
$this->quote = $quote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the correct template to send
|
||||
* @param string $reminder_template The template name ie reminder1
|
||||
* @return array
|
||||
*/
|
||||
public function run($reminder_template = null, $contact = null): array
|
||||
{
|
||||
if (!$reminder_template) {
|
||||
$reminder_template = $this->quote->status_id == Quote::STATUS_DRAFT || Carbon::parse($this->quote->due_date) > now() ? 'invoice' : $this->quote->calculateTemplate();
|
||||
}
|
||||
|
||||
$email_builder = (new QuoteEmail())->build($this->quote, $reminder_template, $contact);
|
||||
|
||||
$this->quote->invitations->each(function ($invitation) use ($email_builder) {
|
||||
if ($invitation->contact->send_invoice && $invitation->contact->email) {
|
||||
EmailQuote::dispatchNow($email_builder, $invitation);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -40,12 +40,12 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($settings->enable_reminder1 !== false &&
|
||||
$settings->schedule_reminder1 == 'before_due_date' &&
|
||||
$settings->num_days_reminder1 > 0) {
|
||||
@ -54,7 +54,7 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
@ -69,12 +69,12 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($settings->enable_reminder2 !== false &&
|
||||
$settings->schedule_reminder2 == 'after_invoice_date' &&
|
||||
$settings->num_days_reminder2 > 0) {
|
||||
@ -83,12 +83,12 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($settings->enable_reminder2 !== false &&
|
||||
$settings->schedule_reminder2 == 'before_due_date' &&
|
||||
$settings->num_days_reminder2 > 0) {
|
||||
@ -97,7 +97,7 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
@ -112,7 +112,7 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
@ -126,12 +126,12 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($settings->enable_reminder3 !== false &&
|
||||
$settings->schedule_reminder3 == 'before_due_date' &&
|
||||
$settings->num_days_reminder3 > 0) {
|
||||
@ -140,7 +140,7 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
@ -155,13 +155,53 @@ trait MakesReminders
|
||||
if (!$nsd) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
|
||||
|
||||
if ($reminder_date->lt($nsd)) {
|
||||
$nsd = $reminder_date;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->next_send_date = $nsd;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function inReminderWindow($schedule_reminder, $num_days_reminder)
|
||||
{
|
||||
switch ($schedule_reminder) {
|
||||
case 'after_invoice_date':
|
||||
return Carbon::parse($this->date)->addDays($num_days_reminder)->startOfDay()->eq(Carbon::now()->startOfDay());
|
||||
break;
|
||||
case 'before_due_date':
|
||||
return Carbon::parse($this->due_date)->subDays($num_days_reminder)->startOfDay()->eq(Carbon::now()->startOfDay());
|
||||
break;
|
||||
case 'after_due_date':
|
||||
return Carbon::parse($this->due_date)->addDays($num_days_reminder)->startOfDay()->eq(Carbon::now()->startOfDay());
|
||||
break;
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function calculateTemplate(): string
|
||||
{
|
||||
//if invoice is currently a draft, or being marked as sent, this will be the initial email
|
||||
$customer = $this->client;
|
||||
|
||||
//if the invoice
|
||||
if ($customer->getSetting('enable_reminder1') !== false && $this->inReminderWindow($customer->getSetting('schedule_reminder1'),
|
||||
$customer->getSetting('num_days_reminder1'))) {
|
||||
return 'template1';
|
||||
} elseif ($customer->getSetting('enable_reminder2') !== false && $this->inReminderWindow($customer->getSetting('schedule_reminder2'),
|
||||
$customer->getSetting('num_days_reminder2'))) {
|
||||
return 'template2';
|
||||
} elseif ($customer->getSetting('enable_reminder3') !== false && $this->inReminderWindow($customer->getSetting('schedule_reminder3'),
|
||||
$customer->getSetting('num_days_reminder3'))) {
|
||||
return 'template3';
|
||||
} else {
|
||||
return 'invoice';
|
||||
}
|
||||
|
||||
//also implement endless reminders here
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user