diff --git a/app/Http/Controllers/PublicClientController.php b/app/Http/Controllers/PublicClientController.php index 7aca779532ba..2d7f980af2a8 100644 --- a/app/Http/Controllers/PublicClientController.php +++ b/app/Http/Controllers/PublicClientController.php @@ -16,6 +16,7 @@ use App\Models\Document; use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\PaymentRepository; use App\Ninja\Repositories\ActivityRepository; +use App\Ninja\Repositories\DocumentRepository; use App\Events\InvoiceInvitationWasViewed; use App\Events\QuoteInvitationWasViewed; use App\Services\PaymentService; @@ -27,11 +28,12 @@ class PublicClientController extends BaseController private $paymentRepo; private $documentRepo; - public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo, PaymentService $paymentService) + public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo, DocumentRepository $documentRepo, PaymentService $paymentService) { $this->invoiceRepo = $invoiceRepo; $this->paymentRepo = $paymentRepo; $this->activityRepo = $activityRepo; + $this->documentRepo = $documentRepo; $this->paymentService = $paymentService; } @@ -123,6 +125,7 @@ class PublicClientController extends BaseController 'hideLogo' => $account->isWhiteLabel(), 'hideHeader' => $account->isNinjaAccount(), 'hideDashboard' => !$account->enable_client_portal, + 'showDocuments' => $account->isPro(), 'clientViewCSS' => $account->clientViewCSS(), 'clientFontUrl' => $account->getFontsUrl(), 'invoice' => $invoice->hidePrivateFields(), @@ -271,6 +274,7 @@ class PublicClientController extends BaseController 'color' => $color, 'hideLogo' => $account->isWhiteLabel(), 'hideDashboard' => !$account->enable_client_portal, + 'showDocuments' => $account->isPro(), 'clientViewCSS' => $account->clientViewCSS(), 'clientFontUrl' => $account->getFontsUrl(), 'title' => trans('texts.invoices'), @@ -303,6 +307,7 @@ class PublicClientController extends BaseController 'color' => $color, 'hideLogo' => $account->isWhiteLabel(), 'hideDashboard' => !$account->enable_client_portal, + 'showDocuments' => $account->isPro(), 'clientViewCSS' => $account->clientViewCSS(), 'clientFontUrl' => $account->getFontsUrl(), 'entityType' => ENTITY_PAYMENT, @@ -341,6 +346,7 @@ class PublicClientController extends BaseController 'color' => $color, 'hideLogo' => $account->isWhiteLabel(), 'hideDashboard' => !$account->enable_client_portal, + 'showDocuments' => $account->isPro(), 'clientViewCSS' => $account->clientViewCSS(), 'clientFontUrl' => $account->getFontsUrl(), 'title' => trans('texts.quotes'), @@ -361,6 +367,39 @@ class PublicClientController extends BaseController return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, Input::get('sSearch')); } + public function documentIndex() + { + if (!$invitation = $this->getInvitation()) { + return $this->returnError(); + } + $account = $invitation->account; + $color = $account->primary_color ? $account->primary_color : '#0b4d78'; + + $data = [ + 'color' => $color, + 'hideLogo' => $account->isWhiteLabel(), + 'hideDashboard' => !$account->enable_client_portal, + 'showDocuments' => $account->isPro(), + 'clientViewCSS' => $account->clientViewCSS(), + 'clientFontUrl' => $account->getFontsUrl(), + 'title' => trans('texts.documents'), + 'entityType' => ENTITY_DOCUMENT, + 'columns' => Utils::trans(['invoice_number', 'name', 'document_date', 'document_size']), + ]; + + return response()->view('public_list', $data); + } + + + public function documentDatatable() + { + if (!$invitation = $this->getInvitation()) { + return false; + } + + return $this->documentRepo->getClientDatatable($invitation->contact_id, ENTITY_DOCUMENT, Input::get('sSearch')); + } + private function returnError($error = false) { return response()->view('error', [ diff --git a/app/Http/routes.php b/app/Http/routes.php index 0aaec6a1f925..426b22f8d399 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -45,17 +45,20 @@ Route::group(['middleware' => 'auth:client'], function() { Route::get('complete', 'PaymentController@offsite_payment'); Route::get('client/quotes', 'PublicClientController@quoteIndex'); Route::get('client/invoices', 'PublicClientController@invoiceIndex'); + Route::get('client/documents', 'PublicClientController@documentIndex'); Route::get('client/payments', 'PublicClientController@paymentIndex'); 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')); + Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'PublicClientController@invoiceDatatable')); + Route::get('api/client.documents', array('as'=>'api.client.documents', 'uses'=>'PublicClientController@documentDatatable')); + Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'PublicClientController@paymentDatatable')); + Route::get('api/client.activity', array('as'=>'api.client.activity', 'uses'=>'PublicClientController@activityDatatable')); }); -Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'PublicClientController@quoteDatatable')); -Route::get('api/client.invoices', array('as'=>'api.client.invoices', 'uses'=>'PublicClientController@invoiceDatatable')); -Route::get('api/client.payments', array('as'=>'api.client.payments', 'uses'=>'PublicClientController@paymentDatatable')); -Route::get('api/client.activity', array('as'=>'api.client.activity', 'uses'=>'PublicClientController@activityDatatable')); Route::get('license', 'PaymentController@show_license_payment'); Route::post('license', 'PaymentController@do_license_payment'); @@ -318,6 +321,7 @@ if (!defined('CONTACT_EMAIL')) { define('ENTITY_CLIENT', 'client'); define('ENTITY_CONTACT', 'contact'); define('ENTITY_INVOICE', 'invoice'); + define('ENTITY_DOCUMENT', 'document'); define('ENTITY_INVOICE_ITEMS', 'invoice_items'); define('ENTITY_INVITATION', 'invitation'); define('ENTITY_RECURRING_INVOICE', 'recurring_invoice'); diff --git a/app/Ninja/Repositories/DocumentRepository.php b/app/Ninja/Repositories/DocumentRepository.php index ce4c7fd9d8a4..7fcd954b1ed6 100644 --- a/app/Ninja/Repositories/DocumentRepository.php +++ b/app/Ninja/Repositories/DocumentRepository.php @@ -7,6 +7,7 @@ use App\Models\Document; use App\Ninja\Repositories\BaseRepository; use Intervention\Image\ImageManager; use Session; +use Form; class DocumentRepository extends BaseRepository { @@ -188,4 +189,51 @@ class DocumentRepository extends BaseRepository 'code' => 200 ], 200); } + + public function getClientDatatable($contactId, $entityType, $search) + { + $query = DB::table('invitations') + ->join('accounts', 'accounts.id', '=', 'invitations.account_id') + ->join('invoices', 'invoices.id', '=', 'invitations.invoice_id') + ->join('documents', 'documents.invoice_id', '=', 'invitations.invoice_id') + ->join('clients', 'clients.id', '=', 'invoices.client_id') + ->where('invitations.contact_id', '=', $contactId) + ->where('invitations.deleted_at', '=', null) + ->where('invoices.is_deleted', '=', false) + ->where('clients.deleted_at', '=', null) + ->where('invoices.is_recurring', '=', false) + // This needs to be a setting to also hide the activity on the dashboard page + //->where('invoices.invoice_status_id', '>=', INVOICE_STATUS_SENT) + ->select( + 'invitations.invitation_key', + 'invoices.invoice_number', + 'documents.name', + 'documents.public_id', + 'documents.created_at', + 'documents.size' + ); + + $table = \Datatable::query($query) + ->addColumn('invoice_number', function ($model) { + return link_to( + '/view/'.$model->invitation_key, + $model->invoice_number + )->toHtml(); + }) + ->addColumn('name', function ($model) { + return link_to( + '/client/document/'.$model->invitation_key.'/'.$model->public_id.'/'.$model->name, + $model->name, + ['target'=>'_blank'] + )->toHtml(); + }) + ->addColumn('document_date', function ($model) { + return Utils::fromSqlDate($model->created_at); + }) + ->addColumn('document_size', function ($model) { + return Form::human_filesize($model->size); + }); + + return $table->make(); + } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 8a6760718a75..d5f26393681f 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -162,6 +162,7 @@ class AppServiceProvider extends ServiceProvider { Form::macro('human_filesize', function($bytes, $decimals = 1) { $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); $factor = floor((strlen($bytes) - 1) / 3); + if($factor == 0)$decimals=0;// There aren't fractional bytes return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . @$size[$factor]; }); diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index ec8ba2a2c474..4db617943e20 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -1108,6 +1108,9 @@ $LANG = array( 'invoice_embed_documents_help' => 'Include attached images in the invoice.', 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', + 'documents' => 'Documents', + 'document_date' => 'Document Date', + 'document_size' => 'Size', ); return $LANG; diff --git a/resources/views/public/header.blade.php b/resources/views/public/header.blade.php index 929bda00e419..4f753b4a8d3e 100644 --- a/resources/views/public/header.blade.php +++ b/resources/views/public/header.blade.php @@ -87,6 +87,11 @@
  • {!! link_to('/client/invoices', trans('texts.invoices') ) !!}
  • + @if (!empty($showDocuments)) +
  • + {!! link_to('/client/documents', trans('texts.documents') ) !!} +
  • + @endif
  • {!! link_to('/client/payments', trans('texts.payments') ) !!}