From ae7915353ff9ee5cf02badc3ecfa38234993fd1f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 25 Sep 2023 15:56:32 +1000 Subject: [PATCH] Template scaffold --- app/Http/Controllers/PreviewController.php | 127 ++++++++++++++----- app/Services/PdfMaker/PdfMaker.php | 9 +- app/Services/Template/TemplateService.php | 132 +++++++++++++++----- app/Transformers/PaymentTransformer.php | 7 +- app/Transformers/PaymentTypeTransformer.php | 25 ++++ app/Transformers/TaskTransformer.php | 2 +- tests/Feature/Template/TemplateTest.php | 18 ++- 7 files changed, 240 insertions(+), 80 deletions(-) create mode 100644 app/Transformers/PaymentTypeTransformer.php diff --git a/app/Http/Controllers/PreviewController.php b/app/Http/Controllers/PreviewController.php index fb100b9dd12c..845521c5f2f8 100644 --- a/app/Http/Controllers/PreviewController.php +++ b/app/Http/Controllers/PreviewController.php @@ -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() { diff --git a/app/Services/PdfMaker/PdfMaker.php b/app/Services/PdfMaker/PdfMaker.php index 701222bf359e..2d028563f0a3 100644 --- a/app/Services/PdfMaker/PdfMaker.php +++ b/app/Services/PdfMaker/PdfMaker.php @@ -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); diff --git a/app/Services/Template/TemplateService.php b/app/Services/Template/TemplateService.php index 84f758882101..0eafa0c05f1c 100644 --- a/app/Services/Template/TemplateService.php +++ b/app/Services/Template/TemplateService.php @@ -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']; + } diff --git a/app/Transformers/PaymentTransformer.php b/app/Transformers/PaymentTransformer.php index cb7d038e6941..61d32bf64be8 100644 --- a/app/Transformers/PaymentTransformer.php +++ b/app/Transformers/PaymentTransformer.php @@ -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) diff --git a/app/Transformers/PaymentTypeTransformer.php b/app/Transformers/PaymentTypeTransformer.php new file mode 100644 index 000000000000..3d9aae3da634 --- /dev/null +++ b/app/Transformers/PaymentTypeTransformer.php @@ -0,0 +1,25 @@ + $payment->translatedType() + ]; + } +} diff --git a/app/Transformers/TaskTransformer.php b/app/Transformers/TaskTransformer.php index b4d50535f5fb..5791fa3e5807 100644 --- a/app/Transformers/TaskTransformer.php +++ b/app/Transformers/TaskTransformer.php @@ -55,7 +55,7 @@ class TaskTransformer extends EntityTransformer { $transformer = new InvoiceTransformer($this->serializer); - if (!$task->user) { + if (!$task->invoice) { return null; } diff --git a/tests/Feature/Template/TemplateTest.php b/tests/Feature/Template/TemplateTest.php index 1f6dc241f5e7..0d86917b54e1 100644 --- a/tests/Feature/Template/TemplateTest.php +++ b/tests/Feature/Template/TemplateTest.php @@ -102,7 +102,13 @@ class TemplateTest extends TestCase '; private string $payments_body = ' - + CoName: $company.name + ClName: $client.name + InNumber: $invoice.number + + CoName: $company.name + ClName: $client.name + InNumber: $invoice.number @@ -129,7 +135,7 @@ class TemplateTest extends TestCase {% for payment in invoice.payments|filter(payment => payment.is_deleted == false) %} {% for pivot in payment.paymentables %} - + @@ -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()); }
{{ payment.number }} {{ payment.date }}