Send Invoices/Estimates/Payments as email attachments

This commit is contained in:
Sebastian Cretu
2021-02-05 20:24:56 +01:00
parent f47029ca78
commit 392f6f469b
21 changed files with 574099 additions and 47 deletions

View File

@ -13,15 +13,17 @@ class SendEstimateMail extends Mailable
use Queueable, SerializesModels; use Queueable, SerializesModels;
public $data = []; public $data = [];
public $pdfData;
/** /**
* Create a new message instance. * Create a new message instance.
* *
* @return void * @return void
*/ */
public function __construct($data) public function __construct($data, $pdfData)
{ {
$this->data = $data; $this->data = $data;
$this->pdfData = $pdfData;
} }
/** /**
@ -40,9 +42,17 @@ class SendEstimateMail extends Mailable
'mailable_id' => $this->data['estimate']['id'] 'mailable_id' => $this->data['estimate']['id']
]); ]);
return $this->from($this->data['from']) $mailContent = $this->from($this->data['from'])
->subject($this->data['subject']) ->subject($this->data['subject'])
->markdown('emails.send.estimate', ['data', $this->data]); ->markdown('emails.send.estimate', ['data', $this->data]);
if ($this->pdfData) {
$mailContent->attachData(
$this->pdfData->output(),
$this->data['estimate']['estimate_number'] . '.pdf'
);
}
return $mailContent;
} }
} }

View File

@ -13,15 +13,17 @@ class SendInvoiceMail extends Mailable
use Queueable, SerializesModels; use Queueable, SerializesModels;
public $data = []; public $data = [];
public $pdfData;
/** /**
* Create a new message instance. * Create a new message instance.
* *
* @return void * @return void
*/ */
public function __construct($data) public function __construct($data, $pdfData)
{ {
$this->data = $data; $this->data = $data;
$this->pdfData = $pdfData;
} }
/** /**
@ -39,9 +41,18 @@ class SendInvoiceMail extends Mailable
'mailable_type' => Invoice::class, 'mailable_type' => Invoice::class,
'mailable_id' => $this->data['invoice']['id'] 'mailable_id' => $this->data['invoice']['id']
]); ]);
$mailContent = $this->from($this->data['from'])
->subject($this->data['subject'])
->markdown('emails.send.invoice', ['data', $this->data]);
return $this->from($this->data['from']) if ($this->pdfData) {
->subject($this->data['subject']) $mailContent->attachData(
->markdown('emails.send.invoice', ['data', $this->data]); $this->pdfData->output(),
$this->data['invoice']['invoice_number'] . '.pdf'
);
}
return $mailContent;
} }
} }

View File

@ -14,15 +14,17 @@ class SendPaymentMail extends Mailable
use Queueable, SerializesModels; use Queueable, SerializesModels;
public $data = []; public $data = [];
public $pdfData;
/** /**
* Create a new message instance. * Create a new message instance.
* *
* @return void * @return void
*/ */
public function __construct($data) public function __construct($data, $pdfData)
{ {
$this->data = $data; $this->data = $data;
$this->pdfData = $pdfData;
} }
/** /**
@ -41,9 +43,17 @@ class SendPaymentMail extends Mailable
'mailable_id' => $this->data['payment']['id'] 'mailable_id' => $this->data['payment']['id']
]); ]);
return $this->from($this->data['from']) $mailContent = $this->from($this->data['from'])
->subject($this->data['subject']) ->subject($this->data['subject'])
->markdown('emails.send.payment', ['data', $this->data]); ->markdown('emails.send.payment', ['data', $this->data]);
if ($this->pdfData) {
$mailContent->attachData(
$this->pdfData->output(),
$this->data['payment']['payment_number'] . '.pdf'
);
}
return $mailContent;
} }
} }

View File

@ -379,8 +379,9 @@ class Estimate extends Model implements HasMedia
$data['user'] = $this->user->toArray(); $data['user'] = $this->user->toArray();
$data['company'] = $this->company->toArray(); $data['company'] = $this->company->toArray();
$data['body'] = $this->getEmailBody($data['body']); $data['body'] = $this->getEmailBody($data['body']);
$pdfData = ($this->getEmailAttachmentSetting()) ? $this->getPDFData() : null;
\Mail::to($data['to'])->send(new SendEstimateMail($data)); \Mail::to($data['to'])->send(new SendEstimateMail($data, $pdfData));
if ($this->status == Estimate::STATUS_DRAFT) { if ($this->status == Estimate::STATUS_DRAFT) {
$this->status = Estimate::STATUS_SENT; $this->status = Estimate::STATUS_SENT;
@ -468,6 +469,17 @@ class Estimate extends Model implements HasMedia
return $this->getFormattedString($this->notes); return $this->getFormattedString($this->notes);
} }
public function getEmailAttachmentSetting()
{
$estimateAsAttachment = CompanySetting::getSetting('estimate_email_attachment', $this->company_id);
if($estimateAsAttachment == 'NO') {
return false;
}
return true;
}
public function getEmailBody($body) public function getEmailBody($body)
{ {
$values = array_merge($this->getFieldsArray(), $this->getExtraFields()); $values = array_merge($this->getFieldsArray(), $this->getExtraFields());

View File

@ -429,6 +429,7 @@ class Invoice extends Model implements HasMedia
$data['user'] = $this->user->toArray(); $data['user'] = $this->user->toArray();
$data['company'] = Company::find($this->company_id); $data['company'] = Company::find($this->company_id);
$data['body'] = $this->getEmailBody($data['body']); $data['body'] = $this->getEmailBody($data['body']);
$pdfData = ($this->getEmailAttachmentSetting()) ? $this->getPDFData() : null;
if ($this->status == Invoice::STATUS_DRAFT) { if ($this->status == Invoice::STATUS_DRAFT) {
$this->status = Invoice::STATUS_SENT; $this->status = Invoice::STATUS_SENT;
@ -436,7 +437,7 @@ class Invoice extends Model implements HasMedia
$this->save(); $this->save();
} }
\Mail::to($data['to'])->send(new SendInvoiceMail($data)); \Mail::to($data['to'])->send(new SendInvoiceMail($data, $pdfData));
return [ return [
'success' => true 'success' => true
@ -526,6 +527,17 @@ class Invoice extends Model implements HasMedia
return PDF::loadView('app.pdf.invoice.' . $invoiceTemplate->view); return PDF::loadView('app.pdf.invoice.' . $invoiceTemplate->view);
} }
public function getEmailAttachmentSetting()
{
$invoiceAsAttachment = CompanySetting::getSetting('invoice_email_attachment', $this->company_id);
if($invoiceAsAttachment == 'NO') {
return false;
}
return true;
}
public function getCompanyAddress() public function getCompanyAddress()
{ {
$format = CompanySetting::getSetting('invoice_company_address_format', $this->company_id); $format = CompanySetting::getSetting('invoice_company_address_format', $this->company_id);

View File

@ -124,8 +124,9 @@ class Payment extends Model implements HasMedia
$data['user'] = $this->user->toArray(); $data['user'] = $this->user->toArray();
$data['company'] = Company::find($this->company_id); $data['company'] = Company::find($this->company_id);
$data['body'] = $this->getEmailBody($data['body']); $data['body'] = $this->getEmailBody($data['body']);
$pdfData = ($this->getEmailAttachmentSetting()) ? $this->getPDFData() : null;
\Mail::to($data['to'])->send(new SendPaymentMail($data)); \Mail::to($data['to'])->send(new SendPaymentMail($data, $pdfData));
return [ return [
'success' => true 'success' => true
@ -400,6 +401,17 @@ class Payment extends Model implements HasMedia
return $this->getFormattedString($format); return $this->getFormattedString($format);
} }
public function getEmailAttachmentSetting()
{
$paymentAsAttachment = CompanySetting::getSetting('payment_email_attachment', $this->company_id);
if($paymentAsAttachment == 'NO') {
return false;
}
return true;
}
public function getNotes() public function getNotes()
{ {
return $this->getFormattedString($this->notes); return $this->getFormattedString($this->notes);

View File

@ -60,6 +60,9 @@ class DefaultSettingsSeeder extends Seeder
'payment_prefix' => 'PAY', 'payment_prefix' => 'PAY',
'payment_auto_generate' => 'YES', 'payment_auto_generate' => 'YES',
'save_pdf_to_disk' => 'NO', 'save_pdf_to_disk' => 'NO',
'invoice_email_attachment' => 'NO',
'estimate_email_attachment' => 'NO',
'payment_email_attachment' => 'NO',
]; ];
CompanySetting::setSettings($settings, $user->company_id); CompanySetting::setSettings($settings, $user->company_id);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,24 +1,24 @@
/*! /*!
* tiptap v1.30.0 * tiptap v1.29.6
* (c) 2021 überdosis GbR (limited liability) * (c) 2020 überdosis GbR (limited liability)
* @license MIT * @license MIT
*/ */
/*! /*!
* tiptap-commands v1.15.0 * tiptap-commands v1.14.6
* (c) 2021 überdosis GbR (limited liability) * (c) 2020 überdosis GbR (limited liability)
* @license MIT * @license MIT
*/ */
/*! /*!
* tiptap-extensions v1.33.2 * tiptap-extensions v1.33.1
* (c) 2021 überdosis GbR (limited liability) * (c) 2020 überdosis GbR (limited liability)
* @license MIT * @license MIT
*/ */
/*! /*!
* tiptap-utils v1.11.0 * tiptap-utils v1.10.4
* (c) 2021 überdosis GbR (limited liability) * (c) 2020 überdosis GbR (limited liability)
* @license MIT * @license MIT
*/ */
@ -88,8 +88,8 @@
*/ */
/*! /*!
* vue-i18n v8.22.2 * vue-i18n v8.22.4
* (c) 2020 kazuya kawaguchi * (c) 2021 kazuya kawaguchi
* Released under the MIT License. * Released under the MIT License.
*/ */
@ -100,8 +100,8 @@
*/ */
/*! /*!
* vuex v3.6.0 * vuex v3.6.2
* (c) 2020 Evan You * (c) 2021 Evan You
* @license MIT * @license MIT
*/ */

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{ {
"/assets/js/app.js": "/assets/js/app.js?id=2fe48b55fc5693cab09f", "/assets/js/app.js": "/assets/js/app.js",
"/assets/css/crater.css": "/assets/css/crater.css?id=7a822f915d7e413148f6" "/assets/css/crater.css": "/assets/css/crater.css"
} }

