mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #6943 from beganovich/jira-767
Support for images on PDFs
This commit is contained in:
commit
eee5ce9813
30
app/Helpers/Document/WithTypeHelpers.php
Normal file
30
app/Helpers/Document/WithTypeHelpers.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Helpers\Document;
|
||||||
|
|
||||||
|
trait WithTypeHelpers
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns boolean based on checks for image.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isImage(): bool
|
||||||
|
{
|
||||||
|
if (in_array($this->type, ['png', 'svg', 'jpeg', 'jpg', 'tiff', 'gif'])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Helpers\Document\WithTypeHelpers;
|
||||||
use App\Models\Filterable;
|
use App\Models\Filterable;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
@ -19,6 +20,7 @@ class Document extends BaseModel
|
|||||||
{
|
{
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use Filterable;
|
use Filterable;
|
||||||
|
use WithTypeHelpers;
|
||||||
|
|
||||||
const DOCUMENT_PREVIEW_SIZE = 300; // pixels
|
const DOCUMENT_PREVIEW_SIZE = 300; // pixels
|
||||||
|
|
||||||
|
@ -481,6 +481,8 @@ class HtmlEngine
|
|||||||
$data['$statement_amount'] = ['value' => '', 'label' => ctrans('texts.amount')];
|
$data['$statement_amount'] = ['value' => '', 'label' => ctrans('texts.amount')];
|
||||||
$data['$statement'] = ['value' => '', 'label' => ctrans('texts.statement')];
|
$data['$statement'] = ['value' => '', 'label' => ctrans('texts.statement')];
|
||||||
|
|
||||||
|
$data['$entity_images'] = ['value' => $this->generateEntityImagesMarkup(), 'label' => ''];
|
||||||
|
|
||||||
$arrKeysLength = array_map('strlen', array_keys($data));
|
$arrKeysLength = array_map('strlen', array_keys($data));
|
||||||
array_multisort($arrKeysLength, SORT_DESC, $data);
|
array_multisort($arrKeysLength, SORT_DESC, $data);
|
||||||
|
|
||||||
@ -737,4 +739,38 @@ html {
|
|||||||
|
|
||||||
return $css;
|
return $css;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate markup for HTML images on entity.
|
||||||
|
*
|
||||||
|
* @return string|void
|
||||||
|
*/
|
||||||
|
protected function generateEntityImagesMarkup()
|
||||||
|
{
|
||||||
|
if ($this->client->getSetting('embed_documents') === false) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||||
|
|
||||||
|
$container = $dom->createElement('div');
|
||||||
|
$container->setAttribute('style', 'display:grid; grid-auto-flow: row; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(2, 1fr);');
|
||||||
|
|
||||||
|
foreach ($this->entity->documents as $document) {
|
||||||
|
if (!$document->isImage()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$image = $dom->createElement('img');
|
||||||
|
|
||||||
|
$image->setAttribute('src', $document->generateUrl());
|
||||||
|
$image->setAttribute('style', 'max-height: 100px; margin-top: 20px;');
|
||||||
|
|
||||||
|
$container->appendChild($image);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dom->appendChild($container);
|
||||||
|
|
||||||
|
return $dom->saveHTML();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,6 +367,9 @@
|
|||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div>
|
<div>
|
||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
|
@ -347,6 +347,8 @@
|
|||||||
|
|
||||||
<div class="repeating-header" id="header"></div>
|
<div class="repeating-header" id="header"></div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<div class="repeating-footer" id="footer">
|
<div class="repeating-footer" id="footer">
|
||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -309,6 +309,8 @@
|
|||||||
|
|
||||||
<div class="repeating-header" id="header"></div>
|
<div class="repeating-header" id="header"></div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<div class="repeating-footer" id="footer">
|
<div class="repeating-footer" id="footer">
|
||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -307,6 +307,8 @@
|
|||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
@ -317,6 +317,8 @@
|
|||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
@ -358,6 +358,8 @@
|
|||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
@ -344,6 +344,8 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div class="footer-content">
|
<div class="footer-content">
|
||||||
<div>
|
<div>
|
||||||
|
@ -292,6 +292,8 @@
|
|||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
@ -375,7 +375,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="repeating-footer" id="footer">
|
$entity_images
|
||||||
|
|
||||||
|
<div class="repeating-footer" id="footer">
|
||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
|
|
||||||
<div id="footer-colors">
|
<div id="footer-colors">
|
||||||
|
@ -357,6 +357,8 @@
|
|||||||
<p data-ref="total_table-footer">$entity_footer</p>
|
<p data-ref="total_table-footer">$entity_footer</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
$entity_images
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
45
tests/Unit/WithTypeHelpersTest.php
Normal file
45
tests/Unit/WithTypeHelpersTest.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\Document;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class WithTypeHelpersTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testIsImageHelper(): void
|
||||||
|
{
|
||||||
|
$account = Account::factory()->create();
|
||||||
|
|
||||||
|
$company = Company::factory()->create([
|
||||||
|
'account_id' => $account->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/** @var Document */
|
||||||
|
$document = Document::factory()->create([
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'type' => 'jpeg',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertTrue($document->isImage());
|
||||||
|
|
||||||
|
/** @var Document */
|
||||||
|
$document = Document::factory()->create([
|
||||||
|
'company_id' => $company->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertFalse($document->isImage());
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user