Merge pull request #4820 from turbo124/v5-develop

Generic payment failure notifications.
This commit is contained in:
David Bomba 2021-02-03 09:26:16 +11:00 committed by GitHub
commit 7711a21429
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 398 additions and 180 deletions

View File

@ -53,6 +53,7 @@ class PostUpdate extends Command
nlog("finished migrating"); nlog("finished migrating");
exec('vendor/bin/composer install --no-dev'); exec('vendor/bin/composer install --no-dev');
exec('vendor/bin/composer dump');
nlog("finished running composer install "); nlog("finished running composer install ");

View File

@ -111,7 +111,7 @@ class EmailEntity extends BaseMailerJob implements ShouldQueue
->send( ->send(
new TemplateEmail( new TemplateEmail(
$this->email_entity_builder, $this->email_entity_builder,
$this->invitation->contact->client $this->invitation->contact
) )
); );
} catch (\Exception $e) { } catch (\Exception $e) {

View File

@ -0,0 +1,111 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Mail;
use App\Libraries\MultiDB;
use App\Mail\Admin\ClientPaymentFailureObject;
use App\Mail\Admin\EntityNotificationMailer;
use App\Mail\Admin\PaymentFailureObject;
use App\Models\Invoice;
use App\Models\User;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Notifications\UserNotifies;
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;
/*Multi Mailer implemented*/
class ClientPaymentFailureMailer extends BaseMailerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, UserNotifies, MakesHash;
public $client;
public $error;
public $company;
public $payment_hash;
public $settings;
/**
* Create a new job instance.
*
* @param $client
* @param $message
* @param $company
* @param $amount
*/
public function __construct($client, $error, $company, $payment_hash)
{
$this->company = $company;
$this->error = $error;
$this->client = $client;
$this->payment_hash = $payment_hash;
$this->company = $company;
$this->settings = $client->getMergedSettings();
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
/*If we are migrating data we don't want to fire these notification*/
if ($this->company->is_disabled) {
return true;
}
//Set DB
MultiDB::setDb($this->company->db);
//if we need to set an email driver do it now
$this->setMailDriver();
$this->invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->get();
$this->invoices->first()->invitations->each(function ($invitation) {
if ($invitation->contact->send_email && $invitation->contact->email) {
$mail_obj = (new ClientPaymentFailureObject($this->client, $this->error, $this->company, $this->payment_hash))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
//send email
try {
Mail::to($invitation->contact->email)
->send(new EntityNotificationMailer($mail_obj));
} catch (\Exception $e) {
$this->logMailError($e->getMessage(), $this->client);
}
}
});
}
}

View File

