mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-05 13:24:36 -04:00
Performance improvements (#3634)
* Adjustments for tests * Implement handling of temp downloading resources * Refactor paths * Refactors for file paths * Refactor paths * Add in S3 adapter * Refactor company Documment URL * Refactor for entity pdf performance * Refactors for invoice generation * Enhancements for emails invoices * Emails * Fixes for client portal queries
This commit is contained in:
parent
74a6c4f2ee
commit
e5a230e0c7
@ -5,7 +5,7 @@ APP_URL=http://127.0.0.1:8000
|
|||||||
APP_KEY=s7epnjtomsdond5zgfqgaqmwhhcjct02
|
APP_KEY=s7epnjtomsdond5zgfqgaqmwhhcjct02
|
||||||
APP_CIPHER=AES-256-CBC
|
APP_CIPHER=AES-256-CBC
|
||||||
REQUIRE_HTTPS=false
|
REQUIRE_HTTPS=false
|
||||||
NINJA_ENVIRONMENT=hosted
|
NINJA_ENVIRONMENT=development
|
||||||
|
|
||||||
DB_TYPE=mysql
|
DB_TYPE=mysql
|
||||||
DB_STRICT=false
|
DB_STRICT=false
|
||||||
|
@ -21,3 +21,4 @@ TEST_USERNAME=user@example.com
|
|||||||
TEST_PERMISSIONS_USERNAME=permissions@example.com
|
TEST_PERMISSIONS_USERNAME=permissions@example.com
|
||||||
|
|
||||||
MULTI_DB_ENABLED=true
|
MULTI_DB_ENABLED=true
|
||||||
|
NINJA_ENVIRONMENT=development
|
||||||
|
@ -143,7 +143,7 @@ class SendTestEmails extends Command
|
|||||||
$invoice->setRelation('invitations', $ii);
|
$invoice->setRelation('invitations', $ii);
|
||||||
$invoice->service()->markSent()->save();
|
$invoice->service()->markSent()->save();
|
||||||
|
|
||||||
CreateInvoicePdf::dispatch($invoice, $company, $client->primary_contact()->first());
|
CreateInvoicePdf::dispatch($invoice->invitations()->first());
|
||||||
|
|
||||||
$cc_emails = [config('ninja.testvars.test_email')];
|
$cc_emails = [config('ninja.testvars.test_email')];
|
||||||
$bcc_emails = [config('ninja.testvars.test_email')];
|
$bcc_emails = [config('ninja.testvars.test_email')];
|
||||||
|
@ -173,7 +173,7 @@ class InvoiceFilters extends QueryFilters
|
|||||||
if (auth('contact')->user()) {
|
if (auth('contact')->user()) {
|
||||||
return $this->contactViewFilter();
|
return $this->contactViewFilter();
|
||||||
} else {
|
} else {
|
||||||
return $this->builder->company();
|
return $this->builder->company()->with(['invitations.company'],['documents.company']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
// return $this->builder->whereCompanyId(auth()->user()->company()->id);
|
||||||
|
@ -77,7 +77,7 @@ class InvoiceEmail extends EmailBuilder
|
|||||||
->setViewText(ctrans('texts.view_invoice'));
|
->setViewText(ctrans('texts.view_invoice'));
|
||||||
|
|
||||||
if ($client->getSetting('pdf_email_attachment') !== false) {
|
if ($client->getSetting('pdf_email_attachment') !== false) {
|
||||||
$this->setAttachments($invoice->pdf_file_path());
|
$this->setAttachments($invitation->pdf_file_path());
|
||||||
}
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class QuoteEmail extends EmailBuilder
|
|||||||
->setBody($body_template);
|
->setBody($body_template);
|
||||||
|
|
||||||
if ($client->getSetting('pdf_email_attachment') !== false) {
|
if ($client->getSetting('pdf_email_attachment') !== false) {
|
||||||
$this->attachments = $quote->pdf_file_path();
|
$this->attachments = $invitation->pdf_file_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -19,6 +19,7 @@ use App\Http\Requests\Request;
|
|||||||
use App\Jobs\Entity\ActionEntity;
|
use App\Jobs\Entity\ActionEntity;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Utils\Number;
|
use App\Utils\Number;
|
||||||
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use ZipStream\Option\Archive;
|
use ZipStream\Option\Archive;
|
||||||
@ -45,8 +46,11 @@ class InvoiceController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index(InvoiceFilters $filters)
|
public function index(InvoiceFilters $filters)
|
||||||
{
|
{
|
||||||
$invoices = auth()->user()->client->company->invoices()->paginate(10);
|
$client_id = auth('contact')->user()->client->id;
|
||||||
|
|
||||||
|
$invoices = Invoice::where('client_id', $client_id)->paginate(10);
|
||||||
|
|
||||||
|
// $invoices = Invoice::filter($filters);
|
||||||
return $this->render('invoices.index', ['invoices' => $invoices]);
|
return $this->render('invoices.index', ['invoices' => $invoices]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,10 +158,9 @@ class InvoiceController extends Controller
|
|||||||
|
|
||||||
//if only 1 pdf, output to buffer for download
|
//if only 1 pdf, output to buffer for download
|
||||||
if ($invoices->count() == 1) {
|
if ($invoices->count() == 1) {
|
||||||
return response()->download(public_path($invoices->first()->pdf_file_path()));
|
return response()->download(TempFile::path($invoices->first()->pdf_file_path()), basename($invoices->first()->pdf_file_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# enable output of HTTP headers
|
# enable output of HTTP headers
|
||||||
$options = new Archive();
|
$options = new Archive();
|
||||||
$options->setSendHttpHeaders(true);
|
$options->setSendHttpHeaders(true);
|
||||||
@ -166,7 +169,7 @@ class InvoiceController extends Controller
|
|||||||
$zip = new ZipStream(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.invoices')).".zip", $options);
|
$zip = new ZipStream(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.invoices')).".zip", $options);
|
||||||
|
|
||||||
foreach ($invoices as $invoice) {
|
foreach ($invoices as $invoice) {
|
||||||
$zip->addFileFromPath(basename($invoice->pdf_file_path()), public_path($invoice->pdf_file_path()));
|
$zip->addFileFromPath(basename($invoice->pdf_file_path()), TempFile::path($invoice->pdf_file_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
# finish the zip stream
|
# finish the zip stream
|
||||||
|
@ -7,6 +7,7 @@ use App\Http\Requests\ClientPortal\ProcessQuotesInBulkRequest;
|
|||||||
use App\Http\Requests\ClientPortal\ShowQuoteRequest;
|
use App\Http\Requests\ClientPortal\ShowQuoteRequest;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use ZipStream\Option\Archive;
|
use ZipStream\Option\Archive;
|
||||||
use ZipStream\ZipStream;
|
use ZipStream\ZipStream;
|
||||||
@ -70,7 +71,7 @@ class QuoteController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($quotes->count() == 1) {
|
if ($quotes->count() == 1) {
|
||||||
return response()->download(public_path($quotes->first()->pdf_file_path()));
|
return response()->download(TempFile::path($invoices->first()->pdf_file_path()), basename($quotes->first()->pdf_file_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
# enable output of HTTP headers
|
# enable output of HTTP headers
|
||||||
@ -81,7 +82,7 @@ class QuoteController extends Controller
|
|||||||
$zip = new ZipStream(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.invoices')) . ".zip", $options);
|
$zip = new ZipStream(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.invoices')) . ".zip", $options);
|
||||||
|
|
||||||
foreach ($quotes as $quote) {
|
foreach ($quotes as $quote) {
|
||||||
$zip->addFileFromPath(basename($quote->pdf_file_path()), public_path($quote->pdf_file_path()));
|
$zip->addFileFromPath(basename($quote->pdf_file_path()), TempFile::path($quote->pdf_file_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
# finish the zip stream
|
# finish the zip stream
|
||||||
|
@ -22,6 +22,7 @@ use App\Models\Client;
|
|||||||
use App\Models\Credit;
|
use App\Models\Credit;
|
||||||
use App\Repositories\CreditRepository;
|
use App\Repositories\CreditRepository;
|
||||||
use App\Transformers\CreditTransformer;
|
use App\Transformers\CreditTransformer;
|
||||||
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -526,8 +527,8 @@ class CreditController extends BaseController
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'download':
|
case 'download':
|
||||||
return response()->download(public_path($credit->pdf_file_path()));
|
return response()->download(TempFile::path($credit->pdf_file_path()), basename($credit->pdf_file_path()));
|
||||||
break;
|
break;
|
||||||
case 'archive':
|
case 'archive':
|
||||||
$this->credit_repository->archive($credit);
|
$this->credit_repository->archive($credit);
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ use App\Models\Invoice;
|
|||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
use App\Repositories\InvoiceRepository;
|
use App\Repositories\InvoiceRepository;
|
||||||
use App\Transformers\InvoiceTransformer;
|
use App\Transformers\InvoiceTransformer;
|
||||||
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
@ -659,7 +660,7 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'download':
|
case 'download':
|
||||||
return response()->download(public_path($invoice->pdf_file_path()));
|
return response()->download(TempFile::path($invoice->pdf_file_path()), basename($invoice->pdf_file_path()));
|
||||||
break;
|
break;
|
||||||
case 'archive':
|
case 'archive':
|
||||||
$this->invoice_repo->archive($invoice);
|
$this->invoice_repo->archive($invoice);
|
||||||
|
@ -31,6 +31,7 @@ use App\Models\Quote;
|
|||||||
use App\Repositories\QuoteRepository;
|
use App\Repositories\QuoteRepository;
|
||||||
use App\Transformers\InvoiceTransformer;
|
use App\Transformers\InvoiceTransformer;
|
||||||
use App\Transformers\QuoteTransformer;
|
use App\Transformers\QuoteTransformer;
|
||||||
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@ -657,7 +658,7 @@ class QuoteController extends BaseController
|
|||||||
# code...
|
# code...
|
||||||
break;
|
break;
|
||||||
case 'download':
|
case 'download':
|
||||||
return response()->download(public_path($quote->pdf_file_path()));
|
return response()->download(TempFile::path($quote->pdf_file_path()), basename($quote->pdf_file_path()));
|
||||||
break;
|
break;
|
||||||
case 'archive':
|
case 'archive':
|
||||||
$this->invoice_repo->archive($quote);
|
$this->invoice_repo->archive($quote);
|
||||||
|
@ -47,10 +47,11 @@ class QueryLogging
|
|||||||
$count = count($queries);
|
$count = count($queries);
|
||||||
$timeEnd = microtime(true);
|
$timeEnd = microtime(true);
|
||||||
$time = $timeEnd - $timeStart;
|
$time = $timeEnd - $timeStart;
|
||||||
// Log::info($request->method() . ' - ' . $request->url() . ": $count queries - " . $time);
|
|
||||||
|
Log::info($request->method() . ' - ' . $request->url() . ": $count queries - " . $time);
|
||||||
|
|
||||||
// if($count > 50)
|
if($count > 50)
|
||||||
// Log::info($queries);
|
Log::info($queries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ class CreateAccountRequest extends Request
|
|||||||
public function authorize()
|
public function authorize()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
//return ! auth()->user();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +23,8 @@ class ShowInvoiceRequest extends Request
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public function authorize() : bool
|
public function authorize() : bool
|
||||||
{
|
{info(auth('contact')->user()->client->id);
|
||||||
return auth()->user()->client->id === $this->invoice->client_id;
|
info($this->invoice->client_id);
|
||||||
|
return auth('contact')->user()->client->id === $this->invoice->client_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ use App\Models\ClientContact;
|
|||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Design;
|
use App\Models\Design;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Utils\HtmlEngine;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use App\Utils\Traits\MakesInvoiceHtml;
|
use App\Utils\Traits\MakesInvoiceHtml;
|
||||||
use App\Utils\Traits\NumberFormatter;
|
use App\Utils\Traits\NumberFormatter;
|
||||||
@ -44,32 +45,30 @@ class CreateCreditPdf implements ShouldQueue
|
|||||||
|
|
||||||
private $disk;
|
private $disk;
|
||||||
|
|
||||||
|
public $invitation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct($credit, Company $company, ClientContact $contact = null)
|
public function __construct($invitation)
|
||||||
{
|
{
|
||||||
$this->credit = $credit;
|
$this->invitation = $invitation;
|
||||||
|
|
||||||
$this->company = $company;
|
$this->credit = $invitation->credit;
|
||||||
|
|
||||||
$this->contact = $contact;
|
$this->company = $invitation->company;
|
||||||
|
|
||||||
|
$this->contact = $invitation->contact;
|
||||||
|
|
||||||
$this->disk = $disk ?? config('filesystems.default');
|
$this->disk = $disk ?? config('filesystems.default');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
MultiDB::setDB($this->company->db);
|
|
||||||
|
|
||||||
$this->credit->load('client');
|
$this->credit->load('client');
|
||||||
|
|
||||||
if (!$this->contact) {
|
|
||||||
$this->contact = $this->credit->client->primary_contact()->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
App::setLocale($this->contact->preferredLocale());
|
App::setLocale($this->contact->preferredLocale());
|
||||||
|
|
||||||
$path = $this->credit->client->credit_filepath();
|
$path = $this->credit->client->credit_filepath();
|
||||||
@ -80,11 +79,8 @@ class CreateCreditPdf implements ShouldQueue
|
|||||||
|
|
||||||
$designer = new Designer($this->credit, $design, $this->credit->client->getSetting('pdf_variables'), 'credit');
|
$designer = new Designer($this->credit, $design, $this->credit->client->getSetting('pdf_variables'), 'credit');
|
||||||
|
|
||||||
//get invoice design
|
$html = (new HtmlEngine($designer, $invitation, 'credit'))->build();
|
||||||
// $html = $this->generateInvoiceHtml($designer->build()->getHtml(), $this->credit, $this->contact);
|
|
||||||
$html = $this->generateEntityHtml($designer, $this->credit, $this->contact);
|
|
||||||
|
|
||||||
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
|
||||||
Storage::makeDirectory($path, 0755);
|
Storage::makeDirectory($path, 0755);
|
||||||
|
|
||||||
$pdf = $this->makePdf(null, null, $html);
|
$pdf = $this->makePdf(null, null, $html);
|
||||||
|
@ -19,6 +19,7 @@ use App\Models\ClientContact;
|
|||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Design;
|
use App\Models\Design;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Utils\HtmlEngine;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use App\Utils\Traits\MakesInvoiceHtml;
|
use App\Utils\Traits\MakesInvoiceHtml;
|
||||||
use App\Utils\Traits\NumberFormatter;
|
use App\Utils\Traits\NumberFormatter;
|
||||||
@ -44,30 +45,28 @@ class CreateInvoicePdf implements ShouldQueue
|
|||||||
|
|
||||||
private $disk;
|
private $disk;
|
||||||
|
|
||||||
|
public $invitation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct($invoice, Company $company, ClientContact $contact = null)
|
public function __construct($invitation)
|
||||||
{
|
{
|
||||||
$this->invoice = $invoice;
|
$this->invitation = $invitation;
|
||||||
|
|
||||||
$this->company = $company;
|
$this->invoice = $invitation->invoice;
|
||||||
|
|
||||||
$this->contact = $contact;
|
$this->company = $invitation->company;
|
||||||
|
|
||||||
|
$this->contact = $invitation->contact;
|
||||||
|
|
||||||
$this->disk = $disk ?? config('filesystems.default');
|
$this->disk = $disk ?? config('filesystems.default');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{info(print_r($this->invitation->contact,1));
|
||||||
$this->invoice->load('client');
|
|
||||||
|
|
||||||
if (!$this->contact) {
|
|
||||||
$this->contact = $this->invoice->client->primary_contact()->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
App::setLocale($this->contact->preferredLocale());
|
App::setLocale($this->contact->preferredLocale());
|
||||||
|
|
||||||
$path = $this->invoice->client->invoice_filepath();
|
$path = $this->invoice->client->invoice_filepath();
|
||||||
@ -78,8 +77,7 @@ class CreateInvoicePdf implements ShouldQueue
|
|||||||
|
|
||||||
$designer = new Designer($this->invoice, $design, $this->invoice->client->getSetting('pdf_variables'), 'invoice');
|
$designer = new Designer($this->invoice, $design, $this->invoice->client->getSetting('pdf_variables'), 'invoice');
|
||||||
|
|
||||||
//get invoice design
|
$html = (new HtmlEngine($designer, $this->invitation, 'invoice'))->build();
|
||||||
$html = $this->generateEntityHtml($designer, $this->invoice, $this->contact);
|
|
||||||
|
|
||||||
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
||||||
Storage::makeDirectory($path, 0755);
|
Storage::makeDirectory($path, 0755);
|
||||||
|
@ -16,6 +16,7 @@ use App\Libraries\MultiDB;
|
|||||||
use App\Mail\DownloadInvoices;
|
use App\Mail\DownloadInvoices;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Utils\TempFile;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
@ -72,7 +73,7 @@ class ZipInvoices implements ShouldQueue
|
|||||||
$zip = new ZipStream($file_name, $options);
|
$zip = new ZipStream($file_name, $options);
|
||||||
|
|
||||||
foreach ($this->invoices as $invoice) {
|
foreach ($this->invoices as $invoice) {
|
||||||
$zip->addFileFromPath(basename($invoice->pdf_file_path()), public_path($invoice->pdf_file_path()));
|
$zip->addFileFromPath(basename($invoice->pdf_file_path()), TempFile::path($invoice->pdf_file_path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$zip->finish();
|
$zip->finish();
|
||||||
|
@ -19,6 +19,7 @@ use App\Models\ClientContact;
|
|||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Design;
|
use App\Models\Design;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Utils\HtmlEngine;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use App\Utils\Traits\MakesInvoiceHtml;
|
use App\Utils\Traits\MakesInvoiceHtml;
|
||||||
use App\Utils\Traits\NumberFormatter;
|
use App\Utils\Traits\NumberFormatter;
|
||||||
@ -44,34 +45,30 @@ class CreateQuotePdf implements ShouldQueue
|
|||||||
|
|
||||||
private $disk;
|
private $disk;
|
||||||
|
|
||||||
|
public $invitation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct($quote, Company $company, ClientContact $contact = null)
|
public function __construct($invitation)
|
||||||
{
|
{
|
||||||
$this->quote = $quote;
|
$this->invitation = $invitation;
|
||||||
|
|
||||||
$this->company = $company;
|
$this->quote = $invitation->quote;
|
||||||
|
|
||||||
$this->contact = $contact;
|
$this->company = $invitation->company;
|
||||||
|
|
||||||
|
$this->contact = $invitation->contact;
|
||||||
|
|
||||||
$this->disk = $disk ?? config('filesystems.default');
|
$this->disk = $disk ?? config('filesystems.default');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
MultiDB::setDB($this->company->db);
|
|
||||||
|
|
||||||
$settings = $this->quote->client->getMergedSettings();
|
|
||||||
|
|
||||||
$this->quote->load('client');
|
$this->quote->load('client');
|
||||||
|
|
||||||
if (!$this->contact) {
|
|
||||||
$this->contact = $this->quote->client->primary_contact()->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
App::setLocale($this->contact->preferredLocale());
|
App::setLocale($this->contact->preferredLocale());
|
||||||
|
|
||||||
$path = $this->quote->client->quote_filepath();
|
$path = $this->quote->client->quote_filepath();
|
||||||
@ -82,20 +79,12 @@ class CreateQuotePdf implements ShouldQueue
|
|||||||
|
|
||||||
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
|
||||||
Storage::makeDirectory($path, 0755);
|
Storage::makeDirectory($path, 0755);
|
||||||
|
|
||||||
$quote_number = $this->quote->number;
|
|
||||||
|
|
||||||
//$start = microtime(true);
|
$html = (new HtmlEngine($designer, $this->invitation, 'quote'))->build();
|
||||||
|
|
||||||
$design_body = $designer->build()->getHtml();
|
|
||||||
|
|
||||||
$html = $this->generateEntityHtml($designer, $this->quote, $this->contact);
|
|
||||||
|
|
||||||
$pdf = $this->makePdf(null, null, $html);
|
$pdf = $this->makePdf(null, null, $html);
|
||||||
|
|
||||||
//\Log::error("PDF Build time = ". (microtime(true) - $start));
|
$file_path = $path . $this->quote->number . '.pdf';
|
||||||
|
|
||||||
$file_path = $path . $quote_number . '.pdf';
|
|
||||||
|
|
||||||
$instance = Storage::disk($this->disk)->put($file_path, $pdf);
|
$instance = Storage::disk($this->disk)->put($file_path, $pdf);
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class UploadFile implements ShouldQueue
|
|||||||
|
|
||||||
public $entity;
|
public $entity;
|
||||||
|
|
||||||
public function __construct($file, $type, $user, $company, $entity, $disk = 'public')
|
public function __construct($file, $type, $user, $company, $entity, $disk = null)
|
||||||
{
|
{
|
||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
$this->type = $type;
|
$this->type = $type;
|
||||||
|
@ -34,8 +34,8 @@ class DeleteCompanyDocuments
|
|||||||
// Remove all files & folders, under company's path.
|
// Remove all files & folders, under company's path.
|
||||||
// This will delete directory itself, as well.
|
// This will delete directory itself, as well.
|
||||||
// In case we want to remove the content of folder, we should use $fs->cleanDirectory();
|
// In case we want to remove the content of folder, we should use $fs->cleanDirectory();
|
||||||
$filesystem = new Filesystem();
|
//$filesystem = new Filesystem();
|
||||||
$filesystem->deleteDirectory($path);
|
Storage::deleteDirectory($event->company->company_key);
|
||||||
|
|
||||||
Document::whereCompanyId($event->company->id)->delete();
|
Document::whereCompanyId($event->company->id)->delete();
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ class TemplateEmail extends Mailable
|
|||||||
'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' => $this->build_email->getSubject(),
|
'title' => $this->build_email->getSubject(),
|
||||||
|
'signature' => $settings->email_signature,
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
'company' => $company
|
'company' => $company
|
||||||
]);
|
]);
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Events\Credit\CreditWasUpdated;
|
||||||
use App\Helpers\Invoice\InvoiceSum;
|
use App\Helpers\Invoice\InvoiceSum;
|
||||||
use App\Helpers\Invoice\InvoiceSumInclusive;
|
use App\Helpers\Invoice\InvoiceSumInclusive;
|
||||||
use App\Jobs\Credit\CreateCreditPdf;
|
use App\Jobs\Credit\CreateCreditPdf;
|
||||||
@ -218,15 +219,18 @@ class Credit extends BaseModel
|
|||||||
|
|
||||||
public function pdf_file_path($invitation = null)
|
public function pdf_file_path($invitation = null)
|
||||||
{
|
{
|
||||||
$storage_path = 'storage/' . $this->client->credit_filepath() . $this->number . '.pdf';
|
|
||||||
|
|
||||||
if (Storage::exists($storage_path)) {
|
$storage_path = Storage::url($this->client->credit_filepath() . $this->number . '.pdf');
|
||||||
|
|
||||||
|
if (Storage::exists($this->client->credit_filepath() . $this->number . '.pdf')) {
|
||||||
return $storage_path;
|
return $storage_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$invitation) {
|
if (!$invitation) {
|
||||||
|
event(new CreditWasUpdated($this, $this->company));
|
||||||
CreateCreditPdf::dispatchNow($this, $this->company, $this->client->primary_contact()->first());
|
CreateCreditPdf::dispatchNow($this, $this->company, $this->client->primary_contact()->first());
|
||||||
} else {
|
} else {
|
||||||
|
event(new CreditWasUpdated($this, $this->company));
|
||||||
CreateCreditPdf::dispatchNow($invitation->credit, $invitation->company, $invitation->contact);
|
CreateCreditPdf::dispatchNow($invitation->credit, $invitation->company, $invitation->contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,12 +11,15 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Events\Credit\CreditWasUpdated;
|
||||||
|
use App\Jobs\Credit\CreateCreditPdf;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Utils\Traits\Inviteable;
|
use App\Utils\Traits\Inviteable;
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class CreditInvitation extends BaseModel
|
class CreditInvitation extends BaseModel
|
||||||
{
|
{
|
||||||
@ -112,4 +115,16 @@ class CreditInvitation extends BaseModel
|
|||||||
$this->viewed_date = Carbon::now();
|
$this->viewed_date = Carbon::now();
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function pdf_file_path()
|
||||||
|
{
|
||||||
|
$storage_path = Storage::url($this->credit->client->quote_filepath() . $this->credit->number . '.pdf');
|
||||||
|
|
||||||
|
if (!Storage::exists($this->credit->client->credit_filepath() . $this->credit->number . '.pdf')) {
|
||||||
|
event(new CreditWasUpdated($this, $this->company));
|
||||||
|
CreateCreditPdf::dispatchNow($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $storage_path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,6 +195,16 @@ class Invoice extends BaseModel
|
|||||||
return $this->morphMany(CompanyLedger::class, 'company_ledgerable');
|
return $this->morphMany(CompanyLedger::class, 'company_ledgerable');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function activities()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Activity::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function history()
|
||||||
|
{
|
||||||
|
$this->activities->with('backup');
|
||||||
|
}
|
||||||
|
|
||||||
// public function credits()
|
// public function credits()
|
||||||
// {
|
// {
|
||||||
// return $this->belongsToMany(Credit::class)->using(Paymentable::class)->withPivot(
|
// return $this->belongsToMany(Credit::class)->using(Paymentable::class)->withPivot(
|
||||||
@ -356,21 +366,6 @@ class Invoice extends BaseModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
{
|
|
||||||
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'));
|
|
||||||
} else {
|
|
||||||
return File::get(resource_path('views/pdf/design1.blade.php'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access the invoice calculator object
|
* Access the invoice calculator object
|
||||||
*
|
*
|
||||||
@ -389,34 +384,16 @@ class Invoice extends BaseModel
|
|||||||
return $invoice_calc->build();
|
return $invoice_calc->build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** TODO// DOCUMENT THIS FUNCTIONALITY */
|
public function pdf_file_path($invitation = null)
|
||||||
public function pdf_url()
|
|
||||||
{
|
{
|
||||||
// $public_path = 'storage/' . $this->client->invoice_filepath() . $this->number . '.pdf';
|
if(!$invitation)
|
||||||
|
$invitation = $this->invitations->first();
|
||||||
|
|
||||||
// $storage_path = 'public/' . $this->client->invoice_filepath() . $this->number . '.pdf';
|
$storage_path = Storage::url($this->client->invoice_filepath() . $this->number . '.pdf');
|
||||||
|
|
||||||
$public_path = $this->client->invoice_filepath() . $this->number . '.pdf';
|
if (!Storage::exists($this->client->invoice_filepath() . $this->number . '.pdf')) {
|
||||||
|
|
||||||
$storage_path = 'storage/' . $this->client->invoice_filepath() . $this->number . '.pdf';
|
|
||||||
|
|
||||||
$disk = config('filesystems.default');
|
|
||||||
|
|
||||||
if (!Storage::disk($disk)->exists($public_path)) {
|
|
||||||
event(new InvoiceWasUpdated($this, $this->company));
|
event(new InvoiceWasUpdated($this, $this->company));
|
||||||
CreateInvoicePdf::dispatch($this, $this->company, $this->client->primary_contact()->first());
|
CreateInvoicePdf::dispatchNow($invitation);
|
||||||
}
|
|
||||||
|
|
||||||
return $storage_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function pdf_file_path()
|
|
||||||
{
|
|
||||||
$storage_path = 'storage/' . $this->client->invoice_filepath() . $this->number . '.pdf';
|
|
||||||
|
|
||||||
|
|
||||||
if (!Storage::exists($storage_path)) {
|
|
||||||
CreateInvoicePdf::dispatchNow($this, $this->company, $this->client->primary_contact()->first());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $storage_path;
|
return $storage_path;
|
||||||
|
@ -11,12 +11,14 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Events\Invoice\InvoiceWasUpdated;
|
||||||
|
use App\Jobs\Invoice\CreateInvoicePdf;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Utils\Traits\Inviteable;
|
use App\Utils\Traits\Inviteable;
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class InvoiceInvitation extends BaseModel
|
class InvoiceInvitation extends BaseModel
|
||||||
{
|
{
|
||||||
@ -122,4 +124,17 @@ class InvoiceInvitation extends BaseModel
|
|||||||
$this->viewed_date = Carbon::now();
|
$this->viewed_date = Carbon::now();
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function pdf_file_path()
|
||||||
|
{
|
||||||
|
$storage_path = Storage::url($this->invoice->client->invoice_filepath() . $this->invoice->number . '.pdf');
|
||||||
|
|
||||||
|
if (!Storage::exists($this->invoice->client->invoice_filepath() . $this->invoice->number . '.pdf')) {
|
||||||
|
event(new InvoiceWasUpdated($this->invoice, $this->company));
|
||||||
|
CreateInvoicePdf::dispatchNow($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $storage_path;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Events\Quote\QuoteWasUpdated;
|
||||||
use App\Helpers\Invoice\InvoiceSum;
|
use App\Helpers\Invoice\InvoiceSum;
|
||||||
use App\Helpers\Invoice\InvoiceSumInclusive;
|
use App\Helpers\Invoice\InvoiceSumInclusive;
|
||||||
use App\Jobs\Invoice\CreateInvoicePdf;
|
use App\Jobs\Invoice\CreateInvoicePdf;
|
||||||
@ -177,17 +178,18 @@ class Quote extends BaseModel
|
|||||||
|
|
||||||
public function pdf_file_path($invitation = null)
|
public function pdf_file_path($invitation = null)
|
||||||
{
|
{
|
||||||
$storage_path = 'storage/' . $this->client->quote_filepath() . $this->number . '.pdf';
|
if(!$invitation)
|
||||||
|
$invitation = $this->invitations->where('client_contact_id', $this->client->primary_contact()->first()->id)->first();
|
||||||
|
|
||||||
if (Storage::exists($storage_path)) {
|
$storage_path = Storage::url($this->client->quote_filepath() . $this->number . '.pdf');
|
||||||
|
|
||||||
|
if (Storage::exists($this->client->quote_filepath() . $this->number . '.pdf')) {
|
||||||
return $storage_path;
|
return $storage_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$invitation) {
|
event(new QuoteWasUpdated($this, $this->company));
|
||||||
CreateQuotePdf::dispatchNow($this, $this->company, $this->client->primary_contact()->first());
|
|
||||||
} else {
|
CreateQuotePdf::dispatchNow($invitation);
|
||||||
CreateQuotePdf::dispatchNow($invitation->quote, $invitation->company, $invitation->contact);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $storage_path;
|
return $storage_path;
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,14 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Events\Quote\QuoteWasUpdated;
|
||||||
|
use App\Jobs\Quote\CreateQuotePdf;
|
||||||
use App\Models\Quote;
|
use App\Models\Quote;
|
||||||
use App\Utils\Traits\Inviteable;
|
use App\Utils\Traits\Inviteable;
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class QuoteInvitation extends BaseModel
|
class QuoteInvitation extends BaseModel
|
||||||
{
|
{
|
||||||
@ -110,4 +113,16 @@ class QuoteInvitation extends BaseModel
|
|||||||
$this->viewed_date = Carbon::now();
|
$this->viewed_date = Carbon::now();
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function pdf_file_path()
|
||||||
|
{
|
||||||
|
$storage_path = Storage::url($this->quote->client->quote_filepath() . $this->quote->number . '.pdf');
|
||||||
|
|
||||||
|
if (!Storage::exists($this->quote->client->quote_filepath() . $this->quote->number . '.pdf')) {
|
||||||
|
event(new QuoteWasUpdated($this, $this->company));
|
||||||
|
CreateQuotePdf::dispatchNow($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $storage_path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Notifications;
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use App\Utils\TempFile;
|
||||||
use App\Utils\Traits\MakesInvoiceHtml;
|
use App\Utils\Traits\MakesInvoiceHtml;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@ -74,11 +75,11 @@ class BaseNotification extends Notification implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->settings->pdf_email_attachment) {
|
if ($this->settings->pdf_email_attachment) {
|
||||||
$mail_message->attach(public_path($this->entity->pdf_file_path()));
|
$mail_message->attach(TempFile::path($this->invitation->pdf_file_path()), ['as' => basename($this->invitation->pdf_file_path())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->entity->documents as $document) {
|
foreach ($this->entity->documents as $document) {
|
||||||
$mail_message->attach($document->generateUrl(), ['as' => $document->name]);
|
$mail_message->attach(TempFile::path($document->generateUrl()), ['as' => $document->name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->entity instanceof Invoice && $this->settings->ubl_email_attachment) {
|
if ($this->entity instanceof Invoice && $this->settings->ubl_email_attachment) {
|
||||||
@ -98,7 +99,6 @@ class BaseNotification extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
if ($design_style == 'custom') {
|
if ($design_style == 'custom') {
|
||||||
$email_style_custom = $this->settings->email_style_custom;
|
$email_style_custom = $this->settings->email_style_custom;
|
||||||
//$body = str_replace("$body", $body, $email_style_custom);
|
|
||||||
$body = strtr($email_style_custom, "$body", $body);
|
$body = strtr($email_style_custom, "$body", $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,11 +109,13 @@ class BaseNotification extends Notification implements ShouldQueue
|
|||||||
'title' => '',
|
'title' => '',
|
||||||
'settings' => '',
|
'settings' => '',
|
||||||
'company' => '',
|
'company' => '',
|
||||||
|
'view_link' => $this->invitation->getLink(),
|
||||||
|
'view_text' => ctrans('texts.view_'.$this->entity_string),
|
||||||
'logo' => $this->entity->company->present()->logo(),
|
'logo' => $this->entity->company->present()->logo(),
|
||||||
'signature' => '',
|
'signature' => $this->settings->email_signature,
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -50,6 +50,8 @@ class SendGenericNotification extends BaseNotification implements ShouldQueue
|
|||||||
$this->settings = $this->entity->client->getMergedSettings();
|
$this->settings = $this->entity->client->getMergedSettings();
|
||||||
$this->subject = $subject;
|
$this->subject = $subject;
|
||||||
$this->body = $body;
|
$this->body = $body;
|
||||||
|
$this->invitation = $invitation;
|
||||||
|
$this->entity_string = $entity_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,6 +32,8 @@ class GetInvoicePdf extends AbstractService
|
|||||||
$this->contact = $this->invoice->client->primary_contact()->first();
|
$this->contact = $this->invoice->client->primary_contact()->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$invitation = $this->invoice->invitations->where('client_contact_id', $this->contact->id)->first();
|
||||||
|
|
||||||
$path = $this->invoice->client->invoice_filepath();
|
$path = $this->invoice->client->invoice_filepath();
|
||||||
|
|
||||||
$file_path = $path . $this->invoice->number . '.pdf';
|
$file_path = $path . $this->invoice->number . '.pdf';
|
||||||
@ -41,11 +43,9 @@ class GetInvoicePdf extends AbstractService
|
|||||||
$file = Storage::disk($disk)->exists($file_path);
|
$file = Storage::disk($disk)->exists($file_path);
|
||||||
|
|
||||||
if (!$file) {
|
if (!$file) {
|
||||||
$file_path = CreateInvoicePdf::dispatchNow($this->invoice, $this->invoice->company, $this->contact);
|
$file_path = CreateInvoicePdf::dispatchNow($invitation);
|
||||||
}
|
}
|
||||||
|
|
||||||
//return $file_path;
|
|
||||||
|
|
||||||
return Storage::disk($disk)->path($file_path);
|
return Storage::disk($disk)->path($file_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,9 +105,7 @@ class InvoiceService
|
|||||||
|
|
||||||
public function getInvoicePdf($contact)
|
public function getInvoicePdf($contact)
|
||||||
{
|
{
|
||||||
$get_invoice_pdf = new GetInvoicePdf($this->invoice, $contact);
|
return (new GetInvoicePdf($this->invoice, $contact))->run();
|
||||||
|
|
||||||
return $get_invoice_pdf->run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendEmail($contact)
|
public function sendEmail($contact)
|
||||||
|
@ -22,7 +22,7 @@ class MarkSent
|
|||||||
|
|
||||||
/* Return immediately if status is not draft */
|
/* Return immediately if status is not draft */
|
||||||
if ($this->quote->status_id != Quote::STATUS_DRAFT) {
|
if ($this->quote->status_id != Quote::STATUS_DRAFT) {
|
||||||
return $quote;
|
return $this->quote;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->quote->markInvitationsSent();
|
$this->quote->markInvitationsSent();
|
||||||
|
603
app/Utils/HtmlEngine.php
Normal file
603
app/Utils/HtmlEngine.php
Normal file
@ -0,0 +1,603 @@
|
|||||||
|
<?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\Utils;
|
||||||
|
|
||||||
|
use App\Designs\Designer;
|
||||||
|
use App\Models\Country;
|
||||||
|
use App\Utils\Number;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
|
||||||
|
class HtmlEngine
|
||||||
|
{
|
||||||
|
|
||||||
|
public $entity;
|
||||||
|
|
||||||
|
public $invitation;
|
||||||
|
|
||||||
|
public $client;
|
||||||
|
|
||||||
|
public $contact;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $designer;
|
||||||
|
|
||||||
|
public $settings;
|
||||||
|
|
||||||
|
public $entity_calc;
|
||||||
|
|
||||||
|
public $entity_string;
|
||||||
|
|
||||||
|
public function __construct(Designer $designer, $invitation, $entity_string)
|
||||||
|
{
|
||||||
|
$this->designer = $designer;
|
||||||
|
|
||||||
|
$this->invitation = $invitation;
|
||||||
|
|
||||||
|
$this->entity = $invitation->{$entity_string};
|
||||||
|
|
||||||
|
$this->company = $invitation->company;
|
||||||
|
|
||||||
|
$this->contact = $invitation->contact;
|
||||||
|
|
||||||
|
$this->client = $this->entity->client;
|
||||||
|
|
||||||
|
$this->settings = $this->client->getMergedSettings();
|
||||||
|
|
||||||
|
$this->entity_calc = $this->entity->calc();
|
||||||
|
|
||||||
|
$this->entity_string = $entity_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function build() :string
|
||||||
|
{
|
||||||
|
|
||||||
|
App::setLocale($this->client->preferredLocale());
|
||||||
|
|
||||||
|
$values_and_labels = $this->generateLabelsAndValues();
|
||||||
|
|
||||||
|
$this->designer->build();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
$data['entity'] = $this->entity;
|
||||||
|
$data['lang'] = $this->client->preferredLocale();
|
||||||
|
$data['includes'] = $this->designer->getIncludes();
|
||||||
|
$data['header'] = $this->designer->getHeader();
|
||||||
|
$data['body'] = $this->designer->getBody();
|
||||||
|
$data['footer'] = $this->designer->getFooter();
|
||||||
|
|
||||||
|
$html = view('pdf.stub', $data)->render();
|
||||||
|
|
||||||
|
$html = $this->parseLabelsAndValues($values_and_labels['labels'], $values_and_labels['values'], $html);
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
private function buildEntityDataArray() :array
|
||||||
|
{
|
||||||
|
if (!$this->client->currency()) {
|
||||||
|
throw new \Exception(debug_backtrace()[1]['function'], 1);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
$data['$tax'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$app_url'] = ['value' => $this->generateAppUrl(), 'label' => ''];
|
||||||
|
$data['$from'] = ['value' => '', 'label' => ctrans('texts.from')];
|
||||||
|
$data['$to'] = ['value' => '', 'label' => ctrans('texts.to')];
|
||||||
|
$data['$total_tax_labels'] = ['value' => $this->totalTaxLabels(), 'label' => ctrans('texts.taxes')];
|
||||||
|
$data['$total_tax_values'] = ['value' => $this->totalTaxValues(), 'label' => ctrans('texts.taxes')];
|
||||||
|
$data['$line_tax_labels'] = ['value' => $this->lineTaxLabels(), 'label' => ctrans('texts.taxes')];
|
||||||
|
$data['$line_tax_values'] = ['value' => $this->lineTaxValues(), 'label' => ctrans('texts.taxes')];
|
||||||
|
$data['$date'] = ['value' => $this->entity->date ?: ' ', 'label' => ctrans('texts.date')];
|
||||||
|
//$data['$invoice_date'] = ['value' => $this->date ?: ' ', 'label' => ctrans('texts.invoice_date')];
|
||||||
|
$data['$invoice.date'] = &$data['$date'];
|
||||||
|
$data['$invoice.due_date'] = ['value' => $this->entity->due_date ?: ' ', 'label' => ctrans('texts.due_date')];
|
||||||
|
$data['$due_date'] = &$data['$invoice.due_date'];
|
||||||
|
$data['$invoice.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')];
|
||||||
|
$data['$invoice.po_number'] = ['value' => $this->entity->po_number ?: ' ', 'label' => ctrans('texts.po_number')];
|
||||||
|
$data['$line_taxes'] = ['value' => $this->makeLineTaxes() ?: ' ', 'label' => ctrans('texts.taxes')];
|
||||||
|
$data['$invoice.line_taxes'] = &$data['$line_taxes'];
|
||||||
|
$data['$total_taxes'] = ['value' => $this->makeTotalTaxes() ?: ' ', 'label' => ctrans('texts.taxes')];
|
||||||
|
$data['$invoice.total_taxes'] = &$data['$total_taxes'];
|
||||||
|
|
||||||
|
if ($this->entity_string == 'invoice') {
|
||||||
|
$data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.invoice')];
|
||||||
|
$data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.invoice_number')];
|
||||||
|
$data['$entity.terms'] = ['value' => $this->entity->terms ?: ' ', 'label' => ctrans('texts.invoice_terms')];
|
||||||
|
$data['$terms'] = &$data['$entity.terms'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->entity_string == 'quote') {
|
||||||
|
$data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.quote')];
|
||||||
|
$data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.quote_number')];
|
||||||
|
$data['$entity.terms'] = ['value' => $this->entity->terms ?: ' ', 'label' => ctrans('texts.quote_terms')];
|
||||||
|
$data['$terms'] = &$data['$entity.terms'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->entity_string == 'credit') {
|
||||||
|
$data['$entity_label'] = ['value' => '', 'label' => ctrans('texts.credit')];
|
||||||
|
$data['$number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.credit_number')];
|
||||||
|
$data['$entity.terms'] = ['value' => $this->entity->terms ?: ' ', 'label' => ctrans('texts.credit_terms')];
|
||||||
|
$data['$terms'] = &$data['$entity.terms'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['$entity_number'] = &$data['$number'];
|
||||||
|
|
||||||
|
//$data['$paid_to_date'] = ;
|
||||||
|
$data['$invoice.discount'] = ['value' => Number::formatMoney($this->entity_calc->getTotalDiscount(), $this->client) ?: ' ', 'label' => ctrans('texts.discount')];
|
||||||
|
$data['$discount'] = &$data['$invoice.discount'];
|
||||||
|
$data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.subtotal')];
|
||||||
|
$data['$invoice.subtotal'] = &$data['$subtotal'];
|
||||||
|
$data['$invoice.balance_due'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: ' ', 'label' => ctrans('texts.balance_due')];
|
||||||
|
$data['$quote.balance_due'] = &$data['$invoice.balance_due'];
|
||||||
|
$data['$balance_due'] = &$data['$invoice.balance_due'];
|
||||||
|
$data['$invoice.partial_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
||||||
|
$data['$total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.total')];
|
||||||
|
$data['$amount'] = &$data['$total'];
|
||||||
|
$data['$quote.total'] = &$data['$total'];
|
||||||
|
$data['$invoice.total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.invoice_total')];
|
||||||
|
$data['$invoice.amount'] = &$data['$total'];
|
||||||
|
$data['$quote.amount'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.quote_total')];
|
||||||
|
$data['$credit.total'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_total')];
|
||||||
|
$data['$credit.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.credit_number')];
|
||||||
|
$data['$credit.amount'] = &$data['$credit.total'];
|
||||||
|
$data['$credit.po_number'] = &$data['$invoice.po_number'];
|
||||||
|
$data['$credit.date'] = ['value' => $this->entity->date, 'label' => ctrans('texts.credit_date')];
|
||||||
|
$data['$balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.balance')];
|
||||||
|
$data['$credit.balance'] = &$data['$balance'];
|
||||||
|
|
||||||
|
$data['$invoice.balance'] = &$data['$balance'];
|
||||||
|
$data['$taxes'] = ['value' => Number::formatMoney($this->entity_calc->getItemTotalTaxes(), $this->client) ?: ' ', 'label' => ctrans('texts.taxes')];
|
||||||
|
$data['$invoice.taxes'] = &$data['$taxes'];
|
||||||
|
|
||||||
|
$data['$invoice.custom1'] = ['value' => $this->entity->custom_value1 ?: ' ', 'label' => $this->makeCustomField('invoice1')];
|
||||||
|
$data['$invoice.custom2'] = ['value' => $this->entity->custom_value2 ?: ' ', 'label' => $this->makeCustomField('invoice2')];
|
||||||
|
$data['$invoice.custom3'] = ['value' => $this->entity->custom_value3 ?: ' ', 'label' => $this->makeCustomField('invoice3')];
|
||||||
|
$data['$invoice.custom4'] = ['value' => $this->entity->custom_value4 ?: ' ', 'label' => $this->makeCustomField('invoice4')];
|
||||||
|
$data['$invoice.public_notes'] = ['value' => $this->entity->public_notes ?: ' ', 'label' => ctrans('texts.public_notes')];
|
||||||
|
$data['$entity.public_notes'] = &$data['$invoice.public_notes'];
|
||||||
|
|
||||||
|
// $data['$your_invoice'] = ;
|
||||||
|
// $data['$quote'] = ;
|
||||||
|
// $data['$your_quote'] = ;
|
||||||
|
//
|
||||||
|
$data['$quote.date'] = ['value' => $this->entity->date ?: ' ', 'label' => ctrans('texts.quote_date')];
|
||||||
|
$data['$quote.number'] = ['value' => $this->entity->number ?: ' ', 'label' => ctrans('texts.quote_number')];
|
||||||
|
$data['$quote.po_number'] = &$data['$invoice.po_number'];
|
||||||
|
$data['$quote.quote_number'] = &$data['$quote.number'];
|
||||||
|
$data['$quote_no'] = &$data['$quote.number'];
|
||||||
|
$data['$quote.quote_no'] = &$data['$quote.number'];
|
||||||
|
$data['$quote.valid_until'] = ['value' => $this->entity->due_date, 'label' => ctrans('texts.valid_until')];
|
||||||
|
$data['$credit_amount'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_amount')];
|
||||||
|
$data['$credit_balance'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: ' ', 'label' => ctrans('texts.credit_balance')];
|
||||||
|
;
|
||||||
|
$data['$credit_number'] = &$data['$number'];
|
||||||
|
$data['$credit_no'] = &$data['$number'];
|
||||||
|
$data['$credit.credit_no'] = &$data['$number'];
|
||||||
|
|
||||||
|
// $data['$invoice_issued_to'] = ;
|
||||||
|
// $data['$quote_issued_to'] = ;
|
||||||
|
// $data['$rate'] = ;
|
||||||
|
// $data['$hours'] = ;
|
||||||
|
// $data['$from'] = ;
|
||||||
|
// $data['$to'] = ;
|
||||||
|
// $data['$invoice_to'] = ;
|
||||||
|
// $data['$quote_to'] = ;
|
||||||
|
// $data['$details'] = ;
|
||||||
|
$data['$invoice_no'] = &$data['$number'];
|
||||||
|
$data['$invoice.invoice_no'] = &$data['$number'];
|
||||||
|
$data['$client1'] = ['value' => $this->client->custom_value1 ?: ' ', 'label' => $this->makeCustomField('client1')];
|
||||||
|
$data['$client2'] = ['value' => $this->client->custom_value2 ?: ' ', 'label' => $this->makeCustomField('client2')];
|
||||||
|
$data['$client3'] = ['value' => $this->client->custom_value3 ?: ' ', 'label' => $this->makeCustomField('client3')];
|
||||||
|
$data['$client4'] = ['value' => $this->client->custom_value4 ?: ' ', 'label' => $this->makeCustomField('client4')];
|
||||||
|
$data['$address1'] = ['value' => $this->client->address1 ?: ' ', 'label' => ctrans('texts.address1')];
|
||||||
|
$data['$address2'] = ['value' => $this->client->address2 ?: ' ', 'label' => ctrans('texts.address2')];
|
||||||
|
$data['$id_number'] = ['value' => $this->client->id_number ?: ' ', 'label' => ctrans('texts.id_number')];
|
||||||
|
$data['$vat_number'] = ['value' => $this->client->vat_number ?: ' ', 'label' => ctrans('texts.vat_number')];
|
||||||
|
$data['$website'] = ['value' => $this->client->present()->website() ?: ' ', 'label' => ctrans('texts.website')];
|
||||||
|
$data['$phone'] = ['value' => $this->client->present()->phone() ?: ' ', 'label' => ctrans('texts.phone')];
|
||||||
|
$data['$country'] = ['value' => isset($this->client->country->name) ? $this->client->country->name : 'No Country Set', 'label' => ctrans('texts.country')];
|
||||||
|
$data['$email'] = ['value' => isset($this->contact) ? $this->contact->email : 'no contact email on record', 'label' => ctrans('texts.email')];
|
||||||
|
$data['$client_name'] = ['value' => $this->entity->present()->clientName() ?: ' ', 'label' => ctrans('texts.client_name')];
|
||||||
|
$data['$client.name'] = &$data['$client_name'];
|
||||||
|
$data['$client.address1'] = &$data['$address1'];
|
||||||
|
$data['$client.address2'] = &$data['$address2'];
|
||||||
|
$data['$client_address'] = ['value' => $this->entity->present()->address() ?: ' ', 'label' => ctrans('texts.address')];
|
||||||
|
$data['$client.address'] = &$data['$client_address'];
|
||||||
|
$data['$client.id_number'] = &$data['$id_number'];
|
||||||
|
$data['$client.vat_number'] = &$data['$vat_number'];
|
||||||
|
$data['$client.website'] = &$data['$website'];
|
||||||
|
$data['$client.phone'] = &$data['$phone'];
|
||||||
|
$data['$city_state_postal'] = ['value' => $this->entity->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')];
|
||||||
|
$data['$client.city_state_postal'] = &$data['$city_state_postal'];
|
||||||
|
$data['$postal_city_state'] = ['value' => $this->entity->present()->cityStateZip($this->client->city, $this->client->state, $this->client->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')];
|
||||||
|
$data['$client.postal_city_state'] = &$data['$postal_city_state'];
|
||||||
|
$data['$client.country'] = &$data['$country'];
|
||||||
|
$data['$client.email'] = &$data['$email'];
|
||||||
|
|
||||||
|
|
||||||
|
$data['$contact.full_name'] = ['value' => $this->contact->present()->name(), 'label' => ctrans('texts.name')];
|
||||||
|
$data['$contact.email'] = ['value' => $this->contact->email, 'label' => ctrans('texts.email')];
|
||||||
|
$data['$contact.phone'] = ['value' => $this->contact->phone, 'label' => ctrans('texts.phone')];
|
||||||
|
|
||||||
|
$data['$contact.name'] = ['value' => isset($this->contact) ? $this->contact->present()->name() : 'no contact name on record', 'label' => ctrans('texts.contact_name')];
|
||||||
|
$data['$contact.custom1'] = ['value' => isset($this->contact) ? $this->contact->custom_value1 : ' ', 'label' => $this->makeCustomField('contact1')];
|
||||||
|
$data['$contact.custom2'] = ['value' => isset($this->contact) ? $this->contact->custom_value2 : ' ', 'label' => $this->makeCustomField('contact1')];
|
||||||
|
$data['$contact.custom3'] = ['value' => isset($this->contact) ? $this->contact->custom_value3 : ' ', 'label' => $this->makeCustomField('contact1')];
|
||||||
|
$data['$contact.custom4'] = ['value' => isset($this->contact) ? $this->contact->custom_value4 : ' ', 'label' => $this->makeCustomField('contact1')];
|
||||||
|
|
||||||
|
$data['$company.city_state_postal'] = ['value' => $this->company->present()->cityStateZip($this->settings->city, $this->settings->state, $this->settings->postal_code, false) ?: ' ', 'label' => ctrans('texts.city_state_postal')];
|
||||||
|
$data['$company.postal_city_state'] = ['value' => $this->company->present()->cityStateZip($this->settings->city, $this->settings->state, $this->settings->postal_code, true) ?: ' ', 'label' => ctrans('texts.postal_city_state')];
|
||||||
|
$data['$company.name'] = ['value' => $this->company->present()->name() ?: ' ', 'label' => ctrans('texts.company_name')];
|
||||||
|
$data['$company.address1'] = ['value' => $this->settings->address1 ?: ' ', 'label' => ctrans('texts.address1')];
|
||||||
|
$data['$company.address2'] = ['value' => $this->settings->address2 ?: ' ', 'label' => ctrans('texts.address2')];
|
||||||
|
$data['$company.city'] = ['value' => $this->settings->city ?: ' ', 'label' => ctrans('texts.city')];
|
||||||
|
$data['$company.state'] = ['value' => $this->settings->state ?: ' ', 'label' => ctrans('texts.state')];
|
||||||
|
$data['$company.postal_code'] = ['value' => $this->settings->postal_code ?: ' ', 'label' => ctrans('texts.postal_code')];
|
||||||
|
$data['$company.country'] = ['value' => $this->getCountryName(), 'label' => ctrans('texts.country')];
|
||||||
|
$data['$company.phone'] = ['value' => $this->settings->phone ?: ' ', 'label' => ctrans('texts.phone')];
|
||||||
|
$data['$company.email'] = ['value' => $this->settings->email ?: ' ', 'label' => ctrans('texts.email')];
|
||||||
|
$data['$company.vat_number'] = ['value' => $this->settings->vat_number ?: ' ', 'label' => ctrans('texts.vat_number')];
|
||||||
|
$data['$company.id_number'] = ['value' => $this->settings->id_number ?: ' ', 'label' => ctrans('texts.id_number')];
|
||||||
|
$data['$company.website'] = ['value' => $this->settings->website ?: ' ', 'label' => ctrans('texts.website')];
|
||||||
|
$data['$company.address'] = ['value' => $this->company->present()->address($this->settings) ?: ' ', 'label' => ctrans('texts.address')];
|
||||||
|
|
||||||
|
$logo = $this->company->present()->logo($this->settings);
|
||||||
|
|
||||||
|
$data['$company.logo'] = ['value' => "<img src='{$logo}' class='h-32' alt='logo'>" ?: ' ', 'label' => ctrans('texts.logo')];
|
||||||
|
$data['$company_logo'] = &$data['$company.logo'];
|
||||||
|
$data['$company1'] = ['value' => $this->settings->custom_value1 ?: ' ', 'label' => $this->makeCustomField('company1')];
|
||||||
|
$data['$company2'] = ['value' => $this->settings->custom_value2 ?: ' ', 'label' => $this->makeCustomField('company2')];
|
||||||
|
$data['$company3'] = ['value' => $this->settings->custom_value3 ?: ' ', 'label' => $this->makeCustomField('company3')];
|
||||||
|
$data['$company4'] = ['value' => $this->settings->custom_value4 ?: ' ', 'label' => $this->makeCustomField('company4')];
|
||||||
|
|
||||||
|
$data['$product.date'] = ['value' => '', 'label' => ctrans('texts.date')];
|
||||||
|
$data['$product.discount'] = ['value' => '', 'label' => ctrans('texts.discount')];
|
||||||
|
$data['$product.product_key'] = ['value' => '', 'label' => ctrans('texts.product_key')];
|
||||||
|
$data['$product.notes'] = ['value' => '', 'label' => ctrans('texts.notes')];
|
||||||
|
$data['$product.cost'] = ['value' => '', 'label' => ctrans('texts.cost')];
|
||||||
|
$data['$product.quantity'] = ['value' => '', 'label' => ctrans('texts.quantity')];
|
||||||
|
$data['$product.tax_name1'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$product.tax'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$product.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$product.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$product.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')];
|
||||||
|
|
||||||
|
$data['$task.date'] = ['value' => '', 'label' => ctrans('texts.date')];
|
||||||
|
$data['$task.discount'] = ['value' => '', 'label' => ctrans('texts.discount')];
|
||||||
|
$data['$task.product_key'] = ['value' => '', 'label' => ctrans('texts.product_key')];
|
||||||
|
$data['$task.notes'] = ['value' => '', 'label' => ctrans('texts.notes')];
|
||||||
|
$data['$task.cost'] = ['value' => '', 'label' => ctrans('texts.cost')];
|
||||||
|
$data['$task.quantity'] = ['value' => '', 'label' => ctrans('texts.quantity')];
|
||||||
|
$data['$task.tax'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$task.tax_name1'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$task.tax_name2'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$task.tax_name3'] = ['value' => '', 'label' => ctrans('texts.tax')];
|
||||||
|
$data['$task.line_total'] = ['value' => '', 'label' => ctrans('texts.line_total')];
|
||||||
|
//$data['$contact.signature']
|
||||||
|
|
||||||
|
// $data['custom_label1'] = ['value' => '', 'label' => ctrans('texts.')];
|
||||||
|
// $data['custom_label2'] = ['value' => '', 'label' => ctrans('texts.')];
|
||||||
|
// $data['custom_label3'] = ['value' => '', 'label' => ctrans('texts.')];
|
||||||
|
// $data['custom_label4'] = ['value' => '', 'label' => ctrans('texts.')];
|
||||||
|
//$data['$blank'] = ;
|
||||||
|
//$data['$surcharge'] = ;
|
||||||
|
/*
|
||||||
|
$data['$tax_invoice'] =
|
||||||
|
$data['$tax_quote'] =
|
||||||
|
$data['$statement'] = ;
|
||||||
|
$data['$statement_date'] = ;
|
||||||
|
$data['$your_statement'] = ;
|
||||||
|
$data['$statement_issued_to'] = ;
|
||||||
|
$data['$statement_to'] = ;
|
||||||
|
$data['$credit_note'] = ;
|
||||||
|
$data['$credit_date'] = ;
|
||||||
|
$data['$credit_issued_to'] = ;
|
||||||
|
$data['$credit_to'] = ;
|
||||||
|
$data['$your_credit'] = ;
|
||||||
|
$data['$phone'] = ;
|
||||||
|
|
||||||
|
$data['$outstanding'] = ;
|
||||||
|
$data['$invoice_due_date'] = ;
|
||||||
|
$data['$quote_due_date'] = ;
|
||||||
|
$data['$service'] = ;
|
||||||
|
$data['$product_key'] = ;
|
||||||
|
$data['$unit_cost'] = ;
|
||||||
|
$data['$custom_value1'] = ;
|
||||||
|
$data['$custom_value2'] = ;
|
||||||
|
$data['$delivery_note'] = ;
|
||||||
|
$data['$date'] = ;
|
||||||
|
$data['$method'] = ;
|
||||||
|
$data['$payment_date'] = ;
|
||||||
|
$data['$reference'] = ;
|
||||||
|
$data['$amount'] = ;
|
||||||
|
$data['$amount_paid'] =;
|
||||||
|
*/
|
||||||
|
|
||||||
|
$arrKeysLength = array_map('strlen', array_keys($data));
|
||||||
|
array_multisort($arrKeysLength, SORT_DESC, $data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateLabelsAndValues()
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$values = $this->buildEntityDataArray();
|
||||||
|
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
$data['values'][$key] = $value['value'];
|
||||||
|
$data['labels'][$key.'_label'] = $value['label'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function totalTaxLabels() :string
|
||||||
|
{
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
if (!$this->entity_calc->getTotalTaxMap()) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->entity_calc->getTotalTaxMap() as $tax) {
|
||||||
|
$data .= '<span>'. $tax['name'] .'</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function totalTaxValues() :string
|
||||||
|
{
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
if (!$this->entity_calc->getTotalTaxMap()) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->entity_calc->getTotalTaxMap() as $tax) {
|
||||||
|
$data .= '<span>'. Number::formatMoney($tax['total'], $this->client) .'</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function lineTaxLabels() :string
|
||||||
|
{
|
||||||
|
$tax_map = $this->entity_calc->getTaxMap();
|
||||||
|
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
foreach ($tax_map as $tax) {
|
||||||
|
$data .= '<span>'. $tax['name'] .'</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCountryName() :string
|
||||||
|
{
|
||||||
|
$country = Country::find($this->settings->country_id)->first();
|
||||||
|
|
||||||
|
if($country)
|
||||||
|
return $country->name;
|
||||||
|
|
||||||
|
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Due to the way we are compiling the blade template we
|
||||||
|
* have no ability to iterate, so in the case
|
||||||
|
* of line taxes where there are multiple rows,
|
||||||
|
* we use this function to format a section of rows
|
||||||
|
*
|
||||||
|
* @return string a collection of <tr> rows with line item
|
||||||
|
* aggregate data
|
||||||
|
*/
|
||||||
|
private function makeLineTaxes() :string
|
||||||
|
{
|
||||||
|
$tax_map = $this->entity_calc->getTaxMap();
|
||||||
|
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
foreach ($tax_map as $tax) {
|
||||||
|
$data .= '<tr class="line_taxes">';
|
||||||
|
$data .= '<td>'. $tax['name'] .'</td>';
|
||||||
|
$data .= '<td>'. Number::formatMoney($tax['total'], $this->client) .'</td></tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function lineTaxValues() :string
|
||||||
|
{
|
||||||
|
$tax_map = $this->entity_calc->getTaxMap();
|
||||||
|
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
foreach ($tax_map as $tax) {
|
||||||
|
$data .= '<span>'. Number::formatMoney($tax['total'], $this->client) .'</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function makeCustomField($field) :string
|
||||||
|
{
|
||||||
|
$custom_fields = $this->company->custom_fields;
|
||||||
|
|
||||||
|
if ($custom_fields && property_exists($custom_fields, $field)) {
|
||||||
|
$custom_field = $custom_fields->{$field};
|
||||||
|
$custom_field_parts = explode("|", $custom_field);
|
||||||
|
|
||||||
|
return $custom_field_parts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function makeTotalTaxes() :string
|
||||||
|
{
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
if (!$this->entity_calc->getTotalTaxMap()) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->entity_calc->getTotalTaxMap() as $tax) {
|
||||||
|
$data .= '<tr class="total_taxes">';
|
||||||
|
$data .= '<td>'. $tax['name'] .'</td>';
|
||||||
|
$data .= '<td>'. Number::formatMoney($tax['total'], $this->client) .'</td></tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseLabelsAndValues($labels, $values, $section) :string
|
||||||
|
{
|
||||||
|
|
||||||
|
$section = strtr($section, $labels);
|
||||||
|
return strtr($section, $values);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
| Ensures the URL doesn't have duplicated trailing slash
|
||||||
|
*/
|
||||||
|
public function generateAppUrl()
|
||||||
|
{
|
||||||
|
return rtrim(config('ninja.app_url'), "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds CSS to assist with the generation
|
||||||
|
* of Repeating headers and footers on the PDF
|
||||||
|
* @return string The css string
|
||||||
|
*/
|
||||||
|
private function generateCustomCSS() :string
|
||||||
|
{
|
||||||
|
|
||||||
|
$header_and_footer = '
|
||||||
|
.header, .header-space {
|
||||||
|
height: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer, .footer-space {
|
||||||
|
height: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0mm;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
thead {display: table-header-group;}
|
||||||
|
tfoot {display: table-footer-group;}
|
||||||
|
button {display: none;}
|
||||||
|
body {margin: 0;}
|
||||||
|
}';
|
||||||
|
|
||||||
|
$header = '
|
||||||
|
.header, .header-space {
|
||||||
|
height: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0mm;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
thead {display: table-header-group;}
|
||||||
|
button {display: none;}
|
||||||
|
body {margin: 0;}
|
||||||
|
}';
|
||||||
|
|
||||||
|
$footer = '
|
||||||
|
|
||||||
|
.footer, .footer-space {
|
||||||
|
height: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
tfoot {display: table-footer-group;}
|
||||||
|
button {display: none;}
|
||||||
|
body {margin: 0;}
|
||||||
|
}';
|
||||||
|
$css = '';
|
||||||
|
|
||||||
|
if ($this->settings->all_pages_header && $this->settings->all_pages_footer) {
|
||||||
|
$css .= $header_and_footer;
|
||||||
|
} elseif ($this->settings->all_pages_header && !$this->settings->all_pages_footer) {
|
||||||
|
$css .= $header;
|
||||||
|
} elseif (!$this->settings->all_pages_header && $this->settings->all_pages_footer) {
|
||||||
|
$css .= $footer;
|
||||||
|
}
|
||||||
|
|
||||||
|
$css .= '
|
||||||
|
.page {
|
||||||
|
page-break-after: always;
|
||||||
|
}
|
||||||
|
|
||||||
|
@page {
|
||||||
|
margin: 0mm
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
';
|
||||||
|
|
||||||
|
$css .= 'font-size:' . $this->settings->font_size . 'px;';
|
||||||
|
// $css .= 'font-size:14px;';
|
||||||
|
|
||||||
|
$css .= '}';
|
||||||
|
|
||||||
|
return $css;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
app/Utils/TempFile.php
Normal file
26
app/Utils/TempFile.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?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\Utils;
|
||||||
|
|
||||||
|
class TempFile
|
||||||
|
{
|
||||||
|
|
||||||
|
public static function path($url) :string
|
||||||
|
{
|
||||||
|
|
||||||
|
$temp_path = tempnam(sys_get_temp_dir(), basename($url));
|
||||||
|
copy($url, $temp_path);
|
||||||
|
|
||||||
|
return $temp_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -102,7 +102,7 @@ class TemplateEngine
|
|||||||
private function replaceValues()
|
private function replaceValues()
|
||||||
{
|
{
|
||||||
if ($this->entity_obj) {
|
if ($this->entity_obj) {
|
||||||
$this->entityValues();
|
$this->entityValues($this->entity_obj->client->primary_contact()->first());
|
||||||
} else {
|
} else {
|
||||||
$this->fakerValues();
|
$this->fakerValues();
|
||||||
}
|
}
|
||||||
@ -115,11 +115,6 @@ class TemplateEngine
|
|||||||
$labels = $this->makeFakerLabels();
|
$labels = $this->makeFakerLabels();
|
||||||
$values = $this->makeFakerValues();
|
$values = $this->makeFakerValues();
|
||||||
|
|
||||||
// $this->body = str_replace(array_keys($labels), array_values($labels), $this->body);
|
|
||||||
// $this->body = str_replace(array_keys($values), array_values($values), $this->body);
|
|
||||||
// $this->subject = str_replace(array_keys($labels), array_values($labels), $this->subject);
|
|
||||||
// $this->subject = str_replace(array_keys($values), array_values($values), $this->subject);
|
|
||||||
|
|
||||||
$this->body = strtr($this->body, $labels);
|
$this->body = strtr($this->body, $labels);
|
||||||
$this->body = strtr($this->body, $values);
|
$this->body = strtr($this->body, $values);
|
||||||
|
|
||||||
@ -133,16 +128,16 @@ class TemplateEngine
|
|||||||
$this->body = $converter->convertToHtml($this->body);
|
$this->body = $converter->convertToHtml($this->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function entityValues()
|
private function entityValues($contact)
|
||||||
{
|
{
|
||||||
$labels = $this->entity_obj->makeLabels();
|
|
||||||
$values = $this->entity_obj->makeValues();
|
|
||||||
|
|
||||||
$this->body = strtr($this->body, $labels);
|
$data = $this->entity_obj->buildLabelsAndValues($contact);
|
||||||
$this->body = strtr($this->body, $values);
|
|
||||||
|
|
||||||
$this->subject = strtr($this->subject, $labels);
|
$this->body = strtr($this->body, $data['labels']);
|
||||||
$this->subject = strtr($this->subject, $values);
|
$this->body = strtr($this->body, $data['values']);
|
||||||
|
|
||||||
|
$this->subject = strtr($this->subject, $data['labels']);
|
||||||
|
$this->subject = strtr($this->subject, $data['values']);
|
||||||
|
|
||||||
$converter = new CommonMarkConverter([
|
$converter = new CommonMarkConverter([
|
||||||
'allow_unsafe_links' => false,
|
'allow_unsafe_links' => false,
|
||||||
|
@ -42,8 +42,7 @@ trait MakesInvoiceHtml
|
|||||||
|
|
||||||
App::setLocale($client->preferredLocale());
|
App::setLocale($client->preferredLocale());
|
||||||
|
|
||||||
$labels = $entity->makeLabels();
|
$values_and_labels = $entity->buildLabelsAndValues($contact);
|
||||||
$values = $entity->makeValues($contact);
|
|
||||||
|
|
||||||
$designer->build();
|
$designer->build();
|
||||||
|
|
||||||
@ -57,10 +56,8 @@ trait MakesInvoiceHtml
|
|||||||
|
|
||||||
$html = view('pdf.stub', $data)->render();
|
$html = view('pdf.stub', $data)->render();
|
||||||
|
|
||||||
$html = $this->parseLabelsAndValues($labels, $values, $html);
|
$html = $this->parseLabelsAndValues($values_and_labels['labels'], $values_and_labels['values'], $html);
|
||||||
|
|
||||||
// info($html);
|
|
||||||
|
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,17 +69,13 @@ trait MakesInvoiceHtml
|
|||||||
|
|
||||||
App::setLocale($client->preferredLocale());
|
App::setLocale($client->preferredLocale());
|
||||||
|
|
||||||
$labels = $entity->makeLabels();
|
$data = $entity->buildLabelsAndValues($contact);
|
||||||
$values = $entity->makeValues($contact);
|
|
||||||
|
|
||||||
return $this->parseLabelsAndValues($labels, $values, $content);
|
return $this->parseLabelsAndValues($data['labels'], $data['values'], $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseLabelsAndValues($labels, $values, $section) :string
|
private function parseLabelsAndValues($labels, $values, $section) :string
|
||||||
{
|
{
|
||||||
|
|
||||||
// $section = str_replace(array_keys($labels), array_values($labels), $section);
|
|
||||||
// $section = str_replace(array_keys($values), array_values($values), $section);
|
|
||||||
|
|
||||||
$section = strtr($section, $labels);
|
$section = strtr($section, $labels);
|
||||||
$section = strtr($section, $values);
|
$section = strtr($section, $values);
|
||||||
|
@ -159,6 +159,20 @@ trait MakesInvoiceValues
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildLabelsAndValues($contact)
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$values = $this->makeLabelsAndValues($contact);
|
||||||
|
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
$data['values'][$key] = $value['value'];
|
||||||
|
$data['labels'][$key.'_label'] = $value['label'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
private function makeLabelsAndValues($contact = null) :array
|
private function makeLabelsAndValues($contact = null) :array
|
||||||
{
|
{
|
||||||
if (!$this->client->currency() || !$this->client) {
|
if (!$this->client->currency() || !$this->client) {
|
||||||
@ -432,7 +446,7 @@ trait MakesInvoiceValues
|
|||||||
|
|
||||||
$table_header .= '</tr>';
|
$table_header .= '</tr>';
|
||||||
|
|
||||||
$table_header = str_replace(array_keys($data), array_values($data), $table_header);
|
$table_header = strtr($table_header, $data);// str_replace(array_keys($data), array_values($data), $table_header);
|
||||||
|
|
||||||
return $table_header;
|
return $table_header;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
"laravel/slack-notification-channel": "^2.0",
|
"laravel/slack-notification-channel": "^2.0",
|
||||||
"laravel/socialite": "^4.0",
|
"laravel/socialite": "^4.0",
|
||||||
"laravel/tinker": "^1.0",
|
"laravel/tinker": "^1.0",
|
||||||
|
"league/flysystem-aws-s3-v3": "~1.0",
|
||||||
|
"league/flysystem-cached-adapter": "~1.0",
|
||||||
"league/fractal": "^0.17.0",
|
"league/fractal": "^0.17.0",
|
||||||
"league/omnipay": "^3.0",
|
"league/omnipay": "^3.0",
|
||||||
"maennchen/zipstream-php": "^1.2",
|
"maennchen/zipstream-php": "^1.2",
|
||||||
|
@ -61,7 +61,9 @@ return [
|
|||||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||||
'region' => env('AWS_DEFAULT_REGION'),
|
'region' => env('AWS_DEFAULT_REGION'),
|
||||||
'bucket' => env('AWS_BUCKET'),
|
'bucket' => env('AWS_BUCKET'),
|
||||||
|
'endpoint' => env('AWS_ENDPOINT'),
|
||||||
'url' => env('AWS_URL'),
|
'url' => env('AWS_URL'),
|
||||||
|
'visibility' => 'public',
|
||||||
],
|
],
|
||||||
'gcs' => [
|
'gcs' => [
|
||||||
'driver' => 'gcs',
|
'driver' => 'gcs',
|
||||||
|
@ -3197,4 +3197,5 @@ return [
|
|||||||
'open_in_new_tab' => 'Open in new tab',
|
'open_in_new_tab' => 'Open in new tab',
|
||||||
'complete_your_payment' => 'Complete payment',
|
'complete_your_payment' => 'Complete payment',
|
||||||
'authorize_for_future_use' => 'Authorize payment method for future use',
|
'authorize_for_future_use' => 'Authorize payment method for future use',
|
||||||
|
'view_credit' => 'View Credit',
|
||||||
];
|
];
|
||||||
|
@ -9,9 +9,15 @@
|
|||||||
@lang($body)
|
@lang($body)
|
||||||
@endslot
|
@endslot
|
||||||
|
|
||||||
@slot('signature')
|
@if(isset($view_link))
|
||||||
|
@component('email.components.button', ['url' => $view_link])
|
||||||
|
{{ $view_text }}
|
||||||
|
@endcomponent
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(isset($signature))
|
||||||
{{ $signature }}
|
{{ $signature }}
|
||||||
@endslot
|
@endif
|
||||||
|
|
||||||
@slot('footer')
|
@slot('footer')
|
||||||
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja'])
|
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja'])
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
@endcomponent
|
@endcomponent
|
||||||
|
|
||||||
|
@if(isset($view_link))
|
||||||
|
@component('email.components.button', ['url' => $view_link])
|
||||||
|
{{$view_text}}
|
||||||
|
@endcomponent
|
||||||
|
@endif
|
||||||
|
|
||||||
@if($footer)
|
@if($footer)
|
||||||
@component('email.components.button', ['url' => $view_link])
|
@component('email.components.button', ['url' => $view_link])
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
|
|
||||||
<embed src="{{ asset($invoice->pdf_url()) }}#toolbar=1&navpanes=1&scrollbar=1" type="application/pdf" width="100%" height="1180px" />
|
<embed src="{{ $invoice->pdf_file_path() }}#toolbar=1&navpanes=1&scrollbar=1" type="application/pdf" width="100%" height="1180px" />
|
||||||
|
|
||||||
<div id="pdfCanvas" style="display:none;width:100%;background-color:#525659;border:solid 2px #9a9a9a;padding-top:40px;text-align:center">
|
<div id="pdfCanvas" style="display:none;width:100%;background-color:#525659;border:solid 2px #9a9a9a;padding-top:40px;text-align:center">
|
||||||
<canvas id="theCanvas" style="max-width:100%;border:solid 1px #CCCCCC;"></canvas>
|
<canvas id="theCanvas" style="max-width:100%;border:solid 1px #CCCCCC;"></canvas>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@section('meta_title', ctrans('texts.view_invoice'))
|
@section('meta_title', ctrans('texts.view_invoice'))
|
||||||
|
|
||||||
@push('head')
|
@push('head')
|
||||||
<meta name="pdf-url" content="{{ asset($invoice->pdf_url()) }}">
|
<meta name="pdf-url" content="{{ $invoice->pdf_file_path() }}">
|
||||||
<script src="{{ asset('js/vendor/pdf.js/pdf.min.js') }}"></script>
|
<script src="{{ asset('js/vendor/pdf.js/pdf.min.js') }}"></script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@ -84,7 +84,7 @@
|
|||||||
<div x-show="open" x-transition:enter="transition ease-out duration-100" x-transition:enter-start="transform opacity-0 scale-95" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-75" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-95" class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">
|
<div x-show="open" x-transition:enter="transition ease-out duration-100" x-transition:enter-start="transform opacity-0 scale-95" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-75" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-95" class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">
|
||||||
<div class="rounded-md bg-white shadow-xs">
|
<div class="rounded-md bg-white shadow-xs">
|
||||||
<div class="py-1">
|
<div class="py-1">
|
||||||
<a target="_blank" href="{{ asset($invoice->pdf_url()) }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">{{ ctrans('texts.open_in_new_tab') }}</a>
|
<a target="_blank" href="{{ $invoice->pdf_file_path() }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">{{ ctrans('texts.open_in_new_tab') }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
<div x-show="open" x-transition:enter="transition ease-out duration-100" x-transition:enter-start="transform opacity-0 scale-95" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-75" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-95" class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">
|
<div x-show="open" x-transition:enter="transition ease-out duration-100" x-transition:enter-start="transform opacity-0 scale-95" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-75" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-95" class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">
|
||||||
<div class="rounded-md bg-white shadow-xs">
|
<div class="rounded-md bg-white shadow-xs">
|
||||||
<div class="py-1">
|
<div class="py-1">
|
||||||
<a target="_blank" href="{{ asset($invoice->pdf_url()) }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">{{ ctrans('texts.open_in_new_tab') }}</a>
|
<a target="_blank" href="{{ $invoice->pdf_file_path() }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">{{ ctrans('texts.open_in_new_tab') }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,9 +51,7 @@ Route::group(['middleware' => ['auth:contact','locale'], 'prefix' => 'client', '
|
|||||||
|
|
||||||
Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||||
/*Invitation catches*/
|
/*Invitation catches*/
|
||||||
Route::get('invoice/{invitation_key}', 'ClientPortal\InvitationController@router')->name('invoice.invitation_key');
|
Route::get('{entity}/{invitation_key}', 'ClientPortal\InvitationController@router');
|
||||||
Route::get('quote/{invitation_key}', 'ClientPortal\InvitationController@router')->name('quote.invitation_key');
|
|
||||||
Route::get('credit/{invitation_key}', 'ClientPortal\InvitationController@router')->name('credit.invitation_key');
|
|
||||||
Route::get('invoice/{invitation_key}/download_pdf', 'InvoiceController@downloadPdf')->name('invoice.download_invitation_key');
|
Route::get('invoice/{invitation_key}/download_pdf', 'InvoiceController@downloadPdf')->name('invoice.download_invitation_key');
|
||||||
Route::get('quote/{invitation_key}/download_pdf', 'QuoteController@downloadPdf')->name('quote.download_invitation_key');
|
Route::get('quote/{invitation_key}/download_pdf', 'QuoteController@downloadPdf')->name('quote.download_invitation_key');
|
||||||
Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf')->name('credit.download_invitation_key');
|
Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf')->name('credit.download_invitation_key');
|
||||||
|
@ -65,6 +65,10 @@ class DesignTest extends TestCase
|
|||||||
|
|
||||||
$this->invoice->uses_inclusive_taxes = false;
|
$this->invoice->uses_inclusive_taxes = false;
|
||||||
|
|
||||||
|
$this->invoice->service()->createInvitations()->markSent()->save();
|
||||||
|
$this->invoice->fresh();
|
||||||
|
$this->invoice->load('invitations');
|
||||||
|
|
||||||
$settings = $this->invoice->client->settings;
|
$settings = $this->invoice->client->settings;
|
||||||
$settings->invoice_design_id = "VolejRejNm";
|
$settings->invoice_design_id = "VolejRejNm";
|
||||||
$settings->all_pages_header = true;
|
$settings->all_pages_header = true;
|
||||||
@ -73,7 +77,7 @@ class DesignTest extends TestCase
|
|||||||
$this->client->settings = $settings;
|
$this->client->settings = $settings;
|
||||||
$this->client->save();
|
$this->client->save();
|
||||||
|
|
||||||
CreateInvoicePdf::dispatchNow($this->invoice, $this->invoice->company, $this->invoice->client->primary_contact()->first());
|
CreateInvoicePdf::dispatchNow($this->invoice->invitations->first());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testQuoteDesignExists()
|
public function testQuoteDesignExists()
|
||||||
@ -97,6 +101,10 @@ class DesignTest extends TestCase
|
|||||||
|
|
||||||
$this->quote->uses_inclusive_taxes = false;
|
$this->quote->uses_inclusive_taxes = false;
|
||||||
|
|
||||||
|
$this->quote->service()->createInvitations()->markSent()->save();
|
||||||
|
|
||||||
|
$this->quote->fresh();
|
||||||
|
$this->quote->load('invitations');
|
||||||
$settings = $this->quote->client->settings;
|
$settings = $this->quote->client->settings;
|
||||||
$settings->invoice_design_id = "VolejRejNm";
|
$settings->invoice_design_id = "VolejRejNm";
|
||||||
$settings->all_pages_header = true;
|
$settings->all_pages_header = true;
|
||||||
@ -105,7 +113,12 @@ class DesignTest extends TestCase
|
|||||||
$this->client->settings = $settings;
|
$this->client->settings = $settings;
|
||||||
$this->client->save();
|
$this->client->save();
|
||||||
|
|
||||||
CreateQuotePdf::dispatchNow($this->quote, $this->quote->company, $this->quote->client->primary_contact()->first());
|
$this->quote->setRelation('client', $this->client);
|
||||||
|
|
||||||
|
$invitation = $this->quote->invitations->first();
|
||||||
|
$invitation->setRelation('quote', $this->quote);
|
||||||
|
|
||||||
|
CreateQuotePdf::dispatchNow($invitation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -126,12 +139,17 @@ class DesignTest extends TestCase
|
|||||||
|
|
||||||
$this->credit->client_id = $this->client->id;
|
$this->credit->client_id = $this->client->id;
|
||||||
$this->credit->setRelation('client', $this->client);
|
$this->credit->setRelation('client', $this->client);
|
||||||
$this->credit->save();
|
|
||||||
|
$this->credit->service()->createInvitations()->markSent()->save();
|
||||||
|
$this->credit->fresh();
|
||||||
|
$this->credit->load('invitations');
|
||||||
|
$invitation = $this->credit->invitations->first();
|
||||||
|
$invitation->setRelation('credit', $this->credit);
|
||||||
|
|
||||||
$this->client->settings = $settings;
|
$this->client->settings = $settings;
|
||||||
$this->client->save();
|
$this->client->save();
|
||||||
|
|
||||||
CreateCreditPdf::dispatchNow($this->credit, $this->credit->company, $this->credit->client->primary_contact()->first());
|
CreateCreditPdf::dispatchNow($invitation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAllDesigns()
|
public function testAllDesigns()
|
||||||
@ -149,7 +167,14 @@ class DesignTest extends TestCase
|
|||||||
$this->client->settings = $settings;
|
$this->client->settings = $settings;
|
||||||
$this->client->save();
|
$this->client->save();
|
||||||
|
|
||||||
CreateQuotePdf::dispatchNow($this->quote, $this->quote->company, $this->quote->client->primary_contact()->first());
|
$this->quote->service()->createInvitations()->markSent()->save();
|
||||||
|
$this->quote->fresh();
|
||||||
|
$this->quote->load('invitations');
|
||||||
|
|
||||||
|
$invitation = $this->quote->invitations->first();
|
||||||
|
$invitation->setRelation('quote', $this->quote);
|
||||||
|
|
||||||
|
CreateQuotePdf::dispatchNow($invitation);
|
||||||
|
|
||||||
$this->quote->number = $this->getNextQuoteNumber($this->quote->client);
|
$this->quote->number = $this->getNextQuoteNumber($this->quote->client);
|
||||||
$this->quote->save();
|
$this->quote->save();
|
||||||
@ -158,117 +183,4 @@ class DesignTest extends TestCase
|
|||||||
$this->assertTrue(true);
|
$this->assertTrue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// public function testQuoteDesignWithRepeatingHeader()
|
|
||||||
// {
|
|
||||||
|
|
||||||
// $modern = new Modern();
|
|
||||||
|
|
||||||
// $designer = new Designer($this->quote, $modern, $this->company->settings->pdf_variables, 'quote');
|
|
||||||
|
|
||||||
// $html = $designer->build()->getHtml();
|
|
||||||
|
|
||||||
// $this->assertNotNull($html);
|
|
||||||
|
|
||||||
// //\Log::error($html);
|
|
||||||
|
|
||||||
// $settings = $this->invoice->client->settings;
|
|
||||||
// $settings->quote_design_id = "4";
|
|
||||||
// $settings->all_pages_header = true;
|
|
||||||
|
|
||||||
// $this->quote->client_id = $this->client->id;
|
|
||||||
// $this->quote->setRelation('client', $this->client);
|
|
||||||
// $this->quote->save();
|
|
||||||
|
|
||||||
// $this->client->settings = $settings;
|
|
||||||
// $this->client->save();
|
|
||||||
|
|
||||||
// CreateQuotePdf::dispatchNow($this->quote, $this->quote->company, $this->quote->client->primary_contact()->first());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public function testQuoteDesignWithRepeatingFooter()
|
|
||||||
// {
|
|
||||||
|
|
||||||
// $modern = new Modern();
|
|
||||||
|
|
||||||
// $designer = new Designer($this->quote, $modern, $this->company->settings->pdf_variables, 'quote');
|
|
||||||
|
|
||||||
// $html = $designer->build()->getHtml();
|
|
||||||
|
|
||||||
// $this->assertNotNull($html);
|
|
||||||
|
|
||||||
// //\Log::error($html);
|
|
||||||
|
|
||||||
// $settings = $this->invoice->client->settings;
|
|
||||||
// $settings->quote_design_id = "4";
|
|
||||||
// $settings->all_pages_footer = true;
|
|
||||||
|
|
||||||
// $this->quote->client_id = $this->client->id;
|
|
||||||
// $this->quote->setRelation('client', $this->client);
|
|
||||||
// $this->quote->save();
|
|
||||||
|
|
||||||
// $this->client->settings = $settings;
|
|
||||||
// $this->client->save();
|
|
||||||
|
|
||||||
// CreateQuotePdf::dispatchNow($this->quote, $this->quote->company, $this->quote->client->primary_contact()->first());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public function testQuoteDesignWithRepeatingHeaderAndFooter()
|
|
||||||
// {
|
|
||||||
|
|
||||||
// $modern = new Modern();
|
|
||||||
|
|
||||||
// $designer = new Designer($this->quote, $modern, $this->company->settings->pdf_variables, 'quote');
|
|
||||||
|
|
||||||
// $html = $designer->build()->getHtml();
|
|
||||||
|
|
||||||
// $this->assertNotNull($html);
|
|
||||||
|
|
||||||
// //\Log::error($html);
|
|
||||||
|
|
||||||
// $settings = $this->invoice->client->settings;
|
|
||||||
// $settings->quote_design_id = "4";
|
|
||||||
// $settings->all_pages_header = true;
|
|
||||||
// $settings->all_pages_footer = true;
|
|
||||||
|
|
||||||
// $this->quote->client_id = $this->client->id;
|
|
||||||
// $this->quote->setRelation('client', $this->client);
|
|
||||||
// $this->quote->save();
|
|
||||||
|
|
||||||
// $this->client->settings = $settings;
|
|
||||||
// $this->client->save();
|
|
||||||
|
|
||||||
// CreateQuotePdf::dispatchNow($this->quote, $this->quote->company, $this->quote->client->primary_contact()->first());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class InvoiceUploadTest extends TestCase
|
|||||||
|
|
||||||
public function testInvoiceUploadWorks()
|
public function testInvoiceUploadWorks()
|
||||||
{
|
{
|
||||||
CreateInvoicePdf::dispatchNow($this->invoice, $this->invoice->company, $this->invoice->client->primary_contact()->first());
|
CreateInvoicePdf::dispatchNow($this->invoice->invitations->first());
|
||||||
|
|
||||||
$this->assertNotNull($this->invoice->service()->getInvoicePdf($this->invoice->client->primary_contact()->first()));
|
$this->assertNotNull($this->invoice->service()->getInvoicePdf($this->invoice->client->primary_contact()->first()));
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ use Tests\TestCase;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
* @covers App\Http\ViewComposers\TranslationComposer
|
|
||||||
*/
|
*/
|
||||||
class CollectionMergingTest extends TestCase
|
class CollectionMergingTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,9 @@ class CompanyDocumentsTest extends TestCase
|
|||||||
|
|
||||||
public function testCompanyDocumentExists()
|
public function testCompanyDocumentExists()
|
||||||
{
|
{
|
||||||
|
$company_key = $this->company->company_key;
|
||||||
|
|
||||||
|
|
||||||
$original_count = Document::whereCompanyId($this->company->id)->count();
|
$original_count = Document::whereCompanyId($this->company->id)->count();
|
||||||
|
|
||||||
$image = UploadedFile::fake()->image('avatar.jpg');
|
$image = UploadedFile::fake()->image('avatar.jpg');
|
||||||
@ -44,16 +47,14 @@ class CompanyDocumentsTest extends TestCase
|
|||||||
|
|
||||||
$this->assertNotNull($document);
|
$this->assertNotNull($document);
|
||||||
|
|
||||||
$this->assertGreaterThan($original_count, Document::whereCompanyId($this->company->id)->count());
|
$this->assertTrue(Storage::exists($document->path));
|
||||||
|
|
||||||
$company_key = $this->company->company_key;
|
$this->assertGreaterThan($original_count, Document::whereCompanyId($this->company->id)->count());
|
||||||
|
|
||||||
$this->company->delete();
|
$this->company->delete();
|
||||||
|
|
||||||
$this->assertEquals(0, Document::whereCompanyId($this->company->id)->count());
|
$this->assertEquals(0, Document::whereCompanyId($this->company->id)->count());
|
||||||
|
|
||||||
$path = sprintf('%s/%s', storage_path('app/public'), $company_key);
|
$this->assertFalse(Storage::exists($document->path));
|
||||||
|
|
||||||
$this->assertFalse(file_exists($path));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use Tests\TestCase;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
* @covers App\Utils\Traits\Invoice\ActionInvoice
|
* @covers App\Utils\Traits\Invoice\ActionsInvoice
|
||||||
*/
|
*/
|
||||||
class InvoiceActionsTest extends TestCase
|
class InvoiceActionsTest extends TestCase
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user