mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-17 16:42:48 +01:00
Display documents and zip download on client invoice page
This commit is contained in:
parent
2a7e8cb4b7
commit
e6056104bd
@ -19,6 +19,8 @@ use App\Ninja\Repositories\ActivityRepository;
|
||||
use App\Events\InvoiceInvitationWasViewed;
|
||||
use App\Events\QuoteInvitationWasViewed;
|
||||
use App\Services\PaymentService;
|
||||
use League\Flysystem\Filesystem;
|
||||
use League\Flysystem\ZipArchive\ZipArchiveAdapter;
|
||||
|
||||
class PublicClientController extends BaseController
|
||||
{
|
||||
@ -135,6 +137,10 @@ class PublicClientController extends BaseController
|
||||
'checkoutComDebug' => $checkoutComDebug,
|
||||
'phantomjs' => Input::has('phantomjs'),
|
||||
);
|
||||
|
||||
if($account->isPro() && $this->canCreateInvoiceDocsZip($invoice)){
|
||||
$data['documentsZipURL'] = URL::to("client/documents/{$invitation->invitation_key}");
|
||||
}
|
||||
|
||||
return View::make('invoices.view', $data);
|
||||
}
|
||||
@ -375,9 +381,7 @@ class PublicClientController extends BaseController
|
||||
|
||||
return $invitation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public function getDocumentVFSJS($publicId, $name){
|
||||
if (!$invitation = $this->getInvitation()) {
|
||||
return $this->returnError();
|
||||
@ -415,6 +419,101 @@ class PublicClientController extends BaseController
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function canCreateZip(){
|
||||
return function_exists('gmp_init');
|
||||
}
|
||||
|
||||
protected function canCreateInvoiceDocsZip($invoice){
|
||||
if(!$this->canCreateZip())return false;
|
||||
if(count($invoice->documents) == 1)return false;
|
||||
|
||||
$maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000;
|
||||
$i = 0;
|
||||
foreach($invoice->documents as $document){
|
||||
if($document->size <= $maxSize)$i++;
|
||||
if($i > 1){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getInvoiceDocumentsZip($invitationKey){
|
||||
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
||||
return $this->returnError();
|
||||
}
|
||||
|
||||
Session::put('invitation_key', $invitationKey); // track current invitation
|
||||
|
||||
$invoice = $invitation->invoice;
|
||||
|
||||
if(!count($invoice->documents)){
|
||||
return Response::view('error', array('error'=>'No documents'), 404);
|
||||
}
|
||||
|
||||
$documents = $invoice->documents->sortBy('size');
|
||||
|
||||
$size = 0;
|
||||
$maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000;
|
||||
$toZip = array();
|
||||
foreach($documents as $document){
|
||||
$size += $document->size;
|
||||
if($size > $maxSize)break;
|
||||
|
||||
if(!empty($toZip[$document->name])){
|
||||
$hasSameHash = false;
|
||||
foreach($toZip[$document->name] as $sameName){
|
||||
if($sameName->hash == $document->hash){
|
||||
$hasSameHash = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$hasSameHash){
|
||||
// 2 different files with the same name
|
||||
$toZip[$document->name][] = $document;
|
||||
}
|
||||
else{
|
||||
// We're not adding this after all
|
||||
$size -= $document->size;
|
||||
}
|
||||
}
|
||||
else{
|
||||
$toZip[$document->name] = array($document);
|
||||
}
|
||||
}
|
||||
|
||||
if(!count($toZip)){
|
||||
return Response::view('error', array('error'=>'No documents small enough'), 404);
|
||||
}
|
||||
|
||||
$zip = new \Barracuda\ArchiveStream\ZipArchive($invitation->account->name.' Invoice '.$invoice->invoice_number.'.zip');
|
||||
return Response::stream(function() use ($toZip, $zip) {
|
||||
foreach($toZip as $documentsSameName){
|
||||
$i = 0;
|
||||
foreach($documentsSameName as $document){
|
||||
$name = $document->name;
|
||||
|
||||
if($i){
|
||||
$nameInfo = pathinfo($document->name);
|
||||
$name = $nameInfo['filename'].' ('.$i.').'.$nameInfo['extension'];
|
||||
}
|
||||
|
||||
$fileStream = $document->getStream();
|
||||
if($fileStream){
|
||||
$zip->init_file_stream_transfer($name, $document->size);
|
||||
while ($buffer = fread($fileStream, 8192))$zip->stream_file_part($buffer);
|
||||
fclose($fileStream);
|
||||
$zip->complete_file_stream();
|
||||
}
|
||||
else{
|
||||
$zip->add_file($name, $document->getRaw());
|
||||
}
|
||||
}
|
||||
}
|
||||
$zip->finish();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
public function getDocument($invitationKey, $publicId){
|
||||
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
||||
|
@ -49,6 +49,7 @@ Route::group(['middleware' => 'auth:client'], function() {
|
||||
Route::get('client/dashboard', 'PublicClientController@dashboard');
|
||||
Route::get('client/document/js/{public_id}/{filename}', 'PublicClientController@getDocumentVFSJS');
|
||||
Route::get('client/document/{invitation_key}/{public_id}/{filename?}', 'PublicClientController@getDocument');
|
||||
Route::get('client/documents/{invitation_key}/{filename?}', 'PublicClientController@getInvoiceDocumentsZip');
|
||||
});
|
||||
|
||||
Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'PublicClientController@quoteDatatable'));
|
||||
@ -434,6 +435,7 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('MAX_FAILED_LOGINS', 10);
|
||||
define('MAX_DOCUMENT_SIZE', env('MAX_DOCUMENT_SIZE', 10000));// KB
|
||||
define('MAX_EMAIL_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 10000));// Total KB
|
||||
define('MAX_ZIP_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 30000));// Total KB (uncompressed)
|
||||
define('DOCUMENT_PREVIEW_SIZE', env('DOCUMENT_PREVIEW_SIZE', 300));// pixels
|
||||
define('DEFAULT_FONT_SIZE', 9);
|
||||
define('DEFAULT_HEADER_FONT', 1);// Roboto
|
||||
|
@ -158,6 +158,7 @@ class DocumentRepository extends BaseRepository
|
||||
$document->path = $filename;
|
||||
$document->type = $documentType;
|
||||
$document->size = $size;
|
||||
$document->hash = $hash;
|
||||
$document->name = substr($name, -255);
|
||||
|
||||
if(!empty($imageSize)){
|
||||
|
@ -68,7 +68,8 @@
|
||||
"cerdic/css-tidy": "~v1.5",
|
||||
"asgrim/ofxparser": "^1.1",
|
||||
"league/flysystem-aws-s3-v3": "~1.0",
|
||||
"league/flysystem-rackspace": "~1.0"
|
||||
"league/flysystem-rackspace": "~1.0",
|
||||
"barracudanetworks/archivestream-php": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0",
|
||||
|
44
composer.lock
generated
44
composer.lock
generated
@ -4,8 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "aa7451471a31552d5d6dce491ec20272",
|
||||
"content-hash": "d70446a01a12bb41eece33b979adc975",
|
||||
"hash": "5b6b0afc0a26fa2b1dc48241fd665c1e",
|
||||
"content-hash": "33f39a8d05247b96374ed20e95499936",
|
||||
"packages": [
|
||||
{
|
||||
"name": "agmscode/omnipay-agms",
|
||||
@ -401,6 +401,46 @@
|
||||
],
|
||||
"time": "2016-03-22 19:19:22"
|
||||
},
|
||||
{
|
||||
"name": "barracudanetworks/archivestream-php",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barracudanetworks/ArchiveStream-php.git",
|
||||
"reference": "9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barracudanetworks/ArchiveStream-php/zipball/9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6",
|
||||
"reference": "9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gmp": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=5.1.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Barracuda\\ArchiveStream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A library for dynamically streaming dynamic tar or zip files without the need to have the complete file stored on the server.",
|
||||
"homepage": "https://github.com/barracudanetworks/ArchiveStream-php",
|
||||
"keywords": [
|
||||
"archive",
|
||||
"php",
|
||||
"stream",
|
||||
"tar",
|
||||
"zip"
|
||||
],
|
||||
"time": "2016-01-07 06:02:26"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-debugbar",
|
||||
"version": "v2.2.0",
|
||||
|
@ -34,6 +34,7 @@ class AddDocuments extends Migration {
|
||||
$t->string('name');
|
||||
$t->string('type');
|
||||
$t->string('disk');
|
||||
$t->string('hash', 40);
|
||||
$t->unsignedInteger('size');
|
||||
$t->unsignedInteger('width')->nullable();
|
||||
$t->unsignedInteger('height')->nullable();
|
||||
|
@ -1098,6 +1098,7 @@ $LANG = array(
|
||||
'december' => 'December',
|
||||
|
||||
// Documents
|
||||
'documents_header' => 'Documents:',
|
||||
'email_documents_header' => 'Documents:',
|
||||
'email_documents_example_1' => 'Widgets Receipt.pdf',
|
||||
'email_documents_example_2' => 'Final Deliverable.zip',
|
||||
@ -1106,6 +1107,7 @@ $LANG = array(
|
||||
'invoice_embed_documents' => 'Embed Documents',
|
||||
'invoice_embed_documents_help' => 'Include attached images in the invoice.',
|
||||
'document_email_attachment' => 'Attach Documents',
|
||||
'download_documents' => 'Download Documents',
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -24,7 +24,6 @@
|
||||
@if ($checkoutComToken)
|
||||
@include('partials.checkout_com_payment')
|
||||
@else
|
||||
<p> </p>
|
||||
<div class="pull-right" style="text-align:right">
|
||||
@if ($invoice->is_quote)
|
||||
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
|
||||
@ -39,12 +38,28 @@
|
||||
<a href='{!! $paymentURL !!}' class="btn btn-success btn-lg">{{ trans('texts.pay_now') }}</a>
|
||||
@endif
|
||||
@else
|
||||
{!! Button::normal('Download PDF')->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
|
||||
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
|
||||
@endif
|
||||
</div>
|
||||
<div class="pull-left">
|
||||
@if(!empty($documentsZipURL))
|
||||
{!! Button::normal(trans('texts.download_documents'))->asLinkTo($documentsZipURL)->large() !!}
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="clearfix"></div><p> </p>
|
||||
@if ($account->isPro() && count($invoice->documents))
|
||||
<div class="invoice-documents">
|
||||
<h3>{{ trans('texts.documents_header') }}</h3>
|
||||
<ul>
|
||||
@foreach ($invoice->documents as $document)
|
||||
<li><a target="_blank" href="{{ $document->getClientUrl($invitation) }}">{{$document->name}}</a></li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($account->isPro() && $account->invoice_embed_documents)
|
||||
@foreach ($invoice->documents as $document)
|
||||
<script src="{{ $document->getClientVFSJSUrl() }}" type="text/javascript" {{ Input::has('phantomjs')?'':'async' }}></script>
|
||||
|
Loading…
Reference in New Issue
Block a user