@ -31,11 +31,11 @@ class PaymentFailureMailer extends BaseMailerJob implements ShouldQueue
public $client; public $client;
public $message; public $error;
public $company; public $company;
public $amount; public $payment_hash;
public $settings; public $settings;
@ -47,15 +47,15 @@ class PaymentFailureMailer extends BaseMailerJob implements ShouldQueue
* @param $company * @param $company
* @param $amount * @param $amount
*/ */
public function __construct($client, $message, $company, $amount) public function __construct($client, $error, $company, $payment_hash)
{ {
$this->company = $company; $this->company = $company;
$this->message = $message; $this->error = $error;
$this->client = $client; $this->client = $client;
$this->amount = $amount; $this->payment_hash = $payment_hash;
$this->company = $company; $this->company = $company;
@ -92,7 +92,7 @@ class PaymentFailureMailer extends BaseMailerJob implements ShouldQueue
if (($key = array_search('mail', $methods)) !== false) { if (($key = array_search('mail', $methods)) !== false) {
unset($methods[$key]); unset($methods[$key]);
$mail_obj = (new PaymentFailureObject($this->client, $this->message, $this->amount, $this->company))->build(); $mail_obj = (new PaymentFailureObject($this->client, $this->error, $this->company, $this->payment_hash))->build();
$mail_obj->from = [config('mail.from.address'), config('mail.from.name')]; $mail_obj->from = [config('mail.from.address'), config('mail.from.name')];
//send email //send email

View File

@ -80,7 +80,7 @@ class EmailPayment extends BaseMailerJob implements ShouldQueue
try { try {
$mail = Mail::to($this->contact->email, $this->contact->present()->name()); $mail = Mail::to($this->contact->email, $this->contact->present()->name());
$mail->send(new TemplateEmail($email_builder, $this->contact->client)); $mail->send(new TemplateEmail($email_builder, $this->contact));
} catch (\Exception $e) { } catch (\Exception $e) {
nlog("mailing failed with message " . $e->getMessage()); nlog("mailing failed with message " . $e->getMessage());
event(new PaymentWasEmailedAndFailed($this->payment, $this->company, Mail::failures(), Ninja::eventVars())); event(new PaymentWasEmailedAndFailed($this->payment, $this->company, Mail::failures(), Ninja::eventVars()));

View File

@ -28,7 +28,7 @@ class AutoBillingFailureObject
public $payment_hash; public $payment_hash;
private $invoice; private $invoices;
/** /**
* Create a new job instance. * Create a new job instance.
@ -54,8 +54,7 @@ class AutoBillingFailureObject
public function build() public function build()
{ {
$this->$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->get();
$this->invoice = Invoice::where('id', $this->decodePrimarykey($this->payment_hash->invoices()[0]->invoice_id))->first();
$mail_obj = new stdClass; $mail_obj = new stdClass;
$mail_obj->amount = $this->getAmount(); $mail_obj->amount = $this->getAmount();
@ -78,7 +77,7 @@ class AutoBillingFailureObject
return return
ctrans( ctrans(
'texts.auto_bill_failed', 'texts.auto_bill_failed',
['invoice_number' => $this->invoice->number] ['invoice_number' => $this->invoices->first()->number]
); );
} }
@ -89,7 +88,7 @@ class AutoBillingFailureObject
$data = [ $data = [
'title' => ctrans( 'title' => ctrans(
'texts.auto_bill_failed', 'texts.auto_bill_failed',
['invoice_number' => $this->invoice->number] ['invoice_number' => $this->invoices->first()->number]
), ),
'message' => $this->error, 'message' => $this->error,
'signature' => $signature, 'signature' => $signature,

View File

@ -0,0 +1,114 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Mail\Admin;
use App\Models\Invoice;
use App\Utils\Number;
use App\Utils\Traits\MakesHash;
use stdClass;
class ClientPaymentFailureObject
{
use MakesHash;
public $client;
public $error;
public $company;
public $payment_hash;
private $invoices;
/**
* Create a new job instance.
*
* @param $client
* @param $message
* @param $company
* @param $amount
*/
public function __construct($client, $error, $company, $payment_hash)
{
$this->client = $client;
$this->error = $error;
$this->company = $company;
$this->payment_hash = $payment_hash;
$this->company = $company;
}
public function build()
{
$this->invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->get();
$mail_obj = new stdClass;
$mail_obj->amount = $this->getAmount();
$mail_obj->subject = $this->getSubject();
$mail_obj->data = $this->getData();
$mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key;
return $mail_obj;
}
private function getAmount()
{
return array_sum(array_column($this->payment_hash->invoices(), 'amount')) + $this->payment_hash->fee_total;
}
private function getSubject()
{
return
ctrans(
'texts.notification_invoice_payment_failed_subject',
['invoice' => $this->client->present()->name()]
);
}
private function getData()
{
$signature = $this->client->getSetting('email_signature');
$data = [
'title' => ctrans(
'texts.notification_invoice_payment_failed_subject',
[
'invoice' => $this->invoices->first()->number
]
),
'greeting' => ctrans('texts.email_salutation', ['name' => $this->client->present()->name]),
'message' => $this->error,
'signature' => $signature,
'logo' => $this->company->present()->logo(),
'settings' => $this->client->getMergedSettings(),
'whitelabel' => $this->company->account->isPaid() ? true : false,
'url' => route('client.login'),
'button' => ctrans('texts.login'),
'additional_info' => false
];
return $data;
}
}

View File

@ -11,29 +11,52 @@
namespace App\Mail\Admin; namespace App\Mail\Admin;
use App\Models\Invoice;
use App\Utils\Number; use App\Utils\Number;
use App\Utils\Traits\MakesHash;
use stdClass; use stdClass;
class PaymentFailureObject class PaymentFailureObject
{ {
use MakesHash;
public $client; public $client;
public $message; public $error;
public $company; public $company;
public $amount; public $payment_hash;
public function __construct($client, $message, $amount, $company) private $invoices;
/**
* Create a new job instance.
*
* @param $client
* @param $message
* @param $company
* @param $amount
*/
public function __construct($client, $error, $company, $payment_hash)
{ {
$this->client = $client; $this->client = $client;
$this->message = $message;
$this->amount = $amount; $this->error = $error;
$this->company = $company; $this->company = $company;
$this->payment_hash = $payment_hash;
$this->company = $company;
} }
public function build() public function build()
{ {
$this->invoices = Invoice::whereIn('id', $this->transformKeys(array_column($this->payment_hash->invoices(), 'invoice_id')))->get();
$mail_obj = new stdClass; $mail_obj = new stdClass;
$mail_obj->amount = $this->getAmount(); $mail_obj->amount = $this->getAmount();
$mail_obj->subject = $this->getSubject(); $mail_obj->subject = $this->getSubject();
@ -46,16 +69,20 @@ class PaymentFailureObject
private function getAmount() private function getAmount()
{ {
return Number::formatMoney($this->amount, $this->client);
return array_sum(array_column($this->payment_hash->invoices(), 'amount')) + $this->payment_hash->fee_total;
} }
private function getSubject() private function getSubject()
{ {
return return
ctrans( ctrans(
'texts.payment_failed_subject', 'texts.payment_failed_subject',
['client' => $this->client->present()->name()] ['client' => $this->client->present()->name()]
); );
} }
private function getData() private function getData()
@ -65,23 +92,36 @@ class PaymentFailureObject
$data = [ $data = [
'title' => ctrans( 'title' => ctrans(
'texts.payment_failed_subject', 'texts.payment_failed_subject',
['client' => $this->client->present()->name()] [
), 'client' => $this->client->present()->name()
'message' => ctrans( ]
'texts.notification_payment_paid',
['amount' => $this->getAmount(),
'client' => $this->client->present()->name(),
'message' => $this->message,
]
), ),
'message' => $this->error,
'signature' => $signature, 'signature' => $signature,
'logo' => $this->company->present()->logo(), 'logo' => $this->company->present()->logo(),
'settings' => $this->client->getMergedSettings(), 'settings' => $this->client->getMergedSettings(),
'whitelabel' => $this->company->account->isPaid() ? true : false, 'whitelabel' => $this->company->account->isPaid() ? true : false,
'url' => config('ninja.app_url'), 'url' => config('ninja.app_url'),
'button' => ctrans('texts.login'), 'button' => ctrans('texts.login'),
'additional_info' => $this->buildFailedInvoices()
]; ];
return $data; return $data;
} }
private function buildFailedInvoices()
{
$text = '';
foreach($this->invoices as $invoice)
{
$text .= ctrans('texts.notification_invoice_payment_failed_subject', ['invoice' => $invoice->number]) . "\n";
}
return $text;
}
} }

View File

@ -31,14 +31,14 @@ class DownloadInvoices extends Mailable
public function build() public function build()
{ {
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->subject(ctrans('texts.download_files'))
->subject(ctrans('texts.download_files')) ->markdown(
->markdown( 'email.admin.download_files',
'email.admin.download_files', [
[ 'url' => $this->file_path,
'url' => $this->file_path, 'logo' => $this->company->present()->logo,
'logo' => $this->company->present()->logo, 'whitelabel' => $this->company->account->isPaid() ? true : false,
] ]
); );
} }
} }

View File

@ -32,7 +32,8 @@ class MigrationCompleted extends Mailable
{ {
$data['settings'] = $this->company->settings; $data['settings'] = $this->company->settings;
$data['company'] = $this->company; $data['company'] = $this->company;
$data['whitelabel'] = $this->company->account->isPaid() ? true : false;
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.import.completed', $data) ->view('email.import.completed', $data)
->attach($this->company->invoices->first()->pdf_file_path()); ->attach($this->company->invoices->first()->pdf_file_path());

View File

@ -32,7 +32,6 @@ class MigrationFailed extends Mailable
public function build() public function build()
{ {
return $this->from(config('mail.from.address'), config('mail.from.name')) return $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.migration.failed'); ->view('email.migration.failed');
} }
} }

View File

@ -12,6 +12,7 @@
namespace App\Mail; namespace App\Mail;
use App\Models\Client; use App\Models\Client;
use App\Models\ClientContact;
use App\Models\User; use App\Models\User;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable; use Illuminate\Mail\Mailable;
@ -25,11 +26,15 @@ class TemplateEmail extends Mailable
private $client; private $client;
public function __construct($build_email, Client $client) private $contact;
public function __construct($build_email, ClientContact $contact)
{ {
$this->build_email = $build_email; $this->build_email = $build_email;
$this->client = $client; $this->contact = $contact;
$this->client = $contact->client;
} }
/** /**
@ -64,12 +69,12 @@ class TemplateEmail extends Mailable
'settings' => $settings, 'settings' => $settings,
]) ])
->view($template_name, [ ->view($template_name, [
'greeting' => ctrans('texts.email_salutation', ['name' => $this->contact->present()->name()]),
'body' => $this->build_email->getBody(), 'body' => $this->build_email->getBody(),
'footer' => $this->build_email->getFooter(), 'footer' => $this->build_email->getFooter(),
'view_link' => $this->build_email->getViewLink(), 'view_link' => $this->build_email->getViewLink(),
'view_text' => $this->build_email->getViewText(), 'view_text' => $this->build_email->getViewText(),
'title' => '', 'title' => '',
// 'title' => $this->build_email->getSubject(),
'signature' => $settings->email_signature, 'signature' => $settings->email_signature,
'settings' => $settings, 'settings' => $settings,
'company' => $company, 'company' => $company,

View File

@ -17,6 +17,7 @@ use App\Exceptions\PaymentFailed;
use App\Factory\PaymentFactory; use App\Factory\PaymentFactory;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\Jobs\Mail\AutoBillingFailureMailer; use App\Jobs\Mail\AutoBillingFailureMailer;
use App\Jobs\Mail\ClientPaymentFailureMailer;
use App\Jobs\Mail\PaymentFailureMailer; use App\Jobs\Mail\PaymentFailureMailer;
use App\Jobs\Util\SystemLogger; use App\Jobs\Util\SystemLogger;
use App\Models\Client; use App\Models\Client;
@ -335,6 +336,8 @@ class BaseDriver extends AbstractPaymentDriver
public function processInternallyFailedPayment($gateway, $e) public function processInternallyFailedPayment($gateway, $e)
{ {
$this->unWindGatewayFees($this->payment_hash);
if ($e instanceof CheckoutHttpException) { if ($e instanceof CheckoutHttpException) {
$error = $e->getBody(); $error = $e->getBody();
} }
@ -344,7 +347,14 @@ class BaseDriver extends AbstractPaymentDriver
else else
$error = $e->getMessage(); $error = $e->getMessage();
AutoBillingFailureMailer::dispatch( PaymentFailureMailer::dispatch(
$gateway->client,
$error,
$gateway->client->company,
$this->payment_hash
);
ClientPaymentFailureMailer::dispatch(
$gateway->client, $gateway->client,
$error, $error,
$gateway->client->company, $gateway->client->company,
@ -362,36 +372,6 @@ class BaseDriver extends AbstractPaymentDriver
throw new PaymentFailed($error, $e->getCode()); throw new PaymentFailed($error, $e->getCode());
} }
public function tokenBillingFailed($gateway, $e)
{
$this->unWindGatewayFees($this->payment_hash);
if ($e instanceof CheckoutHttpException) {
$error = $e->getBody();
}
else if ($e instanceof Exception) {
$error = $e->getMessage();
}
else
$error = $e->getMessage();
AutoBillingFailureMailer::dispatch(
$gateway->client,
$error,
$gateway->client->company,
$this->payment_hash
);
SystemLogger::dispatch(
$gateway->payment_hash,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_ERROR,
$gateway::SYSTEM_LOG_TYPE,
$gateway->client,
);
}
/** /**
* Wrapper method for checking if resource is good. * Wrapper method for checking if resource is good.
* *

View File

@ -79,102 +79,47 @@ class Charge
]); ]);
SystemLogger::dispatch($response, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_STRIPE, $this->stripe->client); SystemLogger::dispatch($response, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_STRIPE, $this->stripe->client);
} catch (CardException $e) { } catch (\Exception $e) {
// Since it's a decline, \Stripe\Exception\CardException will be caught
$data = [ $data =[
'status' => $e->getHttpStatus(), 'status' => '',
'error_type' => $e->getError()->type, 'error_type' => '',
'error_code' => $e->getError()->code, 'error_code' => '',
'param' => $e->getError()->param, 'param' => '',
'message' => $e->getError()->message, 'message' => '',
]; ];
$this->stripe->tokenBillingFailed($this->stripe, $e);
switch ($e) {
case ($e instanceof CardException):
$data['status'] = $e->getHttpStatus();
$data['error_type'] = $e->getError()->type;
$data['error_code'] = $e->getError()->code;
$data['param'] = $e->getError()->param;
$data['message'] = $e->getError()->message;
break;
case ($e instanceof RateLimitException):
$data['message'] = 'Too many requests made to the API too quickly';
break;
case ($e instanceof InvalidRequestException):
$data['message'] = 'Invalid parameters were supplied to Stripe\'s API';
break;
case ($e instanceof AuthenticationException):
$data['message'] = 'Authentication with Stripe\'s API failed';
break;
case ($e instanceof ApiErrorException):
$data['message'] = 'Network communication with Stripe failed';
break;
default:
$data['message'] = $e->getMessage();
break;
}
$this->stripe->processInternallyFailedPayment($this->stripe, $e);
SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client); SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client);
} catch (RateLimitException $e) { }
// Too many requests made to the API too quickly
$data = [
'status' => '',
'error_type' => '',
'error_code' => '',
'param' => '',
'message' => 'Too many requests made to the API too quickly',
];
$this->stripe->tokenBillingFailed($this->stripe, $e);
SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client);
} catch (InvalidRequestException $e) {
// Invalid parameters were supplied to Stripe's API
//
$data = [
'status' => '',
'error_type' => '',
'error_code' => '',
'param' => '',
'message' => 'Invalid parameters were supplied to Stripe\'s API',
];
$this->stripe->tokenBillingFailed($this->stripe, $e);
SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client);
} catch (AuthenticationException $e) {
// Authentication with Stripe's API failed
$data = [
'status' => '',
'error_type' => '',
'error_code' => '',
'param' => '',
'message' => 'Authentication with Stripe\'s API failed',
];
$this->stripe->tokenBillingFailed($this->stripe, $e);
SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client);
} catch (ApiConnectionException $e) {
// Network communication with Stripe failed
$data = [
'status' => '',
'error_type' => '',
'error_code' => '',
'param' => '',
'message' => 'Network communication with Stripe failed',
];
$this->stripe->tokenBillingFailed($this->stripe, $e);
SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client);
} catch (ApiErrorException $e) {
$data = [
'status' => '',
'error_type' => '',
'error_code' => '',
'param' => '',
'message' => 'API Error',
];
$this->stripe->tokenBillingFailed($this->stripe, $e);
SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client);
} catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
//
$data = [
'status' => '',
'error_type' => '',
'error_code' => '',
'param' => '',
'message' => $e->getMessage(),
];
$this->stripe->tokenBillingFailed($this->stripe, $e);
SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client);
}
if (! $response) { if (! $response) {
return false; return false;

View File

@ -193,6 +193,9 @@ class Phantom
->build() ->build()
->getCompiledHTML(true); ->getCompiledHTML(true);
if (config('ninja.log_pdf_html')) {
info($data['html']);
}
return view('pdf.html', $data); return view('pdf.html', $data);
} }

View File

@ -16,10 +16,11 @@
InvoiceNinja (contact@invoiceninja.com) InvoiceNinja (contact@invoiceninja.com)
@endslot @endslot
@slot('footer') @if(!$whitelabel)
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja']) @slot('footer')
For any info, please visit InvoiceNinja. @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja'])
@endcomponent For any info, please visit InvoiceNinja.
@endslot @endcomponent
@endslot
@endif
@endcomponent @endcomponent

View File

@ -1,14 +1,23 @@
@component('email.template.master', ['design' => 'light', 'settings' => $settings]) @component('email.template.master', ['design' => 'light', 'settings' => $settings])
@slot('header') @slot('header')
@include('email.components.header', ['logo' => $logo]) @include('email.components.header', ['logo' => $logo])
@endslot @endslot
@if(isset($greeting))
<p>{{ $greeting }}</p>
@endif
<p>{{ $title }}</p> <p>{{ $title }}</p>
<p>{{ $message }}</p> <p>{{ $message }}</p>
@if(isset($additional_info))
<p> {{ $additional_info }}</p>
@endif
@component('email.components.button', ['url' => $url]) @component('email.components.button', ['url' => $url])
@lang($button) @lang($button)
@endcomponent @endcomponent
@ -17,9 +26,11 @@
{{ $signature }} {{ $signature }}
@endslot @endslot
@slot('footer') @if(!$whitelabel)
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja']) @slot('footer')
For any info, please visit InvoiceNinja. @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja'])
@endcomponent For any info, please visit InvoiceNinja.
@endslot @endcomponent
@endslot
@endif
@endcomponent @endcomponent

View File

@ -76,4 +76,12 @@
<a href="{{ url('/') }}" target="_blank" class="button">{{ ctrans('texts.account_login')}}</a> <a href="{{ url('/') }}" target="_blank" class="button">{{ ctrans('texts.account_login')}}</a>
<p>{{ ctrans('texts.email_signature')}}<br/> {{ ctrans('texts.email_from') }}</p> <p>{{ ctrans('texts.email_signature')}}<br/> {{ ctrans('texts.email_from') }}</p>
@endcomponent
@if(!$whitelabel)
@slot('footer')
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja'])
For any info, please visit InvoiceNinja.
@endcomponent
@endslot
@endif
@endcomponent

View File

@ -51,7 +51,7 @@ class CompanyLedgerTest extends TestCase
$this->withoutExceptionHandling(); $this->withoutExceptionHandling();
$this->artisan('db:seed'); $this->artisan('db:seed --force');
/* Warm up the cache !*/ /* Warm up the cache !*/
$cached_tables = config('ninja.cached_tables'); $cached_tables = config('ninja.cached_tables');

View File

@ -131,7 +131,7 @@ trait MockAccountData
/* Warm up the cache !*/ /* Warm up the cache !*/
$cached_tables = config('ninja.cached_tables'); $cached_tables = config('ninja.cached_tables');
$this->artisan('db:seed'); $this->artisan('db:seed --force');
foreach ($cached_tables as $name => $class) { foreach ($cached_tables as $name => $class) {