mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-01 10:44:35 -04:00
Repeating header and footers on Invoice PDFs (#3424)
* remove jobs table * Working on notifications * Working on notifications * Fixes for setting group level currency id on new client * Working on repeating headers * Use CSS to force headers and footers * recurring headers and footers * Preview PDF * Working on PDF Preview
This commit is contained in:
parent
5a7d6c4a7a
commit
7acc6ee300
@ -220,8 +220,8 @@ class CompanySettings extends BaseSettings {
|
|||||||
public $secondary_font = 'Roboto';
|
public $secondary_font = 'Roboto';
|
||||||
public $hide_paid_to_date = false;
|
public $hide_paid_to_date = false;
|
||||||
public $embed_documents = false;
|
public $embed_documents = false;
|
||||||
public $all_pages_header = true;
|
public $all_pages_header = false;
|
||||||
public $all_pages_footer = true;
|
public $all_pages_footer = false;
|
||||||
public $pdf_variables = [];
|
public $pdf_variables = [];
|
||||||
|
|
||||||
public static $casts = [
|
public static $casts = [
|
||||||
|
@ -19,7 +19,9 @@ abstract class AbstractDesign
|
|||||||
|
|
||||||
abstract public function body();
|
abstract public function body();
|
||||||
|
|
||||||
abstract public function table();
|
abstract public function product_table();
|
||||||
|
|
||||||
|
abstract public function task_table();
|
||||||
|
|
||||||
abstract public function footer();
|
abstract public function footer();
|
||||||
|
|
||||||
|
@ -39,7 +39,11 @@ class Bold extends AbstractDesign
|
|||||||
{
|
{
|
||||||
size: auto;
|
size: auto;
|
||||||
margin-top: 5mm;
|
margin-top: 5mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-left .table_header_thead_class {}
|
||||||
|
.px-12 .text-2xl .px-4 .py-2 .table_header_td_class {}
|
||||||
|
.bg-gray-200 .py-5 .pl-12 .table_body_td_class {}
|
||||||
</style>
|
</style>
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
@ -95,8 +99,10 @@ class Bold extends AbstractDesign
|
|||||||
'table_body_td_class' => "bg-gray-200 py-5 pl-12",
|
'table_body_td_class' => "bg-gray-200 py-5 pl-12",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
public function table() {
|
public function product_table() {
|
||||||
|
|
||||||
return '
|
return '
|
||||||
<table class="w-full table-auto mt-8">
|
<table class="w-full table-auto mt-8">
|
||||||
|
@ -106,7 +106,10 @@ class Business extends AbstractDesign
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table() {
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product_table() {
|
||||||
|
|
||||||
return '
|
return '
|
||||||
<table class="w-full table-auto mt-20">
|
<table class="w-full table-auto mt-20">
|
||||||
|
@ -106,8 +106,10 @@ class Clean extends AbstractDesign
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table() {
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product_table() {
|
||||||
return '
|
return '
|
||||||
<table class="w-full table-auto mt-8">
|
<table class="w-full table-auto mt-8">
|
||||||
<thead class="text-left">
|
<thead class="text-left">
|
||||||
|
@ -102,8 +102,11 @@ class Creative extends AbstractDesign
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table() {
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product_table() {
|
||||||
|
|
||||||
return '
|
return '
|
||||||
<table class="w-full table-auto mt-12 border-t-4 border-pink-700 bg-white">
|
<table class="w-full table-auto mt-12 border-t-4 border-pink-700 bg-white">
|
||||||
<thead class="text-left rounded-lg">
|
<thead class="text-left rounded-lg">
|
||||||
|
@ -19,8 +19,10 @@ class Custom extends AbstractDesign
|
|||||||
|
|
||||||
private $body;
|
private $body;
|
||||||
|
|
||||||
private $table;
|
private $product_table;
|
||||||
|
|
||||||
|
private $task_table;
|
||||||
|
|
||||||
private $footer;
|
private $footer;
|
||||||
|
|
||||||
private $table_styles;
|
private $table_styles;
|
||||||
@ -33,8 +35,10 @@ class Custom extends AbstractDesign
|
|||||||
|
|
||||||
$this->body = $design->body;
|
$this->body = $design->body;
|
||||||
|
|
||||||
$this->table = $design->table;
|
$this->product_table = $design->product_table;
|
||||||
|
|
||||||
|
$this->task_table = $design->task_table;
|
||||||
|
|
||||||
$this->footer = $design->footer;
|
$this->footer = $design->footer;
|
||||||
|
|
||||||
$this->table_styles = $design->table_styles;
|
$this->table_styles = $design->table_styles;
|
||||||
@ -67,18 +71,23 @@ class Custom extends AbstractDesign
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table()
|
public function product_table()
|
||||||
{
|
{
|
||||||
|
|
||||||
return $this->table;
|
return $this->product_table;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function task_table()
|
||||||
|
{
|
||||||
|
return $this->task_table;
|
||||||
|
}
|
||||||
|
|
||||||
public function footer()
|
public function footer()
|
||||||
{
|
{
|
||||||
|
|
||||||
return $this->footer;
|
return $this->footer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -26,6 +26,8 @@ class Designer {
|
|||||||
|
|
||||||
protected $entity_string;
|
protected $entity_string;
|
||||||
|
|
||||||
|
protected $entity;
|
||||||
|
|
||||||
private static $custom_fields = [
|
private static $custom_fields = [
|
||||||
'invoice1',
|
'invoice1',
|
||||||
'invoice2',
|
'invoice2',
|
||||||
@ -49,8 +51,9 @@ class Designer {
|
|||||||
'company4',
|
'company4',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct($design, $input_variables, $entity_string)
|
public function __construct($entity, $design, $input_variables, $entity_string)
|
||||||
{
|
{
|
||||||
|
$this->entity = $entity;
|
||||||
|
|
||||||
$this->design = $design;
|
$this->design = $design;
|
||||||
|
|
||||||
@ -65,27 +68,63 @@ class Designer {
|
|||||||
* formatted HTML
|
* formatted HTML
|
||||||
* @return string The HTML design built
|
* @return string The HTML design built
|
||||||
*/
|
*/
|
||||||
public function build($entity):Designer
|
public function build():Designer
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->exportVariables($entity)
|
$this->setHtml()
|
||||||
|
->exportVariables()
|
||||||
->setDesign($this->getSection('include'))
|
->setDesign($this->getSection('include'))
|
||||||
->setDesign($this->getSection('header'))
|
->setDesign($this->getSection('header'))
|
||||||
->setDesign($this->getSection('body'))
|
->setDesign($this->getSection('body'))
|
||||||
->setDesign($this->getTable($entity))
|
->setDesign($this->getProductTable($this->entity))
|
||||||
->setDesign($this->getSection('footer'));
|
->setDesign($this->getSection('footer'));
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTable($entity):string
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setHtml()
|
||||||
|
->exportVariables();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeader()
|
||||||
{
|
{
|
||||||
|
|
||||||
$table_header = $entity->table_header($this->input_variables['product_columns'], $this->design->table_styles());
|
$this->setDesign($this->getSection('include'))
|
||||||
$table_body = $entity->table_body($this->input_variables['product_columns'], $this->design->table_styles());
|
->setDesign($this->getSection('header'));
|
||||||
|
|
||||||
$data = str_replace('$table_header', $table_header, $this->getSection('table'));
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFooter()
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->setDesign($this->getSection('footer'));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBody()
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->setDesign($this->getSection('include'))
|
||||||
|
->setDesign($this->getSection('body'))
|
||||||
|
->setDesign($this->getProductTable());
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
$data = str_replace('$table_header', $table_header, $this->getSection('product_table'));
|
||||||
$data = str_replace('$table_body', $table_body, $data);
|
$data = str_replace('$table_body', $table_body, $data);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
@ -97,6 +136,13 @@ class Designer {
|
|||||||
return $this->html;
|
return $this->html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setHtml()
|
||||||
|
{
|
||||||
|
$this->html = '';
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
private function setDesign($section)
|
private function setDesign($section)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -117,10 +163,10 @@ class Designer {
|
|||||||
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($entity)
|
private function exportVariables()
|
||||||
{
|
{
|
||||||
|
|
||||||
$company = $entity->company;
|
$company = $this->entity->company;
|
||||||
|
|
||||||
$this->exported_variables['$client_details'] = $this->processVariables($this->processInputVariables($company, $this->input_variables['client_details']), $this->clientDetails($company));
|
$this->exported_variables['$client_details'] = $this->processVariables($this->processInputVariables($company, $this->input_variables['client_details']), $this->clientDetails($company));
|
||||||
$this->exported_variables['$company_details'] = $this->processVariables($this->processInputVariables($company, $this->input_variables['company_details']), $this->companyDetails($company));
|
$this->exported_variables['$company_details'] = $this->processVariables($this->processInputVariables($company, $this->input_variables['company_details']), $this->companyDetails($company));
|
||||||
@ -170,35 +216,6 @@ class Designer {
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private function exportVariables()
|
|
||||||
// {
|
|
||||||
// /*
|
|
||||||
// * $entity_labels
|
|
||||||
// * $entity_details
|
|
||||||
// */
|
|
||||||
// $header = $this->design->header();
|
|
||||||
|
|
||||||
// /*
|
|
||||||
// * $company_logo - full URL
|
|
||||||
// * $client_details
|
|
||||||
// */
|
|
||||||
// $body = $this->design->body();
|
|
||||||
|
|
||||||
// /*
|
|
||||||
// * $table_header
|
|
||||||
// * $table_body
|
|
||||||
// * $total_labels
|
|
||||||
// * $total_values
|
|
||||||
// */
|
|
||||||
// $table = $this->design->table();
|
|
||||||
|
|
||||||
// /*
|
|
||||||
// * $company_details
|
|
||||||
// * $company_address
|
|
||||||
// */
|
|
||||||
// $footer = $this->design->footer();
|
|
||||||
// }
|
|
||||||
|
|
||||||
private function clientDetails(Company $company)
|
private function clientDetails(Company $company)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -95,8 +95,10 @@ class Elegant extends AbstractDesign
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table() {
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product_table() {
|
||||||
return '
|
return '
|
||||||
<table class="w-full table-auto mb-6 mt-16">
|
<table class="w-full table-auto mb-6 mt-16">
|
||||||
<thead class="text-left border-dashed border-b border-black">
|
<thead class="text-left border-dashed border-b border-black">
|
||||||
|
@ -110,8 +110,10 @@ class Hipster extends AbstractDesign
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table() {
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product_table() {
|
||||||
return '
|
return '
|
||||||
<table class="w-full table-auto mt-24">
|
<table class="w-full table-auto mt-24">
|
||||||
<thead class="text-left">
|
<thead class="text-left">
|
||||||
|
File diff suppressed because one or more lines are too long
@ -109,8 +109,10 @@ class Photo extends AbstractDesign
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table() {
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product_table() {
|
||||||
return '
|
return '
|
||||||
<div class="px-16 py-16">
|
<div class="px-16 py-16">
|
||||||
<table class="w-full table-auto">
|
<table class="w-full table-auto">
|
||||||
|
@ -96,8 +96,10 @@ class Plain extends AbstractDesign
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table() {
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product_table() {
|
||||||
return '
|
return '
|
||||||
<table class="w-full table-auto mt-8">
|
<table class="w-full table-auto mt-8">
|
||||||
<thead class="text-left bg-gray-300">
|
<thead class="text-left bg-gray-300">
|
||||||
|
@ -104,8 +104,10 @@ class Playful extends AbstractDesign
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table() {
|
public function task_table() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function product_table() {
|
||||||
return '
|
return '
|
||||||
<table class="w-full table-auto mt-20 mb-8">
|
<table class="w-full table-auto mt-20 mb-8">
|
||||||
<thead class="text-left bg-teal-600 rounded-lg">
|
<thead class="text-left bg-teal-600 rounded-lg">
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\ClientPortal;
|
namespace App\Http\Controllers\ClientPortal;
|
||||||
|
|
||||||
|
use App\Events\Misc\InvitationWasViewed;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\InvoiceInvitation;
|
use App\Models\InvoiceInvitation;
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
|
140
app/Http/Controllers/PreviewController.php
Normal file
140
app/Http/Controllers/PreviewController.php
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<?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\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Designs\Custom;
|
||||||
|
use App\Designs\Designer;
|
||||||
|
use App\Factory\InvoiceFactory;
|
||||||
|
use App\Jobs\Invoice\CreateInvoicePdf;
|
||||||
|
use App\Jobs\Util\PreviewPdf;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\MakesInvoiceHtml;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
|
||||||
|
class PreviewController extends BaseController
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
use MakesInvoiceHtml;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a template filled with entity variables
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/preview",
|
||||||
|
* operationId="getPreview",
|
||||||
|
* tags={"preview"},
|
||||||
|
* summary="Returns a pdf preview",
|
||||||
|
* description="Returns a pdf preview.",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="entity",
|
||||||
|
* in="path",
|
||||||
|
* description="The PDF",
|
||||||
|
* example="invoice",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="entity_id",
|
||||||
|
* in="path",
|
||||||
|
* description="The Entity ID",
|
||||||
|
* example="X9f87dkf",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="The pdf response",
|
||||||
|
* @OA\Header(header="X-API-Version", ref="#/components/headers/X-API-Version"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (request()->has('entity') &&
|
||||||
|
request()->has('entity_id') &&
|
||||||
|
request()->has('body'))
|
||||||
|
{
|
||||||
|
|
||||||
|
$invoice_design = new Custom((object)request()->input('body'));
|
||||||
|
|
||||||
|
$entity = ucfirst(request()->input('entity'));
|
||||||
|
|
||||||
|
$class = "App\Models\\$entity";
|
||||||
|
|
||||||
|
$pdf_class = "App\Jobs\\$entity\\Create{$entity}Pdf";
|
||||||
|
|
||||||
|
$entity_obj = $class::whereId($this->decodePrimaryKey(request()->input('entity_id')))->company()->first();
|
||||||
|
|
||||||
|
if(!$entity_obj)
|
||||||
|
return $this->blankEntity();
|
||||||
|
|
||||||
|
$entity_obj->load('client');
|
||||||
|
|
||||||
|
$designer = new Designer($entity_obj, $invoice_design, $entity_obj->client->getSetting('pdf_variables'), lcfirst($entity));
|
||||||
|
|
||||||
|
$html = $this->generateInvoiceHtml($designer->build()->getHtml(), $entity_obj);
|
||||||
|
|
||||||
|
$file_path = PreviewPdf::dispatchNow($html, auth()->user()->company());
|
||||||
|
|
||||||
|
return response()->download($file_path)->deleteFileAfterSend(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->blankEntity();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function blankEntity()
|
||||||
|
{
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Blank Entity not implemented.'], 200);
|
||||||
|
|
||||||
|
// $invoice_design = new Custom((object)request()->input('body'));
|
||||||
|
|
||||||
|
// $file_path = PreviewPdf::dispatchNow(request()->input('body'), auth()->user()->company());
|
||||||
|
|
||||||
|
// return response()->download($file_path)->deleteFileAfterSend(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -11,10 +11,13 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use League\CommonMark\CommonMarkConverter;
|
use League\CommonMark\CommonMarkConverter;
|
||||||
|
|
||||||
class TemplateController extends BaseController
|
class TemplateController extends BaseController
|
||||||
{
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
@ -100,7 +103,7 @@ class TemplateController extends BaseController
|
|||||||
{
|
{
|
||||||
if (request()->has('entity') && request()->has('entity_id')) {
|
if (request()->has('entity') && request()->has('entity_id')) {
|
||||||
$class = 'App\Models\\'.ucfirst(request()->input('entity'));
|
$class = 'App\Models\\'.ucfirst(request()->input('entity'));
|
||||||
$entity_obj = $class::whereId(request()->input('entity_id'))->company()->first();
|
$entity_obj = $class::whereId($this->decodePrimaryKey(request()->input('entity_id')))->company()->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
$subject = request()->input('subject') ?: '';
|
$subject = request()->input('subject') ?: '';
|
||||||
|
@ -88,16 +88,16 @@ class StoreClientRequest extends Request
|
|||||||
|
|
||||||
if(empty($input['group_settings_id']))
|
if(empty($input['group_settings_id']))
|
||||||
{
|
{
|
||||||
$input['settings']->currency_id = auth()->user()->company()->settings->currency_id;
|
$input['settings']->currency_id =(string) auth()->user()->company()->settings->currency_id;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$group_settings = GroupSetting::find($input['group_settings_id']);
|
$group_settings = GroupSetting::find($input['group_settings_id']);
|
||||||
|
|
||||||
if($group_settings && property_exists($group_settings->settings, 'currency_id') && is_int($group_settings->settings->currency_id))
|
if($group_settings && property_exists($group_settings->settings, 'currency_id') && is_int($group_settings->settings->currency_id))
|
||||||
$input['settings']->currency_id = $group_settings->currency_id;
|
$input['settings']->currency_id = (string)$group_settings->settings->currency_id;
|
||||||
else
|
else
|
||||||
$input['settings']->currency_id = auth()->user()->company()->settings->currency_id;
|
$input['settings']->currency_id = (string)auth()->user()->company()->settings->currency_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,10 +86,10 @@ class CreateCreditPdf implements ShouldQueue {
|
|||||||
$credit_design = new $class();
|
$credit_design = new $class();
|
||||||
}
|
}
|
||||||
|
|
||||||
$designer = new Designer($credit_design, $this->credit->client->getSetting('pdf_variables'), 'credit');
|
$designer = new Designer($this->credit, $credit_design, $this->credit->client->getSetting('pdf_variables'), 'credit');
|
||||||
|
|
||||||
//get invoice design
|
//get invoice design
|
||||||
$html = $this->generateInvoiceHtml($designer->build($this->credit)->getHtml(), $this->credit, $this->contact);
|
$html = $this->generateInvoiceHtml($designer->build()->getHtml(), $this->credit, $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);
|
||||||
|
@ -84,10 +84,10 @@ class CreateInvoicePdf implements ShouldQueue {
|
|||||||
$invoice_design = new $class();
|
$invoice_design = new $class();
|
||||||
}
|
}
|
||||||
|
|
||||||
$designer = new Designer($invoice_design, $this->invoice->client->getSetting('pdf_variables'), 'invoice');
|
$designer = new Designer($this->invoice, $invoice_design, $this->invoice->client->getSetting('pdf_variables'), 'invoice');
|
||||||
|
|
||||||
//get invoice design
|
//get invoice design
|
||||||
$html = $this->generateInvoiceHtml($designer->build($this->invoice)->getHtml(), $this->invoice, $this->contact);
|
$html = $this->generateInvoiceHtml($designer->build()->getHtml(), $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);
|
||||||
|
@ -65,6 +65,8 @@ class CreateQuotePdf implements ShouldQueue {
|
|||||||
|
|
||||||
MultiDB::setDB($this->company->db);
|
MultiDB::setDB($this->company->db);
|
||||||
|
|
||||||
|
$settings = $this->quote->client->getMergedSettings();
|
||||||
|
|
||||||
$this->quote->load('client');
|
$this->quote->load('client');
|
||||||
|
|
||||||
if(!$this->contact)
|
if(!$this->contact)
|
||||||
@ -74,7 +76,6 @@ class CreateQuotePdf implements ShouldQueue {
|
|||||||
|
|
||||||
$path = $this->quote->client->quote_filepath();
|
$path = $this->quote->client->quote_filepath();
|
||||||
|
|
||||||
$file_path = $path . $this->quote->number . '.pdf';
|
|
||||||
|
|
||||||
$design = Design::find($this->quote->client->getSetting('quote_design_id'));
|
$design = Design::find($this->quote->client->getSetting('quote_design_id'));
|
||||||
|
|
||||||
@ -86,16 +87,46 @@ class CreateQuotePdf implements ShouldQueue {
|
|||||||
$quote_design = new $class();
|
$quote_design = new $class();
|
||||||
}
|
}
|
||||||
|
|
||||||
$designer = new Designer($quote_design, $this->quote->client->getSetting('pdf_variables'), 'quote');
|
$designer = new Designer($this->quote, $quote_design, $this->quote->client->getSetting('pdf_variables'), 'quote');
|
||||||
|
|
||||||
//get invoice design
|
|
||||||
$html = $this->generateInvoiceHtml($designer->build($this->quote)->getHtml(), $this->quote, $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);
|
||||||
|
|
||||||
//\Log::error($html);
|
//\Log::error($html);
|
||||||
$pdf = $this->makePdf(null, null, $html);
|
|
||||||
|
$all_pages_header = $settings->all_pages_header;
|
||||||
|
$all_pages_footer = $settings->all_pages_footer;
|
||||||
|
|
||||||
|
$quote_number = $this->quote->number;
|
||||||
|
|
||||||
|
|
||||||
|
// if($all_pages_header && $all_pages_footer){
|
||||||
|
// $all_pages_header = $designer->init()->getHeader()->getHtml();
|
||||||
|
// $all_pages_footer = $designer->init()->getFooter()->getHtml();
|
||||||
|
// $design_body = $designer->init()->getBody()->getHtml();
|
||||||
|
// $quote_number = "header_and_footer";
|
||||||
|
// }
|
||||||
|
// elseif($all_pages_header){
|
||||||
|
// $all_pages_header = $designer->init()->getHeader()->getHtml();
|
||||||
|
// $design_body = $designer->init()->getBody()->getFooter()->getHtml();
|
||||||
|
// $quote_number = "header_only";
|
||||||
|
// }
|
||||||
|
// elseif($all_pages_footer){
|
||||||
|
// $all_pages_footer = $designer->init()->getFooter()->getHtml();
|
||||||
|
// $design_body = $designer->init()->getHeader()->getBody()->getHtml();
|
||||||
|
// $quote_number = "footer_only";
|
||||||
|
// }
|
||||||
|
// else{
|
||||||
|
$design_body = $designer->build()->getHtml();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//get invoice design
|
||||||
|
$html = $this->generateInvoiceHtml($design_body, $this->quote, $this->contact);
|
||||||
|
|
||||||
|
$pdf = $this->makePdf($all_pages_header, $all_pages_footer, $html);
|
||||||
|
$file_path = $path . $quote_number . '.pdf';
|
||||||
|
|
||||||
$instance = Storage::disk($this->disk)->put($file_path, $pdf);
|
$instance = Storage::disk($this->disk)->put($file_path, $pdf);
|
||||||
|
|
||||||
|
81
app/Jobs/Util/PreviewPdf.php
Normal file
81
app/Jobs/Util/PreviewPdf.php
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?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\Jobs\Util;
|
||||||
|
|
||||||
|
use App\Designs\Custom;
|
||||||
|
use App\Designs\Designer;
|
||||||
|
use App\Designs\Modern;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\Design;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Utils\Traits\Pdf\PdfMaker;
|
||||||
|
use App\Utils\Traits\MakesInvoiceHtml;
|
||||||
|
use App\Utils\Traits\NumberFormatter;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\App;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Spatie\Browsershot\Browsershot;
|
||||||
|
|
||||||
|
class PreviewPdf implements ShouldQueue {
|
||||||
|
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter, MakesInvoiceHtml, PdfMaker;
|
||||||
|
|
||||||
|
public $invoice;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $contact;
|
||||||
|
|
||||||
|
private $disk;
|
||||||
|
|
||||||
|
public $design_string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($design_string, Company $company)
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->company = $company;
|
||||||
|
|
||||||
|
$this->design_string = $design_string;
|
||||||
|
|
||||||
|
$this->disk = $disk ?? config('filesystems.default');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle() {
|
||||||
|
|
||||||
|
|
||||||
|
$path = $this->company->company_key;
|
||||||
|
|
||||||
|
//Storage::makeDirectory($path, 0755);
|
||||||
|
|
||||||
|
$file_path = $path . '/stream.pdf';
|
||||||
|
|
||||||
|
$pdf = $this->makePdf(null, null, $this->design_string);
|
||||||
|
|
||||||
|
$instance = Storage::disk('local')->put($file_path, $pdf);
|
||||||
|
|
||||||
|
return storage_path('app') .'/'. $file_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -47,7 +47,7 @@ class InvitationViewedListener implements ShouldQueue
|
|||||||
|
|
||||||
$notification->is_system = true;
|
$notification->is_system = true;
|
||||||
|
|
||||||
Notification::route('slack', $payment->company->slack_webhook_url)
|
Notification::route('slack', $invitation->company->slack_webhook_url)
|
||||||
->notify($notification);
|
->notify($notification);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -448,19 +448,25 @@ class Client extends BaseModel implements HasLocalePreference
|
|||||||
|
|
||||||
public function invoice_filepath()
|
public function invoice_filepath()
|
||||||
{
|
{
|
||||||
return $this->client_hash . '/invoices/';
|
return $this->company->company_key . '/' . $this->client_hash . '/invoices/';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function quote_filepath()
|
public function quote_filepath()
|
||||||
{
|
{
|
||||||
return $this->client_hash . '/quotes/';
|
return $this->company->company_key . '/' . $this->client_hash . '/quotes/';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function credit_filepath()
|
public function credit_filepath()
|
||||||
{
|
{
|
||||||
return $this->client_hash . '/credits/';
|
return $this->company->company_key . '/' . $this->client_hash . '/credits/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function company_filepath()
|
||||||
|
{
|
||||||
|
return $this->company->company_key . '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function setInvoiceDefaults() :Invoice
|
public function setInvoiceDefaults() :Invoice
|
||||||
{
|
{
|
||||||
$invoice_factory = InvoiceFactory::create($this->company_id, auth()->user()->id);
|
$invoice_factory = InvoiceFactory::create($this->company_id, auth()->user()->id);
|
||||||
|
@ -87,6 +87,14 @@ class Invoice extends BaseModel
|
|||||||
'line_items',
|
'line_items',
|
||||||
'client_id',
|
'client_id',
|
||||||
'footer',
|
'footer',
|
||||||
|
'custom_surcharge1',
|
||||||
|
'custom_surcharge2',
|
||||||
|
'custom_surcharge3',
|
||||||
|
'custom_surcharge4',
|
||||||
|
'custom_surcharge_tax1',
|
||||||
|
'custom_surcharge_tax2',
|
||||||
|
'custom_surcharge_tax3',
|
||||||
|
'custom_surcharge_tax4',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
@ -11,7 +11,7 @@ use Illuminate\Notifications\Notification;
|
|||||||
|
|
||||||
class EntityViewedNotification extends Notification implements ShouldQueue
|
class EntityViewedNotification extends Notification implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Queueable, Dispatchable;
|
use Queueable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new notification instance.
|
* Create a new notification instance.
|
||||||
@ -36,6 +36,7 @@ class EntityViewedNotification extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function __construct($invitation, $entity_name, $is_system = false, $settings = null)
|
public function __construct($invitation, $entity_name, $is_system = false, $settings = null)
|
||||||
{
|
{
|
||||||
|
$this->entity_name = $entity_name;
|
||||||
$this->entity = $invitation->{$entity_name};
|
$this->entity = $invitation->{$entity_name};
|
||||||
$this->contact = $invitation->contact;
|
$this->contact = $invitation->contact;
|
||||||
$this->company = $invitation->company;
|
$this->company = $invitation->company;
|
||||||
@ -89,16 +90,34 @@ class EntityViewedNotification extends Notification implements ShouldQueue
|
|||||||
$logo = $this->company->present()->logo();
|
$logo = $this->company->present()->logo();
|
||||||
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
|
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
|
||||||
|
|
||||||
|
// return (new SlackMessage)
|
||||||
|
// ->success()
|
||||||
|
// ->from(ctrans('texts.notification_bot'))
|
||||||
|
// ->image($logo)
|
||||||
|
// ->content(ctrans("texts.notification_{$this->entity_name}_viewed",
|
||||||
|
// [
|
||||||
|
// 'amount' => $amount,
|
||||||
|
// 'client' => $this->contact->present()->name(),
|
||||||
|
// $this->entity_name => $this->entity->number
|
||||||
|
// ]));
|
||||||
|
|
||||||
return (new SlackMessage)
|
return (new SlackMessage)
|
||||||
->success()
|
->from(ctrans('texts.notification_bot'))
|
||||||
->from(ctrans('texts.notification_bot'))
|
->success()
|
||||||
->image($logo)
|
->image('https://app.invoiceninja.com/favicon-v2.png')
|
||||||
->content(ctrans("texts.notification_{$this->entity_name}_viewed",
|
->content(ctrans("texts.notification_{$this->entity_name}_viewed",
|
||||||
[
|
[
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'client' => $this->contact->present()->name(),
|
'client' => $this->contact->present()->name(),
|
||||||
$this->entity_name => $this->entity->number
|
$this->entity_name => $this->entity->number
|
||||||
]));
|
]))
|
||||||
|
->attachment(function ($attachment) use($amount){
|
||||||
|
$attachment->title(ctrans('texts.entity_number_placeholder', ['entity' => ucfirst($this->entity_name), 'entity_number' => $this->entity->number]), $this->invitation->getAdminLink())
|
||||||
|
->fields([
|
||||||
|
ctrans('texts.client') => $this->contact->present()->name(),
|
||||||
|
ctrans('texts.status_viewed') => $this->invitation->viewed_date,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,11 +126,6 @@ class EntityViewedNotification extends Notification implements ShouldQueue
|
|||||||
{
|
{
|
||||||
|
|
||||||
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
|
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
|
||||||
$subject = ctrans("texts.notification_{$this->entity_name}_viewed_subject",
|
|
||||||
[
|
|
||||||
'client' => $this->contact->present()->name(),
|
|
||||||
$this->entity_name => $this->entity->number,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'title' => $subject,
|
'title' => $subject,
|
||||||
@ -127,5 +141,20 @@ class EntityViewedNotification extends Notification implements ShouldQueue
|
|||||||
'logo' => $this->company->present()->logo(),
|
'logo' => $this->company->present()->logo(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildSubject()
|
||||||
|
{
|
||||||
|
$subject = ctrans("texts.notification_{$this->entity_name}_viewed_subject",
|
||||||
|
[
|
||||||
|
'client' => $this->contact->present()->name(),
|
||||||
|
$this->entity_name => $this->entity->number,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $subject;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ class InvoiceSentNotification extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function __construct($invitation, $company, $is_system = false, $settings = null)
|
public function __construct($invitation, $company, $is_system = false, $settings = null)
|
||||||
{
|
{
|
||||||
|
$this->invitation = $invitation;
|
||||||
$this->invoice = $invitation->invoice;
|
$this->invoice = $invitation->invoice;
|
||||||
$this->contact = $invitation->contact;
|
$this->contact = $invitation->contact;
|
||||||
$this->company = $company;
|
$this->company = $company;
|
||||||
@ -131,7 +132,7 @@ class InvoiceSentNotification extends Notification implements ShouldQueue
|
|||||||
'invoice' => $this->invoice->number
|
'invoice' => $this->invoice->number
|
||||||
]))
|
]))
|
||||||
->attachment(function ($attachment) use($amount){
|
->attachment(function ($attachment) use($amount){
|
||||||
$attachment->title(ctrans('texts.invoice_number_placeholder', ['invoice' => $this->invoice->number]), 'http://linky')
|
$attachment->title(ctrans('texts.invoice_number_placeholder', ['invoice' => $this->invoice->number]), $this->invitation->getAdminLink())
|
||||||
->fields([
|
->fields([
|
||||||
ctrans('texts.client') => $this->contact->present()->name(),
|
ctrans('texts.client') => $this->contact->present()->name(),
|
||||||
ctrans('texts.amount') => $amount,
|
ctrans('texts.amount') => $amount,
|
||||||
|
@ -127,7 +127,10 @@ class InvoiceTransformer extends EntityTransformer
|
|||||||
'custom_surcharge2' => (float)$invoice->custom_surcharge2,
|
'custom_surcharge2' => (float)$invoice->custom_surcharge2,
|
||||||
'custom_surcharge3' => (float)$invoice->custom_surcharge3,
|
'custom_surcharge3' => (float)$invoice->custom_surcharge3,
|
||||||
'custom_surcharge4' => (float)$invoice->custom_surcharge4,
|
'custom_surcharge4' => (float)$invoice->custom_surcharge4,
|
||||||
'custom_surcharge_taxes' => (bool) $invoice->custom_surcharge_taxes,
|
'custom_surcharge_tax1' => (float) $invoice->custom_surcharge_tax1,
|
||||||
|
'custom_surcharge_tax2' => (float) $invoice->custom_surcharge_tax2,
|
||||||
|
'custom_surcharge_tax3' => (float) $invoice->custom_surcharge_tax3,
|
||||||
|
'custom_surcharge_tax4' => (float) $invoice->custom_surcharge_tax4,
|
||||||
'line_items' => $invoice->line_items ?: (array)[],
|
'line_items' => $invoice->line_items ?: (array)[],
|
||||||
'backup' => $invoice->backup ?: '',
|
'backup' => $invoice->backup ?: '',
|
||||||
'entity_type' => 'invoice',
|
'entity_type' => 'invoice',
|
||||||
|
@ -80,6 +80,10 @@ class PaymentTransformer extends EntityTransformer
|
|||||||
'invitation_id' => (string) $payment->invitation_id ?: '',
|
'invitation_id' => (string) $payment->invitation_id ?: '',
|
||||||
'private_notes' => (string) $payment->private_notes ?: '',
|
'private_notes' => (string) $payment->private_notes ?: '',
|
||||||
'number' => (string) $payment->number ?: '',
|
'number' => (string) $payment->number ?: '',
|
||||||
|
'custom_value1' => (string) $payment->custom_value1 ?: '',
|
||||||
|
'custom_value2' => (string) $payment->custom_value2 ?: '',
|
||||||
|
'custom_value3' => (string) $payment->custom_value3 ?: '',
|
||||||
|
'custom_value4' => (string) $payment->custom_value4 ?: '',
|
||||||
'client_id' => (string) $this->encodePrimaryKey($payment->client_id),
|
'client_id' => (string) $this->encodePrimaryKey($payment->client_id),
|
||||||
'client_contact_id' => (string) $this->encodePrimaryKey($payment->client_contact_id),
|
'client_contact_id' => (string) $this->encodePrimaryKey($payment->client_contact_id),
|
||||||
'company_gateway_id' => (string) $this->encodePrimaryKey($payment->company_gateway_id),
|
'company_gateway_id' => (string) $this->encodePrimaryKey($payment->company_gateway_id),
|
||||||
|
@ -505,7 +505,7 @@ trait MakesInvoiceValues
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function table_header(array $columns, array $css) :?string
|
public function table_header($columns, $css) :?string
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Table Header */
|
/* Table Header */
|
||||||
@ -516,7 +516,7 @@ trait MakesInvoiceValues
|
|||||||
$column_headers = $this->transformColumnsForHeader($columns);
|
$column_headers = $this->transformColumnsForHeader($columns);
|
||||||
|
|
||||||
foreach ($column_headers as $column)
|
foreach ($column_headers as $column)
|
||||||
$table_header .= '<td class="'.$css['table_header_td_class'].'">' . ctrans('texts.'.$column.'') . '</td>';
|
$table_header .= '<td class="table_header_td_class">' . ctrans('texts.'.$column.'') . '</td>';
|
||||||
|
|
||||||
//$table_header .= '</tr></thead>';
|
//$table_header .= '</tr></thead>';
|
||||||
|
|
||||||
@ -524,7 +524,7 @@ trait MakesInvoiceValues
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function table_body(array $columns, array $css) :?string
|
public function table_body($columns, $css) :?string
|
||||||
{
|
{
|
||||||
$table_body = '';
|
$table_body = '';
|
||||||
|
|
||||||
@ -538,7 +538,7 @@ trait MakesInvoiceValues
|
|||||||
$table_body .= '<tr class="">';
|
$table_body .= '<tr class="">';
|
||||||
|
|
||||||
foreach ($columns as $column) {
|
foreach ($columns as $column) {
|
||||||
$table_body .= '<td class="'.$css['table_body_td_class'].'">'. $item->{$column} . '</td>';
|
$table_body .= '<td class="table_body_td_class">'. $item->{$column} . '</td>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$table_body .= '</tr>';
|
$table_body .= '</tr>';
|
||||||
@ -555,6 +555,9 @@ trait MakesInvoiceValues
|
|||||||
*/
|
*/
|
||||||
private function transformColumnsForHeader(array $columns) :array
|
private function transformColumnsForHeader(array $columns) :array
|
||||||
{
|
{
|
||||||
|
if(count($columns) == 0)
|
||||||
|
return [];
|
||||||
|
|
||||||
$pre_columns = $columns;
|
$pre_columns = $columns;
|
||||||
$columns = array_intersect($columns, self::$master_columns);
|
$columns = array_intersect($columns, self::$master_columns);
|
||||||
|
|
||||||
|
@ -18,15 +18,44 @@ trait PdfMaker
|
|||||||
* @return string The PDF string
|
* @return string The PDF string
|
||||||
*/
|
*/
|
||||||
public function makePdf($header, $footer, $html) {
|
public function makePdf($header, $footer, $html) {
|
||||||
return Browsershot::html($html)
|
|
||||||
//->showBrowserHeaderAndFooter()
|
|
||||||
//->headerHtml($header)
|
|
||||||
//->footerHtml($footer)
|
// if($header && $footer){
|
||||||
->deviceScaleFactor(1)
|
// $browser = Browsershot::html($html)
|
||||||
->showBackground()
|
// ->headerHtml($header)
|
||||||
->waitUntilNetworkIdle(true) ->pdf();
|
// ->footerHtml($footer);
|
||||||
//->margins(10,10,10,10)
|
// }
|
||||||
//->savePdf('test.pdf');
|
// elseif($header){
|
||||||
|
// $browser = Browsershot::html($html)
|
||||||
|
// ->headerHtml($header);
|
||||||
|
// }
|
||||||
|
// else if($footer){
|
||||||
|
// $browser = Browsershot::html($html)
|
||||||
|
// ->footerHtml($footer);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// $browser = Browsershot::html($html);
|
||||||
|
// }
|
||||||
|
|
||||||
|
$browser = Browsershot::html($html);
|
||||||
|
|
||||||
|
|
||||||
|
return $browser->deviceScaleFactor(1)
|
||||||
|
->showBackground()
|
||||||
|
->deviceScaleFactor(1)
|
||||||
|
->waitUntilNetworkIdle(true)
|
||||||
|
->pdf();
|
||||||
|
|
||||||
|
// return Browsershot::html($html)
|
||||||
|
// //->showBrowserHeaderAndFooter()
|
||||||
|
// //->headerHtml($header)
|
||||||
|
// //->footerHtml($footer)
|
||||||
|
// ->deviceScaleFactor(1)
|
||||||
|
// ->showBackground()
|
||||||
|
// ->waitUntilNetworkIdle(true) ->pdf();
|
||||||
|
// //->margins(10,10,10,10)
|
||||||
|
// //->savePdf('test.pdf');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -969,6 +969,9 @@ class CreateUsersTable extends Migration
|
|||||||
$t->softDeletes('deleted_at', 6);
|
$t->softDeletes('deleted_at', 6);
|
||||||
$t->boolean('is_deleted')->default(false);
|
$t->boolean('is_deleted')->default(false);
|
||||||
$t->boolean('is_manual')->default(false);
|
$t->boolean('is_manual')->default(false);
|
||||||
|
$t->decimal('exchange_rate', 16, 6)->default(1);
|
||||||
|
$t->unsignedInteger('currency_id');
|
||||||
|
$t->unsignedInteger('exchange_currency_id');
|
||||||
|
|
||||||
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade')->onUpdate('cascade');
|
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade')->onUpdate('cascade');
|
||||||
$t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade')->onUpdate('cascade');
|
$t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade')->onUpdate('cascade');
|
||||||
|
@ -46,7 +46,8 @@ class DesignSeeder extends Seeder
|
|||||||
$design_object->header = $invoice_design->header();
|
$design_object->header = $invoice_design->header();
|
||||||
$design_object->body = $invoice_design->body();
|
$design_object->body = $invoice_design->body();
|
||||||
$design_object->table_styles = $invoice_design->table_styles();
|
$design_object->table_styles = $invoice_design->table_styles();
|
||||||
$design_object->table = $invoice_design->table();
|
$design_object->product_table = $invoice_design->product_table();
|
||||||
|
$design_object->task_table = $invoice_design->task_table();
|
||||||
$design_object->footer = $invoice_design->footer();
|
$design_object->footer = $invoice_design->footer();
|
||||||
|
|
||||||
$design->design = $design_object;
|
$design->design = $design_object;
|
||||||
|
@ -3129,8 +3129,8 @@ $LANG = array(
|
|||||||
'notification_partial_payment_paid' => 'A partial payment of :amount was made by client :client towards :invoice',
|
'notification_partial_payment_paid' => 'A partial payment of :amount was made by client :client towards :invoice',
|
||||||
'notification_bot' => 'Notification Bot',
|
'notification_bot' => 'Notification Bot',
|
||||||
'invoice_number_placeholder' => 'Invoice # :invoice',
|
'invoice_number_placeholder' => 'Invoice # :invoice',
|
||||||
|
'entity_number_placeholder' => ':entity # :entity_number',
|
||||||
'email_link_not_working' => 'If button above isn\'t working for you, please click on the link',
|
'email_link_not_working' => 'If button above isn\'t working for you, please click on the link',
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return $LANG;
|
return $LANG;
|
||||||
|
@ -116,6 +116,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
|||||||
Route::post('refresh', 'Auth\LoginController@refresh');
|
Route::post('refresh', 'Auth\LoginController@refresh');
|
||||||
|
|
||||||
Route::post('templates', 'TemplateController@show')->name('templates.show');
|
Route::post('templates', 'TemplateController@show')->name('templates.show');
|
||||||
|
|
||||||
|
Route::post('preview', 'PreviewController@show')->name('previews.show');
|
||||||
|
|
||||||
Route::post('self-update', 'SelfUpdateController@update')->middleware('password_protected');
|
Route::post('self-update', 'SelfUpdateController@update')->middleware('password_protected');
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ class DesignTest extends TestCase
|
|||||||
|
|
||||||
$modern = new Modern();
|
$modern = new Modern();
|
||||||
|
|
||||||
$designer = new Designer($modern, $this->company->settings->pdf_variables, 'quote');
|
$designer = new Designer($this->invoice, $modern, $this->company->settings->pdf_variables, 'quote');
|
||||||
|
|
||||||
$html = $designer->build($this->invoice)->getHtml();
|
$html = $designer->build()->getHtml();
|
||||||
|
|
||||||
$this->assertNotNull($html);
|
$this->assertNotNull($html);
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class DesignTest extends TestCase
|
|||||||
$this->invoice->uses_inclusive_taxes = false;
|
$this->invoice->uses_inclusive_taxes = false;
|
||||||
|
|
||||||
$settings = $this->invoice->client->settings;
|
$settings = $this->invoice->client->settings;
|
||||||
$settings->invoice_design_id = "5";
|
$settings->invoice_design_id = "4";
|
||||||
|
|
||||||
$this->client->settings = $settings;
|
$this->client->settings = $settings;
|
||||||
$this->client->save();
|
$this->client->save();
|
||||||
@ -61,16 +61,16 @@ class DesignTest extends TestCase
|
|||||||
|
|
||||||
$modern = new Modern();
|
$modern = new Modern();
|
||||||
|
|
||||||
$designer = new Designer($modern, $this->company->settings->pdf_variables, 'quote');
|
$designer = new Designer($this->quote, $modern, $this->company->settings->pdf_variables, 'quote');
|
||||||
|
|
||||||
$html = $designer->build($this->quote)->getHtml();
|
$html = $designer->build()->getHtml();
|
||||||
|
|
||||||
$this->assertNotNull($html);
|
$this->assertNotNull($html);
|
||||||
|
|
||||||
//\Log::error($html);
|
//\Log::error($html);
|
||||||
|
|
||||||
$settings = $this->invoice->client->settings;
|
$settings = $this->invoice->client->settings;
|
||||||
$settings->quote_design_id = "6";
|
$settings->quote_design_id = "4";
|
||||||
|
|
||||||
$this->quote->client_id = $this->client->id;
|
$this->quote->client_id = $this->client->id;
|
||||||
$this->quote->setRelation('client', $this->client);
|
$this->quote->setRelation('client', $this->client);
|
||||||
@ -82,19 +82,101 @@ class DesignTest extends TestCase
|
|||||||
CreateQuotePdf::dispatchNow($this->quote, $this->quote->company, $this->quote->client->primary_contact()->first());
|
CreateQuotePdf::dispatchNow($this->quote, $this->quote->company, $this->quote->client->primary_contact()->first());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
// }
|
||||||
|
|
||||||
public function testCreditDesignExists()
|
public function testCreditDesignExists()
|
||||||
{
|
{
|
||||||
|
|
||||||
$modern = new Modern();
|
$modern = new Modern();
|
||||||
|
|
||||||
$designer = new Designer($modern, $this->company->settings->pdf_variables, 'credit');
|
$designer = new Designer($this->credit, $modern, $this->company->settings->pdf_variables, 'credit');
|
||||||
|
|
||||||
$html = $designer->build($this->credit)->getHtml();
|
$html = $designer->build()->getHtml();
|
||||||
|
|
||||||
$this->assertNotNull($html);
|
$this->assertNotNull($html);
|
||||||
|
|
||||||
$settings = $this->invoice->client->settings;
|
$settings = $this->invoice->client->settings;
|
||||||
$settings->quote_design_id = "6";
|
$settings->quote_design_id = "4";
|
||||||
|
|
||||||
$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);
|
||||||
@ -106,32 +188,32 @@ class DesignTest extends TestCase
|
|||||||
CreateCreditPdf::dispatchNow($this->credit, $this->credit->company, $this->credit->client->primary_contact()->first());
|
CreateCreditPdf::dispatchNow($this->credit, $this->credit->company, $this->credit->client->primary_contact()->first());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAllDesigns()
|
// public function testAllDesigns()
|
||||||
{
|
// {
|
||||||
|
|
||||||
for($x=1; $x<=10; $x++)
|
// for($x=1; $x<=10; $x++)
|
||||||
{
|
// {
|
||||||
|
|
||||||
$settings = $this->invoice->client->settings;
|
// $settings = $this->invoice->client->settings;
|
||||||
$settings->quote_design_id = (string)$x;
|
// $settings->quote_design_id = (string)$x;
|
||||||
|
|
||||||
$this->quote->client_id = $this->client->id;
|
// $this->quote->client_id = $this->client->id;
|
||||||
$this->quote->setRelation('client', $this->client);
|
// $this->quote->setRelation('client', $this->client);
|
||||||
$this->quote->save();
|
// $this->quote->save();
|
||||||
|
|
||||||
$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());
|
// CreateQuotePdf::dispatchNow($this->quote, $this->quote->company, $this->quote->client->primary_contact()->first());
|
||||||
|
|
||||||
$this->quote->number = $this->getNextQuoteNumber($this->quote->client);
|
// $this->quote->number = $this->getNextQuoteNumber($this->quote->client);
|
||||||
$this->quote->save();
|
// $this->quote->save();
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
$this->assertTrue(true);
|
// $this->assertTrue(true);
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,6 +394,51 @@ trait MockAccountData
|
|||||||
|
|
||||||
$line_items[] = $item;
|
$line_items[] = $item;
|
||||||
|
|
||||||
|
$item = InvoiceItemFactory::create();
|
||||||
|
$item->quantity = 1;
|
||||||
|
$item->cost =10;
|
||||||
|
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
$line_items[] = $item;
|
||||||
|
|
||||||
return $line_items;
|
return $line_items;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user