View File

@ -745,6 +745,8 @@
"invoice_settings": "Invoice Settings", "invoice_settings": "Invoice Settings",
"autogenerate_invoice_number": "Auto-generate Invoice Number", "autogenerate_invoice_number": "Auto-generate Invoice Number",
"invoice_setting_description": "Disable this, If you don't wish to auto-generate invoice numbers each time you create a new invoice.", "invoice_setting_description": "Disable this, If you don't wish to auto-generate invoice numbers each time you create a new invoice.",
"invoice_email_attachment": "Send invoices as attachments",
"invoice_email_attachment_setting_description": "Enable this if you want to send invoices as email attachment.",
"enter_invoice_prefix": "Enter invoice prefix", "enter_invoice_prefix": "Enter invoice prefix",
"terms_and_conditions": "Terms and Conditions", "terms_and_conditions": "Terms and Conditions",
"company_address_format": "Company Address Format", "company_address_format": "Company Address Format",
@ -759,6 +761,8 @@
"estimate_settings": "Estimate Settings", "estimate_settings": "Estimate Settings",
"autogenerate_estimate_number": "Auto-generate Estimate Number", "autogenerate_estimate_number": "Auto-generate Estimate Number",
"estimate_setting_description": "Disable this, If you don't wish to auto-generate estimate numbers each time you create a new estimate.", "estimate_setting_description": "Disable this, If you don't wish to auto-generate estimate numbers each time you create a new estimate.",
"estimate_email_attachment": "Send estimates as attachments",
"estimate_email_attachment_setting_description": "Enable this if you want to send the estimates as an email attachment.",
"enter_estimate_prefix": "Enter estmiate prefix", "enter_estimate_prefix": "Enter estmiate prefix",
"estimate_setting_updated": "Estimate Setting updated successfully", "estimate_setting_updated": "Estimate Setting updated successfully",
"company_address_format": "Company Address Format", "company_address_format": "Company Address Format",
@ -773,6 +777,8 @@
"payment_settings": "Payment Settings", "payment_settings": "Payment Settings",
"autogenerate_payment_number": "Auto-generate Payment Number", "autogenerate_payment_number": "Auto-generate Payment Number",
"payment_setting_description": "Disable this, If you don't wish to auto-generate payment numbers each time you create a new payment.", "payment_setting_description": "Disable this, If you don't wish to auto-generate payment numbers each time you create a new payment.",
"payment_email_attachment": "Send payments as attachments",
"payment_email_attachment_setting_description": "Enable this if you want to send the payment receipts as an email attachment.",
"enter_payment_prefix": "Enter Payment Prefix", "enter_payment_prefix": "Enter Payment Prefix",
"payment_setting_updated": "Payment Setting updated successfully", "payment_setting_updated": "Payment Setting updated successfully",
"payment_modes": "Payment Modes", "payment_modes": "Payment Modes",

