mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Template scaffold
This commit is contained in:
parent
909d9ed9df
commit
ae7915353f
@ -11,42 +11,47 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\DataMapper\Analytics\LivePreview;
|
||||
use App\Factory\CreditFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Factory\QuoteFactory;
|
||||
use App\Factory\RecurringInvoiceFactory;
|
||||
use App\Http\Requests\Preview\DesignPreviewRequest;
|
||||
use App\Http\Requests\Preview\PreviewInvoiceRequest;
|
||||
use App\Jobs\Util\PreviewPdf;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Task;
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Models\Quote;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Repositories\CreditRepository;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Repositories\QuoteRepository;
|
||||
use App\Repositories\RecurringInvoiceRepository;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Project;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Factory\QuoteFactory;
|
||||
use App\Jobs\Util\PreviewPdf;
|
||||
use App\Models\ClientContact;
|
||||
use App\Services\Pdf\PdfMock;
|
||||
use App\Factory\CreditFactory;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Utils\PhantomJS\Phantom;
|
||||
use App\Models\InvoiceInvitation;
|
||||
use App\Services\PdfMaker\Design;
|
||||
use App\Utils\HostedPDF\NinjaPdf;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Services\PdfMaker\PdfMaker;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use App\Repositories\QuoteRepository;
|
||||
use App\Repositories\CreditRepository;
|
||||
use App\Utils\Traits\MakesInvoiceHtml;
|
||||
use Turbo124\Beacon\Facades\LightLogs;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Utils\Traits\Pdf\PageNumbering;
|
||||
use App\Factory\RecurringInvoiceFactory;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use App\DataMapper\Analytics\LivePreview;
|
||||
use App\Services\Template\TemplateService;
|
||||
use App\Repositories\RecurringInvoiceRepository;
|
||||
use App\Http\Requests\Preview\DesignPreviewRequest;
|
||||
use App\Services\PdfMaker\Design as PdfDesignModel;
|
||||
use App\Services\PdfMaker\Design as PdfMakerDesign;
|
||||
use App\Services\PdfMaker\PdfMaker;
|
||||
use App\Utils\HostedPDF\NinjaPdf;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\PhantomJS\Phantom;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\MakesInvoiceHtml;
|
||||
use App\Utils\Traits\Pdf\PageNumbering;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Turbo124\Beacon\Facades\LightLogs;
|
||||
use App\Http\Requests\Preview\PreviewInvoiceRequest;
|
||||
use App\Models\PurchaseOrder;
|
||||
|
||||
class PreviewController extends BaseController
|
||||
{
|
||||
@ -67,6 +72,11 @@ class PreviewController extends BaseController
|
||||
|
||||
public function show()
|
||||
{
|
||||
// if(request()->has('template')){
|
||||
return $this->template();
|
||||
// }
|
||||
nlog("wooops");
|
||||
|
||||
if (request()->has('entity') &&
|
||||
request()->has('entity_id') &&
|
||||
! empty(request()->input('entity')) &&
|
||||
@ -132,7 +142,6 @@ class PreviewController extends BaseController
|
||||
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
|
||||
}
|
||||
|
||||
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
@ -342,6 +351,64 @@ class PreviewController extends BaseController
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function template()
|
||||
{
|
||||
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
/** @var \App\Models\Company $company */
|
||||
$company = $user->company();
|
||||
|
||||
// $template = request()->input('design');
|
||||
$design_object = json_decode(json_encode(request()->input('design')),1);
|
||||
|
||||
$data = [
|
||||
'invoices' => Invoice::whereHas('payments')->with('client','payments')->company()->orderBy('id','desc')->take(5)->get(),
|
||||
'quotes' => Quote::query()->company()->with('client')->orderBy('id','desc')->take(5)->get(),
|
||||
'credits' => Credit::query()->company()->with('client')->orderBy('id','desc')->take(5)->get(),
|
||||
'payments' => Payment::query()->company()->with('client')->orderBy('id','desc')->take(5)->get(),
|
||||
'purchase_orders' => PurchaseOrder::query()->with('vendor')->company()->orderBy('id','desc')->take(5)->get(),
|
||||
'tasks' => Task::query()->with('client','invoice')->company()->orderBy('id','desc')->take(5)->get(),
|
||||
'projects' => Project::query()->with('tasks','client')->company()->orderBy('id','desc')->take(5)->get(),
|
||||
];
|
||||
|
||||
nlog($design_object);
|
||||
$ts = (new TemplateService());
|
||||
$ts->setTemplate($design_object)
|
||||
->build($data);
|
||||
|
||||
$html = $ts->getHtml();
|
||||
|
||||
if (request()->query('html') == 'true') {
|
||||
return $html;
|
||||
}
|
||||
|
||||
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
|
||||
return (new Phantom)->convertHtmlToPdf($html);
|
||||
}
|
||||
|
||||
if (config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja') {
|
||||
$pdf = (new NinjaPdf())->build($html);
|
||||
|
||||
$numbered_pdf = $this->pageNumbering($pdf, $company);
|
||||
|
||||
if ($numbered_pdf) {
|
||||
$pdf = $numbered_pdf;
|
||||
}
|
||||
|
||||
return $pdf;
|
||||
}
|
||||
|
||||
$file_path = (new PreviewPdf($html, $company))->handle();
|
||||
|
||||
$response = Response::make($file_path, 200);
|
||||
$response->header('Content-Type', 'application/pdf');
|
||||
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
private function blankEntity()
|
||||
{
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
namespace App\Services\PdfMaker;
|
||||
|
||||
use App\Services\Template\TemplateService;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
|
||||
class PdfMaker
|
||||
@ -78,17 +79,13 @@ class PdfMaker
|
||||
|
||||
$replacements = [];
|
||||
$contents = $this->document->getElementsByTagName('ninja');
|
||||
|
||||
$twig = (new TemplateService())->twig;
|
||||
|
||||
foreach ($contents as $content) {
|
||||
|
||||
$template = $content->ownerDocument->saveHTML($content);
|
||||
|
||||
$loader = new \Twig\Loader\FilesystemLoader(storage_path());
|
||||
$twig = new \Twig\Environment($loader);
|
||||
|
||||
$string_extension = new \Twig\Extension\StringLoaderExtension();
|
||||
$twig->addExtension($string_extension);
|
||||
|
||||
$template = $twig->createTemplate(html_entity_decode($template));
|
||||
$template = $template->render($this->options);
|
||||
|
||||
|
@ -15,7 +15,6 @@ use App\Models\Task;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Design;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Project;
|
||||
use App\Utils\HtmlEngine;
|
||||
@ -24,7 +23,6 @@ use App\Models\ClientContact;
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Utils\VendorHtmlEngine;
|
||||
use App\Utils\PaymentHtmlEngine;
|
||||
use Illuminate\Support\Collection;
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
use App\Transformers\TaskTransformer;
|
||||
use App\Transformers\QuoteTransformer;
|
||||
@ -41,9 +39,11 @@ class TemplateService
|
||||
|
||||
private \DomDocument $document;
|
||||
|
||||
public \Twig\Environment $twig;
|
||||
|
||||
private string $compiled_html = '';
|
||||
|
||||
public function __construct(public Design $template)
|
||||
public function __construct(public ?Design $template = null)
|
||||
{
|
||||
$this->template = $template;
|
||||
$this->init();
|
||||
@ -59,6 +59,12 @@ class TemplateService
|
||||
$this->document = new \DOMDocument();
|
||||
$this->document->validateOnParse = true;
|
||||
|
||||
$loader = new \Twig\Loader\FilesystemLoader(storage_path());
|
||||
$this->twig = new \Twig\Environment($loader);
|
||||
$string_extension = new \Twig\Extension\StringLoaderExtension();
|
||||
$this->twig->addExtension($string_extension);
|
||||
$this->twig->addExtension(new IntlExtension());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -93,24 +99,19 @@ class TemplateService
|
||||
{
|
||||
$data = $this->preProcessDataBlocks($data);
|
||||
$replacements = [];
|
||||
nlog($data);
|
||||
|
||||
// nlog($data);
|
||||
|
||||
$contents = $this->document->getElementsByTagName('ninja');
|
||||
|
||||
foreach ($contents as $content) {
|
||||
|
||||
$template = $content->ownerDocument->saveHTML($content);
|
||||
|
||||
$loader = new \Twig\Loader\FilesystemLoader(storage_path());
|
||||
$twig = new \Twig\Environment($loader);
|
||||
|
||||
$string_extension = new \Twig\Extension\StringLoaderExtension();
|
||||
$twig->addExtension($string_extension);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
$template = $twig->createTemplate(html_entity_decode($template));
|
||||
$template = $this->twig->createTemplate(html_entity_decode($template));
|
||||
$template = $template->render($data);
|
||||
|
||||
nlog($template);
|
||||
// nlog($template);
|
||||
|
||||
$f = $this->document->createDocumentFragment();
|
||||
$f->appendXML($template);
|
||||
@ -140,8 +141,12 @@ nlog($data);
|
||||
$html = $this->getHtml();
|
||||
|
||||
foreach($variables as $key => $variable) {
|
||||
$html = strtr($html, $variable['labels']);
|
||||
$html = strtr($html, $variable['values']);
|
||||
|
||||
if(isset($variable['labels']) && isset($variable['values']))
|
||||
{
|
||||
$html = strtr($html, $variable['labels']);
|
||||
$html = strtr($html, $variable['values']);
|
||||
}
|
||||
}
|
||||
|
||||
@$this->document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
|
||||
@ -169,6 +174,9 @@ nlog($data);
|
||||
*/
|
||||
private function compose(): self
|
||||
{
|
||||
if(!$this->template)
|
||||
return $this;
|
||||
|
||||
$html = '';
|
||||
$html .= $this->template->design->includes;
|
||||
$html .= $this->template->design->header;
|
||||
@ -181,6 +189,27 @@ nlog($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject the template components
|
||||
* manually
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setTemplate(array $partials): self
|
||||
{nlog($partials);
|
||||
|
||||
$html = '';
|
||||
$html .= $partials['design']['includes'];
|
||||
$html .= $partials['design']['header'];
|
||||
$html .= $partials['design']['body'];
|
||||
$html .= $partials['design']['footer'];
|
||||
|
||||
@$this->document->loadHTML($html);
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the labels and values needed to replace the string
|
||||
* holders in the template.
|
||||
@ -200,7 +229,7 @@ nlog($data);
|
||||
'payments' => $processed = (new PaymentHtmlEngine($value->first(), $value->first()->client->contacts()->first()))->generateLabelsAndValues(),
|
||||
'tasks' => $processed = [],
|
||||
'projects' => $processed = [],
|
||||
'purchase_orders' => $processed = (new VendorHtmlEngine($value->first()->invitations()->first()))->generateLabelsAndValues(),
|
||||
'purchase_orders' => $processed = $value->first() && $value->first()->invitations()->first() ? (new VendorHtmlEngine($value->first()->invitations()->first()))->generateLabelsAndValues() : [],
|
||||
};
|
||||
|
||||
return $processed;
|
||||
@ -251,6 +280,7 @@ nlog($data);
|
||||
if($invoice['payments']['data'] ?? false) {
|
||||
foreach($invoice['payments']['data'] as $keyx => $payment) {
|
||||
$invoices['data'][$key]['payments'][$keyx]['paymentables']= $payment['paymentables']['data'] ?? [];
|
||||
$invoices['data'][$key]['payments'][$keyx]['type']= $payment['type']['data'] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,12 +294,22 @@ nlog($data);
|
||||
$it = new QuoteTransformer();
|
||||
$it->setDefaultIncludes(['client']);
|
||||
$manager = new Manager();
|
||||
$manager->setSerializer(new ArraySerializer());
|
||||
$resource = new \League\Fractal\Resource\Collection($quotes, $it, Quote::class);
|
||||
$i = $manager->createData($resource)->toArray();
|
||||
$manager->parseIncludes(['client']);
|
||||
$resource = new \League\Fractal\Resource\Collection($quotes, $it, null);
|
||||
$resources = $manager->createData($resource)->toArray();
|
||||
|
||||
foreach($resources['data'] as $key => $resource) {
|
||||
|
||||
$resources['data'][$key]['client'] = $resource['client']['data'] ?? [];
|
||||
$resources['data'][$key]['client']['contacts'] = $resource['client']['data']['contacts']['data'] ?? [];
|
||||
|
||||
}
|
||||
|
||||
return $resources['data'];
|
||||
|
||||
|
||||
|
||||
|
||||
$i['client']['contacts'] = $i['client']['contacts'][ClientContact::class];
|
||||
return $i[Quote::class];
|
||||
|
||||
}
|
||||
|
||||
@ -278,10 +318,18 @@ nlog($data);
|
||||
$it = new CreditTransformer();
|
||||
$it->setDefaultIncludes(['client']);
|
||||
$manager = new Manager();
|
||||
$manager->setSerializer(new ArraySerializer());
|
||||
$resource = new \League\Fractal\Resource\Collection($credits, $it, Credit::class);
|
||||
$i = $manager->createData($resource)->toArray();
|
||||
return $i[Credit::class];
|
||||
$resources = $manager->createData($resource)->toArray();
|
||||
|
||||
foreach($resources['data'] as $key => $resource) {
|
||||
|
||||
$resources['data'][$key]['client'] = $resource['client']['data'] ?? [];
|
||||
$resources['data'][$key]['client']['contacts'] = $resource['client']['data']['contacts']['data'] ?? [];
|
||||
|
||||
}
|
||||
|
||||
return $resources['data'];
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -290,22 +338,40 @@ nlog($data);
|
||||
$it = new PaymentTransformer();
|
||||
$it->setDefaultIncludes(['client','invoices','paymentables']);
|
||||
$manager = new Manager();
|
||||
$manager->setSerializer(new ArraySerializer());
|
||||
$resource = new \League\Fractal\Resource\Collection($payments, $it, Payment::class);
|
||||
$i = $manager->createData($resource)->toArray();
|
||||
return $i[Payment::class];
|
||||
$resource = new \League\Fractal\Resource\Collection($payments, $it, null);
|
||||
$resources = $manager->createData($resource)->toArray();
|
||||
|
||||
foreach($resources['data'] as $key => $resource) {
|
||||
|
||||
$resources['data'][$key]['client'] = $resource['client']['data'] ?? [];
|
||||
$resources['data'][$key]['client']['contacts'] = $resource['client']['data']['contacts']['data'] ?? [];
|
||||
$resources['data'][$key]['invoices'] = $invoice['invoices']['data'] ?? [];
|
||||
|
||||
}
|
||||
|
||||
return $resources['data'];
|
||||
|
||||
}
|
||||
|
||||
private function processTasks($tasks): array
|
||||
{
|
||||
$it = new TaskTransformer();
|
||||
$it->setDefaultIncludes(['client','tasks','project','invoice']);
|
||||
$it->setDefaultIncludes(['client','project','invoice']);
|
||||
$manager = new Manager();
|
||||
$manager->setSerializer(new ArraySerializer());
|
||||
$resource = new \League\Fractal\Resource\Collection($tasks, $it, Task::class);
|
||||
$i = $manager->createData($resource)->toArray();
|
||||
return $i[Task::class];
|
||||
$resource = new \League\Fractal\Resource\Collection($tasks, $it, null);
|
||||
$resources = $manager->createData($resource)->toArray();
|
||||
|
||||
foreach($resources['data'] as $key => $resource) {
|
||||
|
||||
$resources['data'][$key]['client'] = $resource['client']['data'] ?? [];
|
||||
$resources['data'][$key]['client']['contacts'] = $resource['client']['data']['contacts']['data'] ?? [];
|
||||
$resources['data'][$key]['project'] = $resource['project']['data'] ?? [];
|
||||
$resources['data'][$key]['invoice'] = $resource['invoice'] ?? [];
|
||||
|
||||
}
|
||||
|
||||
return $resources['data'];
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -12,10 +12,11 @@
|
||||
namespace App\Transformers;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Document;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Document;
|
||||
use App\Models\Paymentable;
|
||||
use App\Models\PaymentType;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class PaymentTransformer extends EntityTransformer
|
||||
@ -72,9 +73,7 @@ class PaymentTransformer extends EntityTransformer
|
||||
|
||||
public function includeType(Payment $payment)
|
||||
{
|
||||
return [
|
||||
'type' => $payment->type->translatedType() ?? '',
|
||||
];
|
||||
return $this->includeItem($payment, new PaymentTypeTransformer, PaymentType::class);
|
||||
}
|
||||
|
||||
public function transform(Payment $payment)
|
||||
|
25
app/Transformers/PaymentTypeTransformer.php
Normal file
25
app/Transformers/PaymentTypeTransformer.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Transformers;
|
||||
|
||||
use App\Models\Payment;
|
||||
|
||||
class PaymentTypeTransformer extends EntityTransformer
|
||||
{
|
||||
|
||||
public function transform(Payment $payment)
|
||||
{
|
||||
return [
|
||||
'name' => $payment->translatedType()
|
||||
];
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ class TaskTransformer extends EntityTransformer
|
||||
{
|
||||
$transformer = new InvoiceTransformer($this->serializer);
|
||||
|
||||
if (!$task->user) {
|
||||
if (!$task->invoice) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,13 @@ class TemplateTest extends TestCase
|
||||
';
|
||||
|
||||
private string $payments_body = '
|
||||
<ninja>
|
||||
CoName: $company.name
|
||||
ClName: $client.name
|
||||
InNumber: $invoice.number
|
||||
<ninja>
|
||||
CoName: $company.name
|
||||
ClName: $client.name
|
||||
InNumber: $invoice.number
|
||||
<table class="min-w-full text-left text-sm font-light">
|
||||
<thead class="border-b font-medium dark:border-neutral-500">
|
||||
<tr class="text-sm leading-normal">
|
||||
@ -129,7 +135,7 @@ class TemplateTest extends TestCase
|
||||
{% for payment in invoice.payments|filter(payment => payment.is_deleted == false) %}
|
||||
|
||||
{% for pivot in payment.paymentables %}
|
||||
|
||||
|
||||
<tr class="border-b dark:border-neutral-500">
|
||||
<td class="whitespace-nowrap px-6 py-4 font-medium">{{ payment.number }}</td>
|
||||
<td class="whitespace-nowrap px-6 py-4 font-medium">{{ payment.date }}</td>
|
||||
@ -221,8 +227,8 @@ class TemplateTest extends TestCase
|
||||
$data['invoices'] = $invoices;
|
||||
$ts = $replicated_design->service()->build($data);
|
||||
|
||||
nlog("results = ");
|
||||
nlog($ts->getHtml());
|
||||
// nlog("results = ");
|
||||
// nlog($ts->getHtml());
|
||||
$this->assertNotNull($ts->getHtml());
|
||||
|
||||
}
|
||||
@ -253,8 +259,8 @@ class TemplateTest extends TestCase
|
||||
|
||||
$ts = $replicated_design->service()->build($data);
|
||||
|
||||
nlog("results = ");
|
||||
nlog($ts->getHtml());
|
||||
// nlog("results = ");
|
||||
// nlog($ts->getHtml());
|
||||
$this->assertNotNull($ts->getHtml());
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user