1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 21:22:58 +01:00
invoiceninja/app/Utils/TemplateEngine.php

429 lines
15 KiB
PHP
Raw Normal View History

<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
2023-01-28 23:21:40 +01:00
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
2021-06-16 08:58:16 +02:00
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Utils;
2023-03-18 08:24:56 +01:00
use App\DataMapper\EmailTemplateDefaults;
use App\Mail\Engine\PaymentEmailEngine;
use App\Models\Client;
2023-03-18 08:24:56 +01:00
use App\Models\ClientContact;
use App\Models\Invoice;
2023-03-18 08:24:56 +01:00
use App\Models\InvoiceInvitation;
2022-10-27 11:17:31 +02:00
use App\Models\Payment;
2022-06-30 08:40:31 +02:00
use App\Models\PurchaseOrder;
2023-03-18 08:24:56 +01:00
use App\Models\PurchaseOrderInvitation;
use App\Models\Quote;
2023-03-16 01:51:07 +01:00
use App\Models\QuoteInvitation;
2023-03-18 08:24:56 +01:00
use App\Models\Vendor;
use App\Models\VendorContact;
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\MakesInvoiceHtml;
use App\Utils\Traits\MakesTemplateData;
2023-03-18 08:24:56 +01:00
use DB;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Str;
use League\CommonMark\CommonMarkConverter;
class TemplateEngine
{
use MakesHash;
use MakesTemplateData;
use MakesInvoiceHtml;
public $body;
public $subject;
public $entity;
public $entity_id;
public $template;
2023-08-06 04:34:41 +02:00
/** @var \App\Models\Invoice | \App\Models\Quote | \App\Models\Credit | \App\Models\PurchaseOrder | null $entity_obj **/
private $entity_obj;
2023-08-06 04:34:41 +02:00
/** @var \App\Models\Company | \App\Models\Client | null $settings_entity **/
private $settings_entity;
private $settings;
2021-01-19 01:46:00 +01:00
private $raw_body;
private $raw_subject;
2021-04-22 12:29:00 +02:00
/**
* @var array
*/
private $labels_and_values;
2021-01-19 01:46:00 +01:00
public function __construct($body, $subject, $entity, $entity_id, $template)
{
$this->body = $body;
$this->subject = $subject;
$this->entity = $entity;
$this->entity_id = $entity_id;
$this->template = $template;
$this->entity_obj = null;
$this->settings_entity = null;
}
public function build()
{
return $this->setEntity()
->setSettingsObject()
->setTemplates()
->replaceValues()
->renderTemplate();
}
private function setEntity()
{
if (strlen($this->entity) > 1 && strlen($this->entity_id) > 1) {
$class = 'App\Models\\' . ucfirst(Str::camel($this->entity));
$this->entity_obj = $class::withTrashed()->where('id', $this->decodePrimaryKey($this->entity_id))->company()->first();
2023-08-06 09:35:19 +02:00
} elseif (stripos($this->template, 'quote') !== false && $quote = Quote::query()->whereHas('invitations')->withTrashed()->company()->first()) {
2023-03-16 01:51:07 +01:00
$this->entity = 'quote';
$this->entity_obj = $quote;
2023-08-06 09:35:19 +02:00
} elseif (stripos($this->template, 'purchase') !== false && $purchase_order = PurchaseOrder::query()->whereHas('invitations')->withTrashed()->company()->first()) {
2023-03-16 01:51:07 +01:00
$this->entity = 'purchase_order';
$this->entity_obj = $purchase_order;
2023-08-06 09:35:19 +02:00
}elseif (stripos($this->template, 'payment') !== false && $payment = Payment::query()->withTrashed()->company()->first()) {
2023-06-22 03:03:25 +02:00
$this->entity = 'payment';
$this->entity_obj = $payment;
}
2023-08-06 09:35:19 +02:00
elseif ($invoice = Invoice::query()->whereHas('invitations')->withTrashed()->company()->first()) {
2023-03-16 01:51:07 +01:00
$this->entity_obj = $invoice;
2023-03-18 08:24:56 +01:00
} else {
$this->mockEntity();
2020-11-25 15:19:52 +01:00
}
return $this;
}
private function setSettingsObject()
{
2023-08-06 04:34:41 +02:00
/** @var \App\Models\User $user */
$user = auth()->user();
if ($this->entity == 'purchaseOrder' || $this->entity == 'purchase_order') {
2023-08-06 04:34:41 +02:00
$this->settings_entity = $user->company();
2022-06-30 08:40:31 +02:00
$this->settings = $this->settings_entity->settings;
} elseif ($this->entity_obj->client()->exists()) {
$this->settings_entity = $this->entity_obj->client;
$this->settings = $this->settings_entity->getMergedSettings();
} else {
2023-08-06 04:34:41 +02:00
$this->settings_entity = $user->company();
$this->settings = $this->settings_entity->settings;
}
App::forgetInstance('translator');
2021-05-31 12:40:34 +02:00
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->settings));
return $this;
}
/* If the body / subject are not populated we need to get the defaults */
private function setTemplates()
{
if (strlen($this->subject) == 0 && strlen($this->template) > 1) {
$subject_template = str_replace('template', 'subject', $this->template);
2020-09-17 00:22:23 +02:00
2020-11-25 15:19:52 +01:00
if (strlen($this->settings_entity->getSetting($subject_template)) > 1) {
2020-09-17 00:22:23 +02:00
$this->subject = $this->settings_entity->getSetting($subject_template);
2020-11-25 15:19:52 +01:00
} else {
2020-09-17 00:22:23 +02:00
$this->subject = EmailTemplateDefaults::getDefaultTemplate($subject_template, $this->settings_entity->locale());
2020-11-25 15:19:52 +01:00
}
}
if (strlen($this->body) == 0 && strlen($this->template) > 1) {
2020-11-25 15:19:52 +01:00
if (strlen($this->settings_entity->getSetting($this->template)) > 1) {
2020-09-17 00:22:23 +02:00
$this->body = $this->settings_entity->getSetting($this->template);
2020-11-25 15:19:52 +01:00
} else {
2020-09-17 00:22:23 +02:00
$this->body = EmailTemplateDefaults::getDefaultTemplate($this->template, $this->settings_entity->locale());
2020-11-25 15:19:52 +01:00
}
}
2021-04-20 13:31:21 +02:00
return $this;
}
private function replaceValues()
{
2021-01-19 01:46:00 +01:00
$this->raw_body = $this->body;
$this->raw_subject = $this->subject;
2021-01-19 01:46:00 +01:00
if ($this->entity_obj->client()->exists()) {
$this->entityValues($this->entity_obj->client->primary_contact()->first());
} elseif ($this->entity_obj->vendor()->exists()) {
$this->entityValues($this->entity_obj->vendor->primary_contact()->first());
} else {
$this->fakerValues();
}
return $this;
}
private function fakerValues()
{
$labels = $this->makeFakerLabels();
$values = $this->makeFakerValues();
$this->body = strtr($this->body, $labels);
$this->body = strtr($this->body, $values);
$this->subject = strtr($this->subject, $labels);
$this->subject = strtr($this->subject, $values);
$converter = new CommonMarkConverter([
'allow_unsafe_links' => false,
]);
2022-07-04 06:41:16 +02:00
$this->body = $converter->convert($this->body)->getContent();
}
private function entityValues($contact)
{
2023-02-16 02:36:09 +01:00
if (in_array($this->entity, ['purchaseOrder', 'purchase_order'])) {
$this->labels_and_values = (new VendorHtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues();
2023-02-16 02:36:09 +01:00
} elseif ($this->entity == 'payment') {
2022-10-27 11:17:31 +02:00
$this->labels_and_values = (new PaymentEmailEngine($this->entity_obj, $this->entity_obj->client->contacts->first()))->generateLabelsAndValues();
2023-02-16 02:36:09 +01:00
} else {
$this->labels_and_values = (new HtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues();
2023-02-16 02:36:09 +01:00
}
2020-10-28 06:50:06 +01:00
2021-04-22 12:29:00 +02:00
$this->body = strtr($this->body, $this->labels_and_values['labels']);
$this->body = strtr($this->body, $this->labels_and_values['values']);
2021-01-19 01:46:00 +01:00
2021-04-22 12:29:00 +02:00
$this->subject = strtr($this->subject, $this->labels_and_values['labels']);
$this->subject = strtr($this->subject, $this->labels_and_values['values']);
$email_style = $this->settings_entity->getSetting('email_style');
if ($email_style !== 'custom') {
$this->body = DesignHelpers::parseMarkdownToHtml($this->body);
}
}
private function renderTemplate()
{
2023-08-06 04:34:41 +02:00
/** @var \App\Models\User $user */
$user = auth()->user();
/* wrapper */
$email_style = $this->settings_entity->getSetting('email_style');
$data['title'] = '';
$data['body'] = '$body';
$data['footer'] = '';
2023-08-06 04:34:41 +02:00
$data['logo'] = $user->company()->present()->logo();
2020-10-28 11:10:49 +01:00
2023-02-16 02:36:09 +01:00
if ($this->entity_obj->client()->exists()) {
2022-06-30 08:40:31 +02:00
$data = array_merge($data, Helpers::sharedEmailVariables($this->entity_obj->client));
2023-02-16 02:36:09 +01:00
} else {
2022-06-30 08:40:31 +02:00
$data['signature'] = $this->settings->email_signature;
$data['settings'] = $this->settings;
$data['whitelabel'] = $this->entity_obj ? $this->entity_obj->company->account->isPaid() : true;
$data['company'] = $this->entity_obj ? $this->entity_obj->company : '';
$data['settings'] = $this->settings;
}
if ($email_style == 'custom') {
$wrapper = $this->settings_entity->getSetting('email_style_custom');
2021-04-22 12:29:00 +02:00
// In order to parse variables such as $signature in the body,
// we need to replace strings with the values from HTMLEngine.
$wrapper = strtr($wrapper, $this->labels_and_values['values']);
/*If no custom design exists, send back a blank!*/
if (strlen($wrapper) > 1) {
$wrapper = $this->renderView($wrapper, $data);
} else {
$wrapper = '';
}
} elseif ($email_style == 'plain') {
$wrapper = view($this->getTemplatePath($email_style), $data)->render();
$injection = '';
$wrapper = str_replace('<head>', $injection, $wrapper);
} else {
2021-06-15 15:42:37 +02:00
$wrapper = view($this->getTemplatePath('client'), $data)->render();
$injection = '';
$wrapper = str_replace('<head>', $injection, $wrapper);
}
$data = [
'subject' => $this->subject,
2021-06-23 10:46:51 +02:00
'body' => $this->body,
'wrapper' => $wrapper,
2021-01-19 01:46:00 +01:00
'raw_body' => $this->raw_body,
'raw_subject' => $this->raw_subject,
];
$this->tearDown();
return $data;
}
private function mockEntity()
{
2023-02-16 02:36:09 +01:00
if (!$this->entity && $this->template && str_contains($this->template, 'purchase_order')) {
2022-07-01 10:11:04 +02:00
$this->entity = 'purchaseOrder';
2023-02-16 02:36:09 +01:00
} elseif (str_contains($this->template, 'payment')) {
2022-10-27 11:17:31 +02:00
$this->entity = 'payment';
2023-02-16 02:36:09 +01:00
}
DB::connection(config('database.default'))->beginTransaction();
2023-08-06 04:34:41 +02:00
/** @var \App\Models\User $user */
$user = auth()->user();
2022-06-30 08:40:31 +02:00
2023-08-06 04:34:41 +02:00
$vendor = false;
/** @var \App\Models\Client $client */
$client = Client::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
]);
$contact = ClientContact::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
'client_id' => $client->id,
'is_primary' => 1,
'send_email' => true,
]);
2022-10-27 11:17:31 +02:00
if ($this->entity == 'payment') {
$this->entity_obj = Payment::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
2022-10-27 11:17:31 +02:00
'client_id' => $client->id,
'amount' => 10,
'applied' => 10,
'refunded' => 5,
]);
2023-08-06 04:34:41 +02:00
/** @var \App\Models\Invoice $invoice */
2022-10-27 11:17:31 +02:00
$invoice = Invoice::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
2022-10-27 11:17:31 +02:00
'client_id' => $client->id,
'amount' => 10,
'balance' => 10,
2023-02-16 02:36:09 +01:00
'number' => rand(1, 10000)
2022-10-27 11:17:31 +02:00
]);
2023-08-06 04:34:41 +02:00
/** @var \App\Models\InvoiceInvitation $invitation */
2022-10-27 11:17:31 +02:00
$invitation = InvoiceInvitation::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
2022-10-27 11:17:31 +02:00
'invoice_id' => $invoice->id,
'client_contact_id' => $contact->id,
]);
$this->entity_obj->invoices()->attach($invoice->id, [
'amount' => 10,
]);
}
if (!$this->entity || $this->entity == 'invoice') {
$this->entity_obj = Invoice::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
'client_id' => $client->id,
2023-03-16 01:51:07 +01:00
'amount' => '10',
'balance' => '10',
]);
2021-11-08 04:09:06 +01:00
$invitation = InvoiceInvitation::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
'invoice_id' => $this->entity_obj->id,
'client_contact_id' => $contact->id,
2021-11-08 04:09:06 +01:00
]);
}
if ($this->entity == 'quote') {
2021-11-08 04:09:06 +01:00
$this->entity_obj = Quote::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
'client_id' => $client->id,
]);
2021-11-08 04:09:06 +01:00
$invitation = QuoteInvitation::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
'quote_id' => $this->entity_obj->id,
'client_contact_id' => $contact->id,
2021-11-08 04:09:06 +01:00
]);
}
if ($this->entity == 'purchaseOrder') {
2022-06-30 08:40:31 +02:00
$vendor = Vendor::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
]);
2022-06-30 08:40:31 +02:00
$contact = VendorContact::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
'vendor_id' => $vendor->id,
'is_primary' => 1,
'send_email' => true,
]);
2022-06-30 08:40:31 +02:00
$this->entity_obj = PurchaseOrder::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
'vendor_id' => $vendor->id,
]);
2022-06-30 08:40:31 +02:00
$invitation = PurchaseOrderInvitation::factory()->create([
2023-08-06 04:34:41 +02:00
'user_id' => $user->id,
'company_id' => $user->company()->id,
'purchase_order_id' => $this->entity_obj->id,
'vendor_contact_id' => $contact->id,
2022-06-30 08:40:31 +02:00
]);
}
if ($vendor) {
2022-06-30 08:40:31 +02:00
$this->entity_obj->setRelation('invitations', $invitation);
$this->entity_obj->setRelation('vendor', $vendor);
2023-08-06 04:34:41 +02:00
$this->entity_obj->setRelation('company', $user->company());
2022-06-30 08:40:31 +02:00
$this->entity_obj->load('vendor');
2023-08-06 04:34:41 +02:00
$vendor->setRelation('company', $user->company());
2022-06-30 08:40:31 +02:00
$vendor->load('company');
} else {
2022-06-30 08:40:31 +02:00
$this->entity_obj->setRelation('invitations', $invitation);
$this->entity_obj->setRelation('client', $client);
2023-08-06 04:34:41 +02:00
$this->entity_obj->setRelation('company', $user->company());
2022-06-30 08:40:31 +02:00
$this->entity_obj->load('client');
2023-08-06 04:34:41 +02:00
$client->setRelation('company', $user->company());
2022-06-30 08:40:31 +02:00
$client->load('company');
}
}
private function tearDown()
{
DB::connection(config('database.default'))->rollBack();
}
}