View File

@ -59,12 +59,15 @@ export default {
this.isRequestOnGoing = true this.isRequestOnGoing = true
let res = await this.fetchCompanySettings([ let res = await this.fetchCompanySettings([
'payment_auto_generate', 'payment_auto_generate',
'payment_email_attachment',
'payment_prefix', 'payment_prefix',
'payment_mail_body', 'payment_mail_body',
'invoice_auto_generate', 'invoice_auto_generate',
'invoice_email_attachment',
'invoice_prefix', 'invoice_prefix',
'invoice_mail_body', 'invoice_mail_body',
'estimate_auto_generate', 'estimate_auto_generate',
'estimate_email_attachment',
'estimate_prefix', 'estimate_prefix',
'estimate_mail_body', 'estimate_mail_body',
'invoice_billing_address_format', 'invoice_billing_address_format',

View File

@ -70,7 +70,7 @@
<sw-divider class="mt-6 mb-8" /> <sw-divider class="mt-6 mb-8" />
<div class="flex"> <div class="flex mt-3 mb-4">
<div class="relative w-12"> <div class="relative w-12">
<sw-switch <sw-switch
v-model="estimateAutogenerate" v-model="estimateAutogenerate"
@ -96,6 +96,32 @@
</p> </p>
</div> </div>
</div> </div>
<div class="flex mb-2">
<div class="relative w-12">
<sw-switch
v-model="estimateAsAttachment"
class="absolute"
style="top: -20px"
@change="setEstimateSetting"
/>
</div>
<div class="ml-4">
<p class="p-0 mb-1 text-base leading-snug text-black">
{{
$t('settings.customization.estimates.estimate_email_attachment')
}}
</p>
<p
class="p-0 m-0 text-xs leading-tight text-gray-500"
style="max-width: 480px"
>
{{
$t('settings.customization.estimates.estimate_email_attachment_setting_description')
}}
</p>
</div>
</div>
</div> </div>
</template> </template>
@ -115,6 +141,7 @@ export default {
data() { data() {
return { return {
estimateAutogenerate: false, estimateAutogenerate: false,
estimateAsAttachment: false,
estimates: { estimates: {
estimate_prefix: null, estimate_prefix: null,
@ -204,6 +231,14 @@ export default {
} else { } else {
this.estimateAutogenerate = false this.estimateAutogenerate = false
} }
this.estimate_email_attachment = val ? val.estimate_email_attachment : ''
if (this.estimate_email_attachment === 'YES') {
this.estimateAsAttachment = true
} else {
this.estimateAsAttachment = false
}
}, },
}, },
@ -214,6 +249,7 @@ export default {
let data = { let data = {
settings: { settings: {
estimate_auto_generate: this.estimateAutogenerate ? 'YES' : 'NO', estimate_auto_generate: this.estimateAutogenerate ? 'YES' : 'NO',
estimate_email_attachment: this.estimateAsAttachment ? 'YES' : 'NO',
}, },
} }
let response = await this.updateCompanySettings(data) let response = await this.updateCompanySettings(data)

View File

@ -74,7 +74,7 @@
<sw-divider class="mt-6 mb-8" /> <sw-divider class="mt-6 mb-8" />
<div class="flex"> <div class="flex mt-3 mb-4">
<div class="relative w-12"> <div class="relative w-12">
<sw-switch <sw-switch
v-model="invoiceAutogenerate" v-model="invoiceAutogenerate"
@ -101,6 +101,33 @@
</p> </p>
</div> </div>
</div> </div>
<div class="flex mb-2">
<div class="relative w-12">
<sw-switch
v-model="invoiceAsAttachment"
class="absolute"
style="top: -20px"
@change="setInvoiceSetting"
/>
</div>
<div class="ml-4">
<p class="p-0 mb-1 text-base leading-snug text-black">
{{
$t('settings.customization.invoices.invoice_email_attachment')
}}
</p>
<p
class="p-0 m-0 text-xs leading-tight text-gray-500"
style="max-width: 480px"
>
{{
$t('settings.customization.invoices.invoice_email_attachment_setting_description')
}}
</p>
</div>
</div>
</div> </div>
</template> </template>
@ -120,6 +147,7 @@ export default {
data() { data() {
return { return {
invoiceAutogenerate: false, invoiceAutogenerate: false,
invoiceAsAttachment: false,
invoices: { invoices: {
invoice_prefix: null, invoice_prefix: null,
@ -189,6 +217,14 @@ export default {
} else { } else {
this.invoiceAutogenerate = false this.invoiceAutogenerate = false
} }
this.invoice_email_attachment = val ? val.invoice_email_attachment : ''
if (this.invoice_email_attachment === 'YES') {
this.invoiceAsAttachment = true
} else {
this.invoiceAsAttachment = false
}
}, },
}, },
@ -209,6 +245,7 @@ export default {
let data = { let data = {
settings: { settings: {
invoice_auto_generate: this.invoiceAutogenerate ? 'YES' : 'NO', invoice_auto_generate: this.invoiceAutogenerate ? 'YES' : 'NO',
invoice_email_attachment: this.invoiceAsAttachment ? 'YES' : 'NO',
}, },
} }

View File

@ -63,7 +63,7 @@
<sw-divider class="mt-6 mb-8" /> <sw-divider class="mt-6 mb-8" />
<div class="flex"> <div class="flex mt-3 mb-4">
<div class="relative w-12"> <div class="relative w-12">
<sw-switch <sw-switch
v-model="paymentAutogenerate" v-model="paymentAutogenerate"
@ -90,6 +90,33 @@
</p> </p>
</div> </div>
</div> </div>
<div class="flex mb-2">
<div class="relative w-12">
<sw-switch
v-model="paymentAsAttachment"
class="absolute"
style="top: -20px"
@change="setPaymentSetting"
/>
</div>
<div class="ml-4">
<p class="p-0 mb-1 text-base leading-snug text-black">
{{
$t('settings.customization.payments.payment_email_attachment')
}}
</p>
<p
class="p-0 m-0 text-xs leading-tight text-gray-500"
style="max-width: 480px"
>
{{
$t('settings.customization.payments.payment_email_attachment_setting_description')
}}
</p>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
@ -108,6 +135,7 @@ export default {
data() { data() {
return { return {
paymentAutogenerate: false, paymentAutogenerate: false,
paymentAsAttachment: false,
payments: { payments: {
payment_prefix: null, payment_prefix: null,
@ -184,6 +212,14 @@ export default {
} else { } else {
this.paymentAutogenerate = false this.paymentAutogenerate = false
} }
this.payment_email_attachment = val ? val.payment_email_attachment : ''
if (this.payment_email_attachment === 'YES') {
this.payment_email_attachment = true
} else {
this.payment_email_attachment = false
}
}, },
}, },
@ -203,6 +239,7 @@ export default {
let data = { let data = {
settings: { settings: {
payment_auto_generate: this.paymentAutogenerate ? 'YES' : 'NO', payment_auto_generate: this.paymentAutogenerate ? 'YES' : 'NO',
payment_email_attachment: this.paymentAsAttachment ? 'YES' : 'NO',
}, },
} }
let response = await this.updateCompanySettings(data) let response = await this.updateCompanySettings(data)

View File

@ -17,9 +17,11 @@
@slot('subcopy') @slot('subcopy')
@component('mail::subcopy') @component('mail::subcopy')
{!! $data['body'] !!} {!! $data['body'] !!}
@component('mail::button', ['url' => url('/customer/estimates/pdf/'.$data['estimate']['unique_hash'])]) @if(!$pdfData)
View Estimate @component('mail::button', ['url' => url('/customer/estimates/pdf/'.$data['estimate']['unique_hash'])])
@endcomponent View Estimate
@endcomponent
@endif
@endcomponent @endcomponent
@endslot @endslot

View File

@ -17,9 +17,11 @@
@slot('subcopy') @slot('subcopy')
@component('mail::subcopy') @component('mail::subcopy')
{!! $data['body'] !!} {!! $data['body'] !!}
@component('mail::button', ['url' => url('/customer/invoices/pdf/'.$data['invoice']['unique_hash'])]) @if(!$pdfData)
View Invoice @component('mail::button', ['url' => url('/customer/invoices/pdf/'.$data['invoice']['unique_hash'])])
@endcomponent View Invoice
@endcomponent
@endif
@endcomponent @endcomponent
@endslot @endslot

View File

@ -17,9 +17,11 @@
@slot('subcopy') @slot('subcopy')
@component('mail::subcopy') @component('mail::subcopy')
{!! $data['body'] !!} {!! $data['body'] !!}
@component('mail::button', ['url' => url('/payments/pdf/'.$data['payment']['unique_hash'])]) @if(!$pdfData)
View Payment @component('mail::button', ['url' => url('/payments/pdf/'.$data['payment']['unique_hash'])])
@endcomponent View Payment
@endcomponent
@endif
@endcomponent @endcomponent
@endslot @endslot