1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 13:12:50 +01:00

Refactor Designs (#3449)

* Refactor custom invoice HTML generation

* remove table_styles() method from designs

* Refactor designs

* Clean up designs
This commit is contained in:
David Bomba 2020-03-07 17:31:26 +11:00 committed by GitHub
parent e095b8538f
commit d13ab48d86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 385 additions and 323 deletions

View File

@ -13,18 +13,16 @@ namespace App\Designs;
abstract class AbstractDesign
{
abstract public function include();
abstract public function includes();
abstract public function header();
abstract public function body();
abstract public function product_table();
abstract public function product();
abstract public function task_table();
abstract public function task();
abstract public function footer();
abstract public function table_styles();
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,41 +13,37 @@ namespace App\Designs;
class Custom extends AbstractDesign
{
private $include;
private $includes;
private $header;
private $body;
private $product_table;
private $product;
private $task_table;
private $task;
private $footer;
private $table_styles;
public function __construct($design)
{
$this->include = $design->include;
$this->includes = $design->includes;
$this->header = $design->header;
$this->body = $design->body;
$this->product_table = $design->product_table;
$this->product = $design->product;
$this->task_table = $design->task_table;
$this->task = $design->task;
$this->footer = $design->footer;
$this->table_styles = $design->table_styles;
}
public function include()
public function includes()
{
return $this->include;
return $this->includes;
}
public function header()
@ -64,23 +60,16 @@ class Custom extends AbstractDesign
}
public function table_styles()
public function product()
{
return $this->table_styles;
return $this->product;
}
public function product_table()
public function task()
{
return $this->product_table;
}
public function task_table()
{
return $this->task_table;
return $this->task;
}
public function footer()

View File

@ -16,7 +16,9 @@ use App\Models\Invoice;
class Designer {
protected $design;
public $design;
public $design_name;
protected $input_variables;
@ -55,7 +57,9 @@ class Designer {
{
$this->entity = $entity;
$this->design = $design;
$this->design = $design->design;
$this->design_name = lcfirst($design->name);
$this->input_variables = (array) $input_variables;
@ -73,7 +77,7 @@ class Designer {
$this->setHtml()
->exportVariables()
->setDesign($this->getSection('include'))
->setDesign($this->getSection('includes'))
->setDesign($this->getSection('header'))
->setDesign($this->getSection('body'))
->setDesign($this->getProductTable($this->entity))
@ -91,11 +95,17 @@ class Designer {
return $this;
}
public function getIncludes()
{
$this->setDesign($this->getSection('includes'));
return $this;
}
public function getHeader()
{
$this->setDesign($this->getSection('include'))
->setDesign($this->getSection('header'));
$this->setDesign($this->getSection('header'));
return $this;
}
@ -111,9 +121,7 @@ class Designer {
public function getBody()
{
$this->setDesign($this->getSection('include'))
->setDesign($this->getSection('body'))
->setDesign($this->getProductTable());
$this->setDesign($this->getSection('body'));
return $this;
}
@ -121,11 +129,24 @@ class Designer {
public function getProductTable():string
{
$table_header = $this->entity->table_header($this->input_variables['product_columns'], $this->design->table_styles());
$table_body = $this->entity->table_body($this->input_variables['product_columns'], $this->design->table_styles());
$table_header = $this->entity->table_header($this->input_variables['product_columns']);
$table_body = $this->entity->table_body($this->input_variables['product_columns']);
$data = str_replace('$table_header', $table_header, $this->getSection('product_table'));
$data = str_replace('$table_body', $table_body, $data);
$data = str_replace('$product_table_header', $table_header, $this->getSection('product'));
$data = str_replace('$product_table_body', $table_body, $data);
return $data;
}
public function getTaskTable():string
{
$table_header = $this->entity->table_header($this->input_variables['task_columns']);
$table_body = $this->entity->table_body($this->input_variables['task_columns']);
$data = str_replace('$task_table_header', $table_header, $this->getSection('task'));
$data = str_replace('$task_table_body', $table_body, $data);
return $data;
@ -160,7 +181,7 @@ class Designer {
*/
public function getSection($section):string
{
return str_replace(array_keys($this->exported_variables), array_values($this->exported_variables), $this->design->{$section}());
return str_replace(array_keys($this->exported_variables), array_values($this->exported_variables), $this->design->{$section});
}
private function exportVariables()
@ -366,7 +387,7 @@ class Designer {
foreach (self::$custom_fields as $cf) {
if (!property_exists($custom_fields, $cf) || (strlen($custom_fields->{ $cf}) == 0)) {
if (!property_exists($custom_fields, $cf) || (strlen($custom_fields->{$cf}) == 0)) {
unset($data[$cf]);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -186,7 +186,7 @@ class CreditController extends BaseController
{
$client = Client::find($request->input('client_id'));
$credit = $this->credit_repository->save($request->all(), $client->setCreditDefaults());
$credit = $this->credit_repository->save($request->all(), CreditFactory::create(auth()->user()->company()->id, auth()->user()->id));
$credit = StoreCredit::dispatchNow($credit, $request->all(), $credit->company);

View File

@ -205,7 +205,7 @@ class QuoteController extends BaseController
{
$client = Client::find($request->input('client_id'));
$quote = $this->quote_repo->save($request->all(), $client->setQuoteDefaults());
$quote = $this->quote_repo->save($request->all(), QuoteFactory::create(auth()->user()->company()->id, auth()->user()->id));
return $this->itemResponse($quote);
}

View File

@ -79,18 +79,11 @@ class CreateCreditPdf implements ShouldQueue {
$design = Design::find($this->decodePrimaryKey($this->credit->client->getSetting('credit_design_id')));
if($design->is_custom){
$credit_design = new Custom($design->design);
}
else{
$class = 'App\Designs\\'.$design->name;
$credit_design = new $class();
}
$designer = new Designer($this->credit, $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 = $this->generateInvoiceHtml($designer->build()->getHtml(), $this->credit, $this->contact);
// $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);

View File

@ -77,18 +77,12 @@ class CreateInvoicePdf implements ShouldQueue {
$design = Design::find($this->decodePrimaryKey($this->invoice->client->getSetting('invoice_design_id')));
if($design->is_custom){
$invoice_design = new Custom($design->design);
}
else{
$class = 'App\Designs\\'.$design->name;
$invoice_design = new $class();
}
$designer = new Designer($this->invoice, $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 = $this->generateInvoiceHtml($designer->build()->getHtml(), $this->invoice, $this->contact);
//$html = $this->generateInvoiceHtml($designer->build()->getHtml(), $this->invoice, $this->contact);
$html = $this->generateEntityHtml($designer, $this->invoice, $this->contact);
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
Storage::makeDirectory($path, 0755);

View File

@ -79,15 +79,7 @@ class CreateQuotePdf implements ShouldQueue {
$design = Design::find($this->decodePrimaryKey($this->quote->client->getSetting('quote_design_id')));
if($design->is_custom){
$quote_design = new Custom($design->design);
}
else{
$class = 'App\Designs\\'.$design->name;
$quote_design = new $class();
}
$designer = new Designer($this->quote, $quote_design, $this->quote->client->getSetting('pdf_variables'), 'quote');
$designer = new Designer($this->quote, $design, $this->quote->client->getSetting('pdf_variables'), 'quote');
//todo - move this to the client creation stage so we don't keep hitting this unnecessarily
Storage::makeDirectory($path, 0755);
@ -123,7 +115,8 @@ class CreateQuotePdf implements ShouldQueue {
//get invoice design
$html = $this->generateInvoiceHtml($design_body, $this->quote, $this->contact);
// $html = $this->generateInvoiceHtml($design_body, $this->quote, $this->contact);
$html = $this->generateEntityHtml($designer, $this->quote, $this->contact);
$pdf = $this->makePdf($all_pages_header, $all_pages_footer, $html);
$file_path = $path . $quote_number . '.pdf';

View File

@ -134,8 +134,6 @@ class Import implements ShouldQueue
throw new ResourceNotAvailableForMigration("Resource {$key} is not available for migration.");
}
\Log::error($key);
$method = sprintf("process%s", Str::ucfirst(Str::camel($key)));
$this->{$method}($resource);

View File

@ -468,10 +468,10 @@ class Client extends BaseModel implements HasLocalePreference
public function setCompanyDefaults($data, $entity_name)
{
if(strlen($data['terms']) == 0)
if(isset($data['terms']) && strlen($data['terms']) == 0)
$data['terms'] = $this->getSetting($entity_name.'_terms');
if(strlen($data['footer']) == 0)
if(isset($data['footer']) && strlen($data['footer']) == 0)
$data['footer'] = $this->getSetting($entity_name.'_footer');
if(strlen($this->public_notes) >=1)

View File

@ -188,7 +188,10 @@ class BaseRepository
{
$class = new ReflectionClass($model);
if(array_key_exists('client_id', $data))
$client = Client::find($data['client_id']);
else
$client = Client::find($model->client_id);
$state = [];
$resource = explode('\\', $class->name)[2]; /** This will extract 'Invoice' from App\Models\Invoice */
@ -202,8 +205,6 @@ class BaseRepository
$model->uses_inclusive_taxes = $client->getSetting('inclusive_taxes');
}
\Log::error(print_r($data,1));
$model->fill($data);
$model->save();

View File

@ -11,6 +11,7 @@
namespace App\Utils\Traits;
use App\Designs\Designer;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Blade;
use Symfony\Component\Debug\Exception\FatalThrowableError;
@ -47,12 +48,51 @@ trait MakesInvoiceHtml
$design = str_replace(array_keys($values), array_values($values), $design);
$data['invoice'] = $invoice;
$data['lang'] = $client->preferredLocale();
return $this->renderView($design, $data);
//return view($design, $data)->render();
}
public function generateEntityHtml(Designer $designer, $entity, $contact = null) :string
{
$entity->load('client');
$client = $entity->client;
App::setLocale($client->preferredLocale());
$labels = $entity->makeLabels();
$values = $entity->makeValues($contact);
$css_url = url('').'/css/design/'.$designer->design_name.'.css';
$css_url = "<link href=\"{$css_url}\" rel=\"stylesheet\">";
$data = [];
$data['entity'] = $entity;
$data['lang'] = $client->preferredLocale();
$data['includes'] = $this->parseLabelsAndValues($labels, $values, $designer->init()->getIncludes()->getHtml());
$data['includes'] = str_replace('$css_url', $css_url, $data['includes']);
$data['header'] = $this->parseLabelsAndValues($labels, $values, $designer->init()->getHeader()->getHtml());
$data['body'] = $this->parseLabelsAndValues($labels, $values, $designer->init()->getBody()->getHtml());
$data['product'] = $this->parseLabelsAndValues($labels, $values, $designer->init()->getProductTable());
$data['task'] = $this->parseLabelsAndValues($labels, $values, $designer->init()->getTaskTable());
$data['footer'] = $this->parseLabelsAndValues($labels, $values, $designer->init()->getFooter()->getHtml());
return view('pdf.stub', $data)->render();
}
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);
return $section;
}
/**
* Parses the blade file string and processes the template variables
*
@ -61,11 +101,8 @@ trait MakesInvoiceHtml
* @return string The return HTML string
*
*/
public function renderView($string, $data) :string
public function renderView($string, $data = []) :string
{
if (!$data) {
$data = [];
}
$data['__env'] = app(\Illuminate\View\Factory::class);

View File

@ -505,7 +505,7 @@ trait MakesInvoiceValues
}
public function table_header($columns, $css) :?string
public function table_header($columns) :?string
{
/* Table Header */
@ -524,7 +524,10 @@ trait MakesInvoiceValues
}
public function table_body($columns, $css) :?string
/**
* @todo need to differentiate here between products and tasks - need to filter by invoice_type_id
*/
public function table_body($columns) :?string
{
$table_body = '';

View File

@ -42,11 +42,11 @@ class DesignSeeder extends Seeder
$invoice_design = new $class();
$design_object = new \stdClass;
$design_object->include = $invoice_design->include() ?: '';
$design_object->includes = $invoice_design->includes() ?: '';
$design_object->header = $invoice_design->header() ?: '';
$design_object->body = $invoice_design->body() ?: '';
$design_object->product_table = $invoice_design->product_table() ?: '';
$design_object->task_table = $invoice_design->task_table() ?: '';
$design_object->product = $invoice_design->product() ?: '';
$design_object->task = $invoice_design->task() ?: '';
$design_object->footer = $invoice_design->footer() ?: '';
$design->design = $design_object;

1
public/css/design/bold.css vendored Normal file

File diff suppressed because one or more lines are too long

1
public/css/design/business.css vendored Normal file

File diff suppressed because one or more lines are too long

1
public/css/design/clean.css vendored Normal file

File diff suppressed because one or more lines are too long

1
public/css/design/creative.css vendored Normal file

File diff suppressed because one or more lines are too long

0
public/css/design/custom.css vendored Normal file
View File

1
public/css/design/elegant.css vendored Normal file

File diff suppressed because one or more lines are too long

1
public/css/design/hipster.css vendored Normal file

File diff suppressed because one or more lines are too long

1
public/css/design/modern.css vendored Normal file

File diff suppressed because one or more lines are too long

1
public/css/design/photo.css vendored Normal file

File diff suppressed because one or more lines are too long

2
public/css/design/plain.css vendored Normal file

File diff suppressed because one or more lines are too long

1
public/css/design/playful.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1 +1,23 @@
{!! $pdf !!}
<!DOCTYPE html>
<html lang="{!! $lang !!}">
{!! $includes !!}
<body>
{!! $header !!}
{!! $body !!}
@if($product)
{!! $product !!}
@endif
@if($task)
{!! $task !!}
@endif
{!! $footer !!}
</body>
</html>

View File

@ -80,7 +80,6 @@ class QuoteTest extends TestCase
$message = json_decode($e->validator->getMessageBag(),1);
\Log::error($message);
}
if($response)

View File

@ -7,6 +7,7 @@ use App\Designs\Modern;
use App\Jobs\Credit\CreateCreditPdf;
use App\Jobs\Invoice\CreateInvoicePdf;
use App\Jobs\Quote\CreateQuotePdf;
use App\Models\Design;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesHash;
use Tests\MockAccountData;
@ -32,9 +33,9 @@ class DesignTest extends TestCase
public function testInvoiceDesignExists()
{
$modern = new Modern();
$design = Design::find(3);
$designer = new Designer($this->invoice, $modern, $this->company->settings->pdf_variables, 'quote');
$designer = new Designer($this->invoice, $design, $this->company->settings->pdf_variables, 'quote');
$html = $designer->build()->getHtml();
@ -61,9 +62,9 @@ class DesignTest extends TestCase
public function testQuoteDesignExists()
{
$modern = new Modern();
$design = Design::find(3);
$designer = new Designer($this->quote, $modern, $this->company->settings->pdf_variables, 'quote');
$designer = new Designer($this->quote, $design, $this->company->settings->pdf_variables, 'quote');
$html = $designer->build()->getHtml();
@ -169,9 +170,9 @@ class DesignTest extends TestCase
public function testCreditDesignExists()
{
$modern = new Modern();
$design = Design::find(3);
$designer = new Designer($this->credit, $modern, $this->company->settings->pdf_variables, 'credit');
$designer = new Designer($this->credit, $design, $this->company->settings->pdf_variables, 'credit');
$html = $designer->build()->getHtml();

View File

@ -0,0 +1,41 @@
<?php
namespace Tests\Integration;
use App\Designs\Bold;
use App\Designs\Designer;
use App\Models\Design;
use App\Utils\Traits\MakesInvoiceHtml;
use Tests\MockAccountData;
use Tests\TestCase;
/**
* @test
*/
class HtmlGenerationTest extends TestCase
{
use MockAccountData;
use MakesInvoiceHtml;
public function setUp() :void
{
parent::setUp();
$this->makeTestData();
}
public function testHtmlOutput()
{
$design = Design::find(3);
$designer = new Designer($this->invoice, $design, $this->invoice->client->getSetting('pdf_variables'), 'invoice');
$html = $this->generateEntityHtml($designer, $this->invoice);
\Log::error($html);
$this->assertNotNull($html);
}
}