mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-31 23:04:36 -04:00
Merge designer into design_changes
This commit is contained in:
commit
d21ce4a567
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,6 +19,7 @@ yarn-error.log
|
|||||||
local_version.txt
|
local_version.txt
|
||||||
.env
|
.env
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
|
_ide_helper.php
|
||||||
|
|
||||||
/resources/assets/bower
|
/resources/assets/bower
|
||||||
/public/logo
|
/public/logo
|
||||||
|
@ -22,7 +22,7 @@ class ClientContactFactory
|
|||||||
$client_contact->first_name = '';
|
$client_contact->first_name = '';
|
||||||
$client_contact->user_id = $user_id;
|
$client_contact->user_id = $user_id;
|
||||||
$client_contact->company_id = $company_id;
|
$client_contact->company_id = $company_id;
|
||||||
$client_contact->contact_key = Str::random(40);
|
$client_contact->contact_key = Str::random(32);
|
||||||
$client_contact->id = 0;
|
$client_contact->id = 0;
|
||||||
$client_contact->send_email = true;
|
$client_contact->send_email = true;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class VendorContactFactory
|
|||||||
$vendor_contact->first_name = '';
|
$vendor_contact->first_name = '';
|
||||||
$vendor_contact->user_id = $user_id;
|
$vendor_contact->user_id = $user_id;
|
||||||
$vendor_contact->company_id = $company_id;
|
$vendor_contact->company_id = $company_id;
|
||||||
$vendor_contact->contact_key = Str::random(40);
|
$vendor_contact->contact_key = Str::random(32);
|
||||||
$vendor_contact->id = 0;
|
$vendor_contact->id = 0;
|
||||||
|
|
||||||
return $vendor_contact;
|
return $vendor_contact;
|
||||||
|
@ -91,7 +91,7 @@ class InvitationController extends Controller
|
|||||||
|
|
||||||
$file_name = $invitation->purchase_order->numberFormatter().'.pdf';
|
$file_name = $invitation->purchase_order->numberFormatter().'.pdf';
|
||||||
|
|
||||||
$file = (new CreatePurchaseOrderPdf($invitation))->rawPdf();
|
$file = (new CreatePurchaseOrderPdf($invitation))->handle();
|
||||||
|
|
||||||
$headers = ['Content-Type' => 'application/pdf'];
|
$headers = ['Content-Type' => 'application/pdf'];
|
||||||
|
|
||||||
|
@ -327,21 +327,6 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
return $this->service()->updateBalance($amount);
|
return $this->service()->updateBalance($amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjusts client "balances" when a client
|
|
||||||
* makes a payment that goes on file, but does
|
|
||||||
* not effect the client.balance record.
|
|
||||||
*
|
|
||||||
* @param float $amount Adjustment amount
|
|
||||||
* @return Client
|
|
||||||
*/
|
|
||||||
// public function processUnappliedPayment($amount) :Client
|
|
||||||
// {
|
|
||||||
// return $this->service()->updatePaidToDate($amount)
|
|
||||||
// ->adjustCreditBalance($amount)
|
|
||||||
// ->save();
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the entire filtered set
|
* Returns the entire filtered set
|
||||||
* of settings which have been merged from
|
* of settings which have been merged from
|
||||||
|
@ -169,6 +169,11 @@ class Vendor extends BaseModel
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMergedSettings() :object
|
||||||
|
{
|
||||||
|
return $this->company->settings;
|
||||||
|
}
|
||||||
|
|
||||||
public function purchase_order_filepath($invitation)
|
public function purchase_order_filepath($invitation)
|
||||||
{
|
{
|
||||||
$contact_key = $invitation->contact->contact_key;
|
$contact_key = $invitation->contact->contact_key;
|
||||||
|
1573
app/Services/Pdf/PdfBuilder.php
Normal file
1573
app/Services/Pdf/PdfBuilder.php
Normal file
File diff suppressed because it is too large
Load Diff
352
app/Services/Pdf/PdfConfiguration.php
Normal file
352
app/Services/Pdf/PdfConfiguration.php
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Services\Pdf;
|
||||||
|
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use App\Models\Quote;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\Design;
|
||||||
|
use App\Models\Vendor;
|
||||||
|
use App\Models\Country;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Currency;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\PurchaseOrder;
|
||||||
|
use App\Models\VendorContact;
|
||||||
|
use App\Utils\Traits\AppSetup;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use App\Models\PurchaseOrderInvitation;
|
||||||
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class PdfConfiguration
|
||||||
|
{
|
||||||
|
use MakesHash, AppSetup;
|
||||||
|
|
||||||
|
public ?Client $client;
|
||||||
|
|
||||||
|
public ?ClientContact $contact;
|
||||||
|
|
||||||
|
public Country $country;
|
||||||
|
|
||||||
|
public Currency $currency;
|
||||||
|
|
||||||
|
public Client | Vendor $currency_entity;
|
||||||
|
|
||||||
|
public Design $design;
|
||||||
|
|
||||||
|
public Invoice | Credit | Quote | PurchaseOrder $entity;
|
||||||
|
|
||||||
|
public string $entity_design_id;
|
||||||
|
|
||||||
|
public string $entity_string;
|
||||||
|
|
||||||
|
public ?string $path;
|
||||||
|
|
||||||
|
public array $pdf_variables;
|
||||||
|
|
||||||
|
public object $settings;
|
||||||
|
|
||||||
|
public $settings_object;
|
||||||
|
|
||||||
|
public ?Vendor $vendor;
|
||||||
|
|
||||||
|
public ?VendorContact $vendor_contact;
|
||||||
|
|
||||||
|
public string $date_format;
|
||||||
|
|
||||||
|
public string $locale;
|
||||||
|
|
||||||
|
public Collection $tax_map;
|
||||||
|
|
||||||
|
public ?array $total_tax_map;
|
||||||
|
/**
|
||||||
|
* __construct
|
||||||
|
*
|
||||||
|
* @param PdfService $service
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(public PdfService $service)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function init(): self
|
||||||
|
{
|
||||||
|
$this->setEntityType()
|
||||||
|
->setDateFormat()
|
||||||
|
->setPdfVariables()
|
||||||
|
->setDesign()
|
||||||
|
->setCurrencyForPdf()
|
||||||
|
->setLocale();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setLocale
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function setLocale(): self
|
||||||
|
{
|
||||||
|
App::forgetInstance('translator');
|
||||||
|
|
||||||
|
$t = app('translator');
|
||||||
|
|
||||||
|
App::setLocale($this->settings_object->locale());
|
||||||
|
|
||||||
|
$t->replace(Ninja::transformTranslations($this->settings));
|
||||||
|
|
||||||
|
$this->locale = $this->settings_object->locale();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setCurrency
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function setCurrencyForPdf(): self
|
||||||
|
{
|
||||||
|
$this->currency = $this->client ? $this->client->currency() : $this->vendor->currency();
|
||||||
|
|
||||||
|
$this->currency_entity = $this->client ? $this->client : $this->vendor;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setPdfVariables
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setPdfVariables() :self
|
||||||
|
{
|
||||||
|
$default = (array) CompanySettings::getEntityVariableDefaults();
|
||||||
|
|
||||||
|
// $variables = (array)$this->service->company->settings->pdf_variables;
|
||||||
|
$variables = (array)$this->settings->pdf_variables;
|
||||||
|
|
||||||
|
foreach ($default as $property => $value) {
|
||||||
|
if (array_key_exists($property, $variables)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$variables[$property] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->pdf_variables = $variables;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setEntityType
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function setEntityType(): self
|
||||||
|
{
|
||||||
|
$entity_design_id = '';
|
||||||
|
|
||||||
|
if ($this->service->invitation instanceof InvoiceInvitation) {
|
||||||
|
$this->entity = $this->service->invitation->invoice;
|
||||||
|
$this->entity_string = 'invoice';
|
||||||
|
$this->client = $this->entity->client;
|
||||||
|
$this->contact = $this->service->invitation->contact;
|
||||||
|
$this->path = $this->client->invoice_filepath($this->service->invitation);
|
||||||
|
$this->entity_design_id = 'invoice_design_id';
|
||||||
|
$this->settings = $this->client->getMergedSettings();
|
||||||
|
$this->settings_object = $this->client;
|
||||||
|
$this->country = $this->client->country;
|
||||||
|
} elseif ($this->service->invitation instanceof QuoteInvitation) {
|
||||||
|
$this->entity = $this->service->invitation->quote;
|
||||||
|
$this->entity_string = 'quote';
|
||||||
|
$this->client = $this->entity->client;
|
||||||
|
$this->contact = $this->service->invitation->contact;
|
||||||
|
$this->path = $this->client->quote_filepath($this->service->invitation);
|
||||||
|
$this->entity_design_id = 'quote_design_id';
|
||||||
|
$this->settings = $this->client->getMergedSettings();
|
||||||
|
$this->settings_object = $this->client;
|
||||||
|
$this->country = $this->client->country;
|
||||||
|
} elseif ($this->service->invitation instanceof CreditInvitation) {
|
||||||
|
$this->entity = $this->service->invitation->credit;
|
||||||
|
$this->entity_string = 'credit';
|
||||||
|
$this->client = $this->entity->client;
|
||||||
|
$this->contact = $this->service->invitation->contact;
|
||||||
|
$this->path = $this->client->credit_filepath($this->service->invitation);
|
||||||
|
$this->entity_design_id = 'credit_design_id';
|
||||||
|
$this->settings = $this->client->getMergedSettings();
|
||||||
|
$this->settings_object = $this->client;
|
||||||
|
$this->country = $this->client->country;
|
||||||
|
} elseif ($this->service->invitation instanceof RecurringInvoiceInvitation) {
|
||||||
|
$this->entity = $this->service->invitation->recurring_invoice;
|
||||||
|
$this->entity_string = 'recurring_invoice';
|
||||||
|
$this->client = $this->entity->client;
|
||||||
|
$this->contact = $this->service->invitation->contact;
|
||||||
|
$this->path = $this->client->recurring_invoice_filepath($this->service->invitation);
|
||||||
|
$this->entity_design_id = 'invoice_design_id';
|
||||||
|
$this->settings = $this->client->getMergedSettings();
|
||||||
|
$this->settings_object = $this->client;
|
||||||
|
$this->country = $this->client->country;
|
||||||
|
} elseif ($this->service->invitation instanceof PurchaseOrderInvitation) {
|
||||||
|
$this->entity = $this->service->invitation->purchase_order;
|
||||||
|
$this->entity_string = 'purchase_order';
|
||||||
|
$this->vendor = $this->entity->vendor;
|
||||||
|
$this->vendor_contact = $this->service->invitation->contact;
|
||||||
|
$this->path = $this->vendor->purchase_order_filepath($this->service->invitation);
|
||||||
|
$this->entity_design_id = 'invoice_design_id';
|
||||||
|
$this->entity_design_id = 'purchase_order_design_id';
|
||||||
|
$this->settings = $this->vendor->company->settings;
|
||||||
|
$this->settings_object = $this->vendor;
|
||||||
|
$this->client = null;
|
||||||
|
$this->country = $this->vendor->country ?: $this->vendor->company->country();
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Unable to resolve entity', 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setTaxMap($this->entity->calc()->getTaxMap());
|
||||||
|
$this->setTotalTaxMap($this->entity->calc()->getTotalTaxMap());
|
||||||
|
|
||||||
|
$this->path = $this->path.$this->entity->numberFormatter().'.pdf';
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTaxMap($map): self
|
||||||
|
{
|
||||||
|
$this->tax_map = $map;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTotalTaxMap($map): self
|
||||||
|
{
|
||||||
|
$this->total_tax_map = $map;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCurrency(Currency $currency): self
|
||||||
|
{
|
||||||
|
$this->currency = $currency;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCountry(Country $country): self
|
||||||
|
{
|
||||||
|
$this->country = $country;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setDesign
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function setDesign(): self
|
||||||
|
{
|
||||||
|
$design_id = $this->entity->design_id ? : $this->decodePrimaryKey($this->settings_object->getSetting($this->entity_design_id));
|
||||||
|
|
||||||
|
$this->design = Design::find($design_id ?: 2);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* formatMoney
|
||||||
|
*
|
||||||
|
* @param float $value
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function formatMoney($value): string
|
||||||
|
{
|
||||||
|
$value = floatval($value);
|
||||||
|
|
||||||
|
$thousand = $this->currency->thousand_separator;
|
||||||
|
$decimal = $this->currency->decimal_separator;
|
||||||
|
$precision = $this->currency->precision;
|
||||||
|
$code = $this->currency->code;
|
||||||
|
$swapSymbol = $this->currency->swap_currency_symbol;
|
||||||
|
|
||||||
|
if (isset($this->country->thousand_separator) && strlen($this->country->thousand_separator) >= 1) {
|
||||||
|
$thousand = $this->country->thousand_separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->country->decimal_separator) && strlen($this->country->decimal_separator) >= 1) {
|
||||||
|
$decimal = $this->country->decimal_separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->country->swap_currency_symbol) && strlen($this->country->swap_currency_symbol) >= 1) {
|
||||||
|
$swapSymbol = $this->country->swap_currency_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = number_format($value, $precision, $decimal, $thousand);
|
||||||
|
$symbol = $this->currency->symbol;
|
||||||
|
|
||||||
|
if ($this->settings->show_currency_code === true && $this->currency->code == 'CHF') {
|
||||||
|
return "{$code} {$value}";
|
||||||
|
} elseif ($this->settings->show_currency_code === true) {
|
||||||
|
return "{$value} {$code}";
|
||||||
|
} elseif ($swapSymbol) {
|
||||||
|
return "{$value} ".trim($symbol);
|
||||||
|
} elseif ($this->settings->show_currency_code === false) {
|
||||||
|
return "{$symbol}{$value}";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$value = floatval($value);
|
||||||
|
$thousand = $this->currency->thousand_separator;
|
||||||
|
$decimal = $this->currency->decimal_separator;
|
||||||
|
$precision = $this->currency->precision;
|
||||||
|
|
||||||
|
return number_format($value, $precision, $decimal, $thousand);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* date_format
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function setDateFormat(): self
|
||||||
|
{
|
||||||
|
$date_formats = Cache::get('date_formats');
|
||||||
|
|
||||||
|
if (! $date_formats) {
|
||||||
|
$this->buildCache(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->date_format = $date_formats->filter(function ($item) {
|
||||||
|
return $item->id == $this->settings->date_format_id;
|
||||||
|
})->first()->format;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
73
app/Services/Pdf/PdfDesigner.php
Normal file
73
app/Services/Pdf/PdfDesigner.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Services\Pdf;
|
||||||
|
|
||||||
|
class PdfDesigner
|
||||||
|
{
|
||||||
|
const BOLD = 'bold';
|
||||||
|
const BUSINESS = 'business';
|
||||||
|
const CLEAN = 'clean';
|
||||||
|
const CREATIVE = 'creative';
|
||||||
|
const ELEGANT = 'elegant';
|
||||||
|
const HIPSTER = 'hipster';
|
||||||
|
const MODERN = 'modern';
|
||||||
|
const PLAIN = 'plain';
|
||||||
|
const PLAYFUL = 'playful';
|
||||||
|
const CUSTOM = 'custom';
|
||||||
|
const CALM = 'calm';
|
||||||
|
|
||||||
|
const DELIVERY_NOTE = 'delivery_note';
|
||||||
|
const STATEMENT = 'statement';
|
||||||
|
const PURCHASE_ORDER = 'purchase_order';
|
||||||
|
|
||||||
|
public string $template;
|
||||||
|
|
||||||
|
public function __construct(public PdfService $service)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function build() :self
|
||||||
|
{
|
||||||
|
/*If the design is custom*/
|
||||||
|
if ($this->service->config->design->is_custom) {
|
||||||
|
$this->template = $this->composeFromPartials(json_decode(json_encode($this->service->config->design->design), true));
|
||||||
|
} else {
|
||||||
|
$this->template = file_get_contents(config('ninja.designs.base_path') . strtolower($this->service->config->design->name) . '.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the user has implemented a custom design, then we need to rebuild the design at this point
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the custom HTML design as
|
||||||
|
* a string
|
||||||
|
*
|
||||||
|
* @param array
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private function composeFromPartials(array $partials) :string
|
||||||
|
{
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
$html .= $partials['includes'];
|
||||||
|
$html .= $partials['header'];
|
||||||
|
$html .= $partials['body'];
|
||||||
|
$html .= $partials['footer'];
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
}
|
665
app/Services/Pdf/PdfMock.php
Normal file
665
app/Services/Pdf/PdfMock.php
Normal file
File diff suppressed because one or more lines are too long
157
app/Services/Pdf/PdfService.php
Normal file
157
app/Services/Pdf/PdfService.php
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Services\Pdf;
|
||||||
|
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Utils\HtmlEngine;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Utils\VendorHtmlEngine;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
|
use App\Utils\PhantomJS\Phantom;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Services\Pdf\PdfDesigner;
|
||||||
|
use App\Utils\HostedPDF\NinjaPdf;
|
||||||
|
use App\Utils\Traits\Pdf\PdfMaker;
|
||||||
|
use App\Models\PurchaseOrderInvitation;
|
||||||
|
use App\Utils\Traits\Pdf\PageNumbering;
|
||||||
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
|
|
||||||
|
class PdfService
|
||||||
|
{
|
||||||
|
use PdfMaker, PageNumbering;
|
||||||
|
|
||||||
|
public InvoiceInvitation | QuoteInvitation | CreditInvitation | RecurringInvoiceInvitation | PurchaseOrderInvitation $invitation;
|
||||||
|
|
||||||
|
public Company $company;
|
||||||
|
|
||||||
|
public Account $account;
|
||||||
|
|
||||||
|
public PdfConfiguration $config;
|
||||||
|
|
||||||
|
public PdfBuilder $builder;
|
||||||
|
|
||||||
|
public PdfDesigner $designer;
|
||||||
|
|
||||||
|
public array $html_variables;
|
||||||
|
|
||||||
|
public string $document_type;
|
||||||
|
|
||||||
|
public array $options;
|
||||||
|
|
||||||
|
const DELIVERY_NOTE = 'delivery_note';
|
||||||
|
const STATEMENT = 'statement';
|
||||||
|
const PURCHASE_ORDER = 'purchase_order';
|
||||||
|
const PRODUCT = 'product';
|
||||||
|
|
||||||
|
public function __construct($invitation, $document_type = 'product', $options = [])
|
||||||
|
{
|
||||||
|
$this->invitation = $invitation;
|
||||||
|
|
||||||
|
$this->company = $invitation->company;
|
||||||
|
|
||||||
|
$this->account = $this->company->account;
|
||||||
|
|
||||||
|
$this->document_type = $document_type;
|
||||||
|
|
||||||
|
$this->options = $options;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the PDF generation type and
|
||||||
|
* attempts to generate a PDF from the HTML
|
||||||
|
* string.
|
||||||
|
*
|
||||||
|
* @return mixed | Exception
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getPdf()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
$pdf = $this->resolvePdfEngine();
|
||||||
|
|
||||||
|
$numbered_pdf = $this->pageNumbering($pdf, $this->company);
|
||||||
|
|
||||||
|
if ($numbered_pdf) {
|
||||||
|
$pdf = $numbered_pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
nlog(print_r($e->getMessage(), 1));
|
||||||
|
throw new \Exception($e->getMessage(), $e->getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the dom document to HTML
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getHtml(): string
|
||||||
|
{
|
||||||
|
$html = $this->builder->getCompiledHTML();
|
||||||
|
|
||||||
|
if (config('ninja.log_pdf_html')) {
|
||||||
|
info($html);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all the services to build the PDF
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function init(): self
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->config = (new PdfConfiguration($this))->init();
|
||||||
|
|
||||||
|
|
||||||
|
$this->html_variables = $this->config->client ?
|
||||||
|
(new HtmlEngine($this->invitation))->generateLabelsAndValues() :
|
||||||
|
(new VendorHtmlEngine($this->invitation))->generateLabelsAndValues();
|
||||||
|
|
||||||
|
$this->designer = (new PdfDesigner($this))->build();
|
||||||
|
|
||||||
|
$this->builder = (new PdfBuilder($this))->build();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resolvePdfEngine
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
private function resolvePdfEngine(): mixed
|
||||||
|
{
|
||||||
|
|
||||||
|
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
||||||
|
$pdf = (new Phantom)->convertHtmlToPdf($this->getHtml());
|
||||||
|
} elseif (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
|
||||||
|
$pdf = (new NinjaPdf())->build($this->getHtml());
|
||||||
|
} else {
|
||||||
|
$pdf = $this->makePdf(null, null, $this->getHtml());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -175,10 +175,6 @@ class Design extends BaseDesign
|
|||||||
$this->sharedFooterElements(),
|
$this->sharedFooterElements(),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
// 'swiss-qr' => [
|
|
||||||
// 'id' => 'swiss-qr',
|
|
||||||
// 'elements' => $this->swissQrCodeElement(),
|
|
||||||
// ]
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ class Helpers
|
|||||||
* Process reserved keywords on PDF.
|
* Process reserved keywords on PDF.
|
||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
* @param Client|Company $entity
|
* @param Client|Company|Vendor $entity
|
||||||
* @param null|Carbon $currentDateTime
|
* @param null|Carbon $currentDateTime
|
||||||
* @return null|string
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +26,12 @@ class VendorContactFactory extends Factory
|
|||||||
'first_name' => $this->faker->firstName(),
|
'first_name' => $this->faker->firstName(),
|
||||||
'last_name' => $this->faker->lastName(),
|
'last_name' => $this->faker->lastName(),
|
||||||
'phone' => $this->faker->phoneNumber(),
|
'phone' => $this->faker->phoneNumber(),
|
||||||
|
'email_verified_at' => now(),
|
||||||
'email' => $this->faker->unique()->safeEmail(),
|
'email' => $this->faker->unique()->safeEmail(),
|
||||||
|
'send_email' => true,
|
||||||
|
'password' => bcrypt('password'),
|
||||||
|
'remember_token' => \Illuminate\Support\Str::random(10),
|
||||||
|
'contact_key' => \Illuminate\Support\Str::random(32),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ use Tests\TestCase;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
//@covers App\DataMapper\BaseSettings
|
* @covers App\DataMapper\BaseSettings
|
||||||
*/
|
*/
|
||||||
class PdfGenerationTest extends TestCase
|
class PdfGenerationTest extends TestCase
|
||||||
{
|
{
|
||||||
|
111
tests/Pdf/PdfServiceTest.php
Normal file
111
tests/Pdf/PdfServiceTest.php
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tests\Pdf;
|
||||||
|
|
||||||
|
use App\Services\Pdf\PdfConfiguration;
|
||||||
|
use App\Services\Pdf\PdfService;
|
||||||
|
use Beganovich\Snappdf\Snappdf;
|
||||||
|
use Tests\MockAccountData;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @covers App\Services\Pdf\PdfService
|
||||||
|
*/
|
||||||
|
class PdfServiceTest extends TestCase
|
||||||
|
{
|
||||||
|
use MockAccountData;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->makeTestData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPdfGeneration()
|
||||||
|
{
|
||||||
|
|
||||||
|
$invitation = $this->invoice->invitations->first();
|
||||||
|
|
||||||
|
$service = new PdfService($invitation);
|
||||||
|
|
||||||
|
$this->assertNotNull($service->getPdf());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHtmlGeneration()
|
||||||
|
{
|
||||||
|
|
||||||
|
$invitation = $this->invoice->invitations->first();
|
||||||
|
|
||||||
|
$service = new PdfService($invitation);
|
||||||
|
|
||||||
|
$this->assertIsString($service->getHtml());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInitOfClass()
|
||||||
|
{
|
||||||
|
|
||||||
|
$invitation = $this->invoice->invitations->first();
|
||||||
|
|
||||||
|
$service = new PdfService($invitation);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(PdfService::class, $service);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEntityResolution()
|
||||||
|
{
|
||||||
|
|
||||||
|
$invitation = $this->invoice->invitations->first();
|
||||||
|
|
||||||
|
$service = new PdfService($invitation);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(PdfConfiguration::class, $service->config);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDefaultDesign()
|
||||||
|
{
|
||||||
|
$invitation = $this->invoice->invitations->first();
|
||||||
|
|
||||||
|
$service = new PdfService($invitation);
|
||||||
|
|
||||||
|
$this->assertEquals(2, $service->config->design->id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHtmlIsArray()
|
||||||
|
{
|
||||||
|
$invitation = $this->invoice->invitations->first();
|
||||||
|
|
||||||
|
$service = new PdfService($invitation);
|
||||||
|
|
||||||
|
$this->assertIsArray($service->html_variables);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testTemplateResolution()
|
||||||
|
{
|
||||||
|
$invitation = $this->invoice->invitations->first();
|
||||||
|
|
||||||
|
$service = new PdfService($invitation);
|
||||||
|
|
||||||
|
$this->assertIsString($service->designer->template);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
99
tests/Pdf/PdfmockTest.php
Normal file
99
tests/Pdf/PdfmockTest.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tests\Pdf;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use App\Models\Design;
|
||||||
|
use App\Models\Country;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Currency;
|
||||||
|
use App\Services\Pdf\PdfBuilder;
|
||||||
|
use Tests\MockAccountData;
|
||||||
|
use App\Services\Pdf\PdfMock;
|
||||||
|
use Beganovich\Snappdf\Snappdf;
|
||||||
|
use App\Services\Pdf\PdfService;
|
||||||
|
use App\Services\Pdf\PdfConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @covers App\Services\Pdf\PdfService
|
||||||
|
*/
|
||||||
|
class PdfmockTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPdfInstance ()
|
||||||
|
{
|
||||||
|
|
||||||
|
$entity = (new \App\Services\Pdf\PdfMock())->build();
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Invoice::class, $entity);
|
||||||
|
$this->assertNotNull($entity->client);
|
||||||
|
|
||||||
|
|
||||||
|
$pdf_service = new PdfService($entity->invitation);
|
||||||
|
|
||||||
|
$this->assertNotNull($pdf_service);
|
||||||
|
|
||||||
|
$pdf_config = (new PdfConfiguration($pdf_service));
|
||||||
|
|
||||||
|
$this->assertNotNull($pdf_config);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHtmlGeneration()
|
||||||
|
{
|
||||||
|
$pdf_mock = (new PdfMock());
|
||||||
|
$mock = $pdf_mock->build();
|
||||||
|
|
||||||
|
$pdf_service = new PdfService($mock->invitation);
|
||||||
|
|
||||||
|
$pdf_config = (new PdfConfiguration($pdf_service));
|
||||||
|
$pdf_config->entity = $mock;
|
||||||
|
$pdf_config->setTaxMap($mock->tax_map);
|
||||||
|
$pdf_config->setTotalTaxMap($mock->total_tax_map);
|
||||||
|
$pdf_config->setCurrency(Currency::find(1));
|
||||||
|
$pdf_config->setCountry(Country::find(840));
|
||||||
|
$pdf_config->client = $mock->client;
|
||||||
|
$pdf_config->entity_design_id = 'invoice_design_id';
|
||||||
|
$pdf_config->settings_object = $mock->client;
|
||||||
|
$pdf_config->entity_string = 'invoice';
|
||||||
|
$pdf_config->settings = (object)$pdf_config->service->company->settings;
|
||||||
|
$pdf_config->setPdfVariables();
|
||||||
|
$pdf_config->design = Design::find(2);
|
||||||
|
$pdf_config->currency_entity = $mock->client;
|
||||||
|
|
||||||
|
$pdf_service->config = $pdf_config;
|
||||||
|
|
||||||
|
$pdf_designer = (new \App\Services\Pdf\PdfDesigner($pdf_service))->build();
|
||||||
|
$pdf_service->designer = $pdf_designer;
|
||||||
|
|
||||||
|
$pdf_service->html_variables = $pdf_mock->getStubVariables();
|
||||||
|
|
||||||
|
$pdf_builder = (new PdfBuilder($pdf_service))->build();
|
||||||
|
$pdf_service->builder = $pdf_builder;
|
||||||
|
$this->assertNotNull($pdf_config);
|
||||||
|
|
||||||
|
$html = $pdf_service->getHtml();
|
||||||
|
|
||||||
|
nlog($html);
|
||||||
|
$this->assertNotNull($html);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user