2015-10-13 17:44:01 +02:00
|
|
|
<?php namespace App\Http\Controllers;
|
|
|
|
|
|
|
|
use Auth;
|
2016-01-18 09:30:42 +01:00
|
|
|
use View;
|
2015-10-13 17:44:01 +02:00
|
|
|
use DB;
|
2016-01-18 09:30:42 +01:00
|
|
|
use URL;
|
2015-10-13 17:44:01 +02:00
|
|
|
use Input;
|
|
|
|
use Utils;
|
2016-01-18 09:30:42 +01:00
|
|
|
use Request;
|
2016-03-23 23:40:42 +01:00
|
|
|
use Response;
|
2016-01-18 09:30:42 +01:00
|
|
|
use Session;
|
2015-10-13 17:44:01 +02:00
|
|
|
use Datatable;
|
2016-01-18 09:30:42 +01:00
|
|
|
use App\Models\Gateway;
|
2015-10-13 17:44:01 +02:00
|
|
|
use App\Models\Invitation;
|
2016-03-23 23:40:42 +01:00
|
|
|
use App\Models\Document;
|
2015-10-13 17:44:01 +02:00
|
|
|
use App\Ninja\Repositories\InvoiceRepository;
|
|
|
|
use App\Ninja\Repositories\PaymentRepository;
|
2015-10-28 20:22:07 +01:00
|
|
|
use App\Ninja\Repositories\ActivityRepository;
|
2016-03-24 16:58:30 +01:00
|
|
|
use App\Ninja\Repositories\DocumentRepository;
|
2016-01-18 09:30:42 +01:00
|
|
|
use App\Events\InvoiceInvitationWasViewed;
|
|
|
|
use App\Events\QuoteInvitationWasViewed;
|
|
|
|
use App\Services\PaymentService;
|
2016-03-24 16:33:28 +01:00
|
|
|
use Barracuda\ArchiveStream\ZipArchive;
|
2015-10-13 17:44:01 +02:00
|
|
|
|
|
|
|
class PublicClientController extends BaseController
|
|
|
|
{
|
|
|
|
private $invoiceRepo;
|
|
|
|
private $paymentRepo;
|
2016-03-23 23:40:42 +01:00
|
|
|
private $documentRepo;
|
2015-10-13 17:44:01 +02:00
|
|
|
|
2016-03-24 16:58:30 +01:00
|
|
|
public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo, DocumentRepository $documentRepo, PaymentService $paymentService)
|
2015-10-13 17:44:01 +02:00
|
|
|
{
|
|
|
|
$this->invoiceRepo = $invoiceRepo;
|
|
|
|
$this->paymentRepo = $paymentRepo;
|
2015-10-28 20:22:07 +01:00
|
|
|
$this->activityRepo = $activityRepo;
|
2016-03-24 16:58:30 +01:00
|
|
|
$this->documentRepo = $documentRepo;
|
2016-01-18 09:30:42 +01:00
|
|
|
$this->paymentService = $paymentService;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function view($invitationKey)
|
|
|
|
{
|
|
|
|
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
2016-03-01 08:36:37 +01:00
|
|
|
return $this->returnError();
|
2016-01-18 09:30:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$invoice = $invitation->invoice;
|
|
|
|
$client = $invoice->client;
|
|
|
|
$account = $invoice->account;
|
|
|
|
|
|
|
|
if (!$account->checkSubdomain(Request::server('HTTP_HOST'))) {
|
|
|
|
return response()->view('error', [
|
|
|
|
'error' => trans('texts.invoice_not_found'),
|
|
|
|
'hideHeader' => true,
|
|
|
|
'clientViewCSS' => $account->clientViewCSS(),
|
|
|
|
'clientFontUrl' => $account->getFontsUrl(),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2016-03-14 19:23:20 +01:00
|
|
|
if (!Input::has('phantomjs') && !Input::has('silent') && !Session::has($invitationKey)
|
|
|
|
&& (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
|
2016-01-18 09:30:42 +01:00
|
|
|
if ($invoice->is_quote) {
|
|
|
|
event(new QuoteInvitationWasViewed($invoice, $invitation));
|
|
|
|
} else {
|
|
|
|
event(new InvoiceInvitationWasViewed($invoice, $invitation));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Session::put($invitationKey, true); // track this invitation has been seen
|
|
|
|
Session::put('invitation_key', $invitationKey); // track current invitation
|
|
|
|
|
|
|
|
$account->loadLocalizationSettings($client);
|
|
|
|
|
|
|
|
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
|
|
|
|
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
2016-04-19 04:35:18 +02:00
|
|
|
$invoice->features = [
|
|
|
|
'customize_invoice_design' => $account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
|
|
|
'remove_created_by' => $account->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
|
|
|
'invoice_settings' => $account->hasFeature(FEATURE_INVOICE_SETTINGS),
|
|
|
|
];
|
2016-01-18 09:30:42 +01:00
|
|
|
$invoice->invoice_fonts = $account->getFontsData();
|
|
|
|
|
|
|
|
if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
|
|
|
|
$invoice->invoice_design->javascript = $account->custom_design;
|
|
|
|
} else {
|
|
|
|
$invoice->invoice_design->javascript = $invoice->invoice_design->pdfmake;
|
|
|
|
}
|
|
|
|
$contact = $invitation->contact;
|
|
|
|
$contact->setVisible([
|
|
|
|
'first_name',
|
|
|
|
'last_name',
|
|
|
|
'email',
|
|
|
|
'phone',
|
|
|
|
]);
|
|
|
|
|
|
|
|
$paymentTypes = $this->getPaymentTypes($client, $invitation);
|
|
|
|
$paymentURL = '';
|
|
|
|
if (count($paymentTypes)) {
|
|
|
|
$paymentURL = $paymentTypes[0]['url'];
|
|
|
|
if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
|
|
|
|
$paymentURL = URL::to($paymentURL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$showApprove = $invoice->quote_invoice_id ? false : true;
|
|
|
|
if ($invoice->due_date) {
|
|
|
|
$showApprove = time() < strtotime($invoice->due_date);
|
|
|
|
}
|
2016-01-20 09:41:57 +01:00
|
|
|
if ($invoice->invoice_status_id >= INVOICE_STATUS_APPROVED) {
|
|
|
|
$showApprove = false;
|
|
|
|
}
|
2016-01-18 09:30:42 +01:00
|
|
|
|
|
|
|
// Checkout.com requires first getting a payment token
|
|
|
|
$checkoutComToken = false;
|
|
|
|
$checkoutComKey = false;
|
2016-03-09 15:58:21 +01:00
|
|
|
$checkoutComDebug = false;
|
2016-01-18 09:30:42 +01:00
|
|
|
if ($accountGateway = $account->getGatewayConfig(GATEWAY_CHECKOUT_COM)) {
|
2016-03-09 15:58:21 +01:00
|
|
|
$checkoutComDebug = $accountGateway->getConfigField('testMode');
|
2016-01-18 09:30:42 +01:00
|
|
|
if ($checkoutComToken = $this->paymentService->getCheckoutComToken($invitation)) {
|
|
|
|
$checkoutComKey = $accountGateway->getConfigField('publicApiKey');
|
|
|
|
$invitation->transaction_reference = $checkoutComToken;
|
|
|
|
$invitation->save();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$data = array(
|
|
|
|
'account' => $account,
|
|
|
|
'showApprove' => $showApprove,
|
|
|
|
'showBreadcrumbs' => false,
|
2016-04-19 04:35:18 +02:00
|
|
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
2016-04-13 21:08:41 +02:00
|
|
|
'hideHeader' => $account->isNinjaAccount() || !$account->enable_client_portal,
|
|
|
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
2016-04-19 04:35:18 +02:00
|
|
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
2016-01-18 09:30:42 +01:00
|
|
|
'clientViewCSS' => $account->clientViewCSS(),
|
|
|
|
'clientFontUrl' => $account->getFontsUrl(),
|
|
|
|
'invoice' => $invoice->hidePrivateFields(),
|
|
|
|
'invitation' => $invitation,
|
|
|
|
'invoiceLabels' => $account->getInvoiceLabels(),
|
|
|
|
'contact' => $contact,
|
|
|
|
'paymentTypes' => $paymentTypes,
|
|
|
|
'paymentURL' => $paymentURL,
|
|
|
|
'checkoutComToken' => $checkoutComToken,
|
|
|
|
'checkoutComKey' => $checkoutComKey,
|
2016-03-09 15:58:21 +01:00
|
|
|
'checkoutComDebug' => $checkoutComDebug,
|
2016-01-18 09:30:42 +01:00
|
|
|
'phantomjs' => Input::has('phantomjs'),
|
|
|
|
);
|
2016-03-24 03:41:19 +01:00
|
|
|
|
2016-04-19 04:35:18 +02:00
|
|
|
if($account->hasFeature(FEATURE_DOCUMENTS) && $this->canCreateZip()){
|
2016-03-24 16:33:28 +01:00
|
|
|
$zipDocs = $this->getInvoiceZipDocuments($invoice, $size);
|
|
|
|
|
|
|
|
if(count($zipDocs) > 1){
|
|
|
|
$data['documentsZipURL'] = URL::to("client/documents/{$invitation->invitation_key}");
|
|
|
|
$data['documentsZipSize'] = $size;
|
|
|
|
}
|
2016-03-24 03:41:19 +01:00
|
|
|
}
|
2016-01-18 09:30:42 +01:00
|
|
|
|
|
|
|
return View::make('invoices.view', $data);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getPaymentTypes($client, $invitation)
|
|
|
|
{
|
|
|
|
$paymentTypes = [];
|
|
|
|
$account = $client->account;
|
|
|
|
|
|
|
|
if ($client->getGatewayToken()) {
|
|
|
|
$paymentTypes[] = [
|
|
|
|
'url' => URL::to("payment/{$invitation->invitation_key}/token"), 'label' => trans('texts.use_card_on_file')
|
|
|
|
];
|
|
|
|
}
|
|
|
|
foreach(Gateway::$paymentTypes as $type) {
|
|
|
|
if ($account->getGatewayByType($type)) {
|
|
|
|
$typeLink = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
|
|
|
|
$url = URL::to("/payment/{$invitation->invitation_key}/{$typeLink}");
|
|
|
|
|
|
|
|
// PayPal doesn't allow being run in an iframe so we need to open in new tab
|
|
|
|
if ($type === PAYMENT_TYPE_PAYPAL && $account->iframe_url) {
|
|
|
|
$url = 'javascript:window.open("'.$url.'", "_blank")';
|
|
|
|
}
|
|
|
|
$paymentTypes[] = [
|
|
|
|
'url' => $url, 'label' => trans('texts.'.strtolower($type))
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $paymentTypes;
|
2015-10-13 17:44:01 +02:00
|
|
|
}
|
|
|
|
|
2016-02-17 16:50:01 +01:00
|
|
|
public function download($invitationKey)
|
|
|
|
{
|
|
|
|
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
|
|
|
return response()->view('error', [
|
|
|
|
'error' => trans('texts.invoice_not_found'),
|
|
|
|
'hideHeader' => true,
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$invoice = $invitation->invoice;
|
|
|
|
$pdfString = $invoice->getPDFString();
|
|
|
|
|
2016-02-17 20:13:55 +01:00
|
|
|
header('Content-Type: application/pdf');
|
|
|
|
header('Content-Length: ' . strlen($pdfString));
|
|
|
|
header('Content-disposition: attachment; filename="' . $invoice->getFileName() . '"');
|
|
|
|
header('Cache-Control: public, must-revalidate, max-age=0');
|
|
|
|
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
|
|
|
|
|
|
|
return $pdfString;
|
2016-02-17 16:50:01 +01:00
|
|
|
}
|
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
public function dashboard()
|
|
|
|
{
|
2015-10-20 19:12:34 +02:00
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
2016-03-01 08:36:37 +01:00
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
$account = $invitation->account;
|
|
|
|
$invoice = $invitation->invoice;
|
|
|
|
$client = $invoice->client;
|
|
|
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
|
|
|
|
2016-04-13 21:08:41 +02:00
|
|
|
if (!$account->enable_client_portal || !$account->enable_client_portal_dashboard) {
|
2016-03-01 08:36:37 +01:00
|
|
|
return $this->returnError();
|
|
|
|
}
|
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
$data = [
|
|
|
|
'color' => $color,
|
|
|
|
'account' => $account,
|
|
|
|
'client' => $client,
|
2016-04-19 04:35:18 +02:00
|
|
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
|
|
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
2015-12-30 19:11:51 +01:00
|
|
|
'clientViewCSS' => $account->clientViewCSS(),
|
2016-01-07 08:08:30 +01:00
|
|
|
'clientFontUrl' => $account->getFontsUrl(),
|
2015-10-13 17:44:01 +02:00
|
|
|
];
|
2016-01-06 21:46:11 +01:00
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
return response()->view('invited.dashboard', $data);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function activityDatatable()
|
|
|
|
{
|
2015-10-20 19:12:34 +02:00
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-13 17:44:01 +02:00
|
|
|
$invoice = $invitation->invoice;
|
|
|
|
|
2015-11-16 13:30:44 +01:00
|
|
|
$query = $this->activityRepo->findByClientId($invoice->client_id);
|
2015-10-28 20:22:07 +01:00
|
|
|
$query->where('activities.adjustment', '!=', 0);
|
2015-10-13 17:44:01 +02:00
|
|
|
|
|
|
|
return Datatable::query($query)
|
|
|
|
->addColumn('activities.id', function ($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); })
|
2015-12-31 12:31:50 +01:00
|
|
|
->addColumn('activity_type_id', function ($model) {
|
2015-10-28 20:22:07 +01:00
|
|
|
$data = [
|
|
|
|
'client' => Utils::getClientDisplayName($model),
|
|
|
|
'user' => $model->is_system ? ('<i>' . trans('texts.system') . '</i>') : ($model->user_first_name . ' ' . $model->user_last_name),
|
|
|
|
'invoice' => trans('texts.invoice') . ' ' . $model->invoice,
|
|
|
|
'contact' => Utils::getClientDisplayName($model),
|
|
|
|
'payment' => trans('texts.payment') . ($model->payment ? ' ' . $model->payment : ''),
|
|
|
|
];
|
|
|
|
|
|
|
|
return trans("texts.activity_{$model->activity_type_id}", $data);
|
|
|
|
})
|
2015-12-07 14:34:55 +01:00
|
|
|
->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); })
|
2015-12-14 22:05:17 +01:00
|
|
|
->addColumn('adjustment', function ($model) { return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id, $model->country_id) : ''; })
|
2015-10-13 17:44:01 +02:00
|
|
|
->make();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function invoiceIndex()
|
|
|
|
{
|
2015-10-20 19:12:34 +02:00
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
2016-04-13 21:08:41 +02:00
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
$account = $invitation->account;
|
2016-04-13 21:08:41 +02:00
|
|
|
|
|
|
|
if (!$account->enable_client_portal) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
|
|
|
|
|
|
|
$data = [
|
|
|
|
'color' => $color,
|
2016-04-19 04:35:18 +02:00
|
|
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
2016-04-13 21:08:41 +02:00
|
|
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
2016-04-19 04:35:18 +02:00
|
|
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
2015-12-30 19:11:51 +01:00
|
|
|
'clientViewCSS' => $account->clientViewCSS(),
|
2016-01-07 08:08:30 +01:00
|
|
|
'clientFontUrl' => $account->getFontsUrl(),
|
2015-10-13 17:44:01 +02:00
|
|
|
'title' => trans('texts.invoices'),
|
|
|
|
'entityType' => ENTITY_INVOICE,
|
|
|
|
'columns' => Utils::trans(['invoice_number', 'invoice_date', 'invoice_total', 'balance_due', 'due_date']),
|
|
|
|
];
|
|
|
|
|
|
|
|
return response()->view('public_list', $data);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function invoiceDatatable()
|
|
|
|
{
|
2015-10-20 19:12:34 +02:00
|
|
|
if (!$invitation = $this->getInvitation()) {
|
2015-12-27 12:08:58 +01:00
|
|
|
return '';
|
2015-10-20 19:12:34 +02:00
|
|
|
}
|
2015-10-13 17:44:01 +02:00
|
|
|
|
|
|
|
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_INVOICE, Input::get('sSearch'));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function paymentIndex()
|
|
|
|
{
|
2015-10-20 19:12:34 +02:00
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
2015-10-13 17:44:01 +02:00
|
|
|
$account = $invitation->account;
|
2016-04-13 21:08:41 +02:00
|
|
|
|
|
|
|
if (!$account->enable_client_portal) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
|
|
|
|
|
|
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
2015-10-13 17:44:01 +02:00
|
|
|
$data = [
|
|
|
|
'color' => $color,
|
2016-04-19 04:35:18 +02:00
|
|
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
2016-04-13 21:08:41 +02:00
|
|
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
2016-04-19 04:35:18 +02:00
|
|
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
2015-12-30 19:11:51 +01:00
|
|
|
'clientViewCSS' => $account->clientViewCSS(),
|
2016-01-07 08:08:30 +01:00
|
|
|
'clientFontUrl' => $account->getFontsUrl(),
|
2015-10-13 17:44:01 +02:00
|
|
|
'entityType' => ENTITY_PAYMENT,
|
|
|
|
'title' => trans('texts.payments'),
|
|
|
|
'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date'])
|
|
|
|
];
|
|
|
|
|
|
|
|
return response()->view('public_list', $data);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function paymentDatatable()
|
|
|
|
{
|
2015-10-20 19:12:34 +02:00
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-13 17:44:01 +02:00
|
|
|
$payments = $this->paymentRepo->findForContact($invitation->contact->id, Input::get('sSearch'));
|
|
|
|
|
|
|
|
return Datatable::query($payments)
|
2016-04-10 21:54:02 +02:00
|
|
|
->addColumn('invoice_number', function ($model) { return $model->invitation_key ? link_to('/view/'.$model->invitation_key, $model->invoice_number)->toHtml() : $model->invoice_number; })
|
2015-10-13 17:44:01 +02:00
|
|
|
->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : '<i>Manual entry</i>'; })
|
|
|
|
->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? '<i>Online payment</i>' : ''); })
|
2015-12-07 14:34:55 +01:00
|
|
|
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); })
|
2015-10-13 17:44:01 +02:00
|
|
|
->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); })
|
|
|
|
->make();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function quoteIndex()
|
|
|
|
{
|
2015-10-20 19:12:34 +02:00
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
2016-04-13 21:08:41 +02:00
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
$account = $invitation->account;
|
2016-04-13 21:08:41 +02:00
|
|
|
|
|
|
|
if (!$account->enable_client_portal) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
|
|
|
$data = [
|
|
|
|
'color' => $color,
|
2016-04-19 04:35:18 +02:00
|
|
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
2016-04-13 21:08:41 +02:00
|
|
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
2016-04-19 04:35:18 +02:00
|
|
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
2015-12-30 19:11:51 +01:00
|
|
|
'clientViewCSS' => $account->clientViewCSS(),
|
2016-01-07 08:08:30 +01:00
|
|
|
'clientFontUrl' => $account->getFontsUrl(),
|
2015-10-13 17:44:01 +02:00
|
|
|
'title' => trans('texts.quotes'),
|
|
|
|
'entityType' => ENTITY_QUOTE,
|
|
|
|
'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date']),
|
|
|
|
];
|
|
|
|
|
|
|
|
return response()->view('public_list', $data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function quoteDatatable()
|
|
|
|
{
|
2015-10-20 19:12:34 +02:00
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-13 17:44:01 +02:00
|
|
|
|
|
|
|
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, Input::get('sSearch'));
|
|
|
|
}
|
|
|
|
|
2016-03-24 16:58:30 +01:00
|
|
|
public function documentIndex()
|
|
|
|
{
|
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
2016-04-13 21:08:41 +02:00
|
|
|
|
2016-03-24 16:58:30 +01:00
|
|
|
$account = $invitation->account;
|
2016-04-13 21:08:41 +02:00
|
|
|
|
|
|
|
if (!$account->enable_client_portal) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
|
|
|
|
|
|
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
2016-03-24 16:58:30 +01:00
|
|
|
$data = [
|
|
|
|
'color' => $color,
|
2016-04-19 04:35:18 +02:00
|
|
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
2016-04-13 21:08:41 +02:00
|
|
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
2016-04-19 04:35:18 +02:00
|
|
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
2016-03-24 16:58:30 +01:00
|
|
|
'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'));
|
|
|
|
}
|
|
|
|
|
2016-03-01 08:36:37 +01:00
|
|
|
private function returnError($error = false)
|
2015-10-20 19:12:34 +02:00
|
|
|
{
|
|
|
|
return response()->view('error', [
|
2016-03-01 08:36:37 +01:00
|
|
|
'error' => $error ?: trans('texts.invoice_not_found'),
|
2015-10-20 19:12:34 +02:00
|
|
|
'hideHeader' => true,
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2015-10-13 17:44:01 +02:00
|
|
|
private function getInvitation()
|
|
|
|
{
|
|
|
|
$invitationKey = session('invitation_key');
|
|
|
|
|
|
|
|
if (!$invitationKey) {
|
2015-10-20 19:12:34 +02:00
|
|
|
return false;
|
2015-10-13 17:44:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$invitation = Invitation::where('invitation_key', '=', $invitationKey)->first();
|
|
|
|
|
|
|
|
if (!$invitation || $invitation->is_deleted) {
|
2015-10-20 19:12:34 +02:00
|
|
|
return false;
|
2015-10-13 17:44:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$invoice = $invitation->invoice;
|
|
|
|
|
|
|
|
if (!$invoice || $invoice->is_deleted) {
|
2015-10-20 19:12:34 +02:00
|
|
|
return false;
|
2015-10-13 17:44:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $invitation;
|
|
|
|
}
|
2016-03-24 03:41:19 +01:00
|
|
|
|
2016-03-23 23:40:42 +01:00
|
|
|
public function getDocumentVFSJS($publicId, $name){
|
|
|
|
if (!$invitation = $this->getInvitation()) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
|
|
|
|
|
|
|
$clientId = $invitation->invoice->client_id;
|
|
|
|
$document = Document::scope($publicId, $invitation->account_id)->first();
|
|
|
|
|
|
|
|
|
2016-03-24 16:33:28 +01:00
|
|
|
if(!$document->isPDFEmbeddable()){
|
2016-03-23 23:40:42 +01:00
|
|
|
return Response::view('error', array('error'=>'Image does not exist!'), 404);
|
|
|
|
}
|
|
|
|
|
|
|
|
$authorized = false;
|
|
|
|
if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){
|
|
|
|
$authorized = true;
|
|
|
|
} else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){
|
|
|
|
$authorized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$authorized){
|
|
|
|
return Response::view('error', array('error'=>'Not authorized'), 403);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(substr($name, -3)=='.js'){
|
|
|
|
$name = substr($name, 0, -3);
|
|
|
|
}
|
|
|
|
|
|
|
|
$content = $document->preview?$document->getRawPreview():$document->getRaw();
|
|
|
|
$content = 'ninjaAddVFSDoc('.json_encode(intval($publicId).'/'.strval($name)).',"'.base64_encode($content).'")';
|
|
|
|
$response = Response::make($content, 200);
|
|
|
|
$response->header('content-type', 'text/javascript');
|
|
|
|
$response->header('cache-control', 'max-age=31536000');
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
2016-03-24 02:25:33 +01:00
|
|
|
|
2016-03-24 03:41:19 +01:00
|
|
|
protected function canCreateZip(){
|
|
|
|
return function_exists('gmp_init');
|
|
|
|
}
|
|
|
|
|
2016-03-24 16:33:28 +01:00
|
|
|
protected function getInvoiceZipDocuments($invoice, &$size=0){
|
2016-03-24 23:15:52 +01:00
|
|
|
$documents = $invoice->documents;
|
|
|
|
|
|
|
|
foreach($invoice->expenses as $expense){
|
|
|
|
$documents = $documents->merge($expense->documents);
|
|
|
|
}
|
|
|
|
|
|
|
|
$documents = $documents->sortBy('size');
|
2016-03-24 16:33:28 +01:00
|
|
|
|
|
|
|
$size = 0;
|
2016-03-24 03:41:19 +01:00
|
|
|
$maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000;
|
2016-03-24 16:33:28 +01:00
|
|
|
$toZip = array();
|
|
|
|
foreach($documents as $document){
|
|
|
|
if($size + $document->size > $maxSize)break;
|
|
|
|
|
|
|
|
if(!empty($toZip[$document->name])){
|
|
|
|
// This name is taken
|
|
|
|
if($toZip[$document->name]->hash != $document->hash){
|
|
|
|
// 2 different files with the same name
|
|
|
|
$nameInfo = pathinfo($document->name);
|
|
|
|
|
|
|
|
for($i = 1;; $i++){
|
|
|
|
$name = $nameInfo['filename'].' ('.$i.').'.$nameInfo['extension'];
|
|
|
|
|
|
|
|
if(empty($toZip[$name])){
|
|
|
|
$toZip[$name] = $document;
|
|
|
|
$size += $document->size;
|
|
|
|
break;
|
|
|
|
} else if ($toZip[$name]->hash == $document->hash){
|
|
|
|
// We're not adding this after all
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
$toZip[$document->name] = $document;
|
|
|
|
$size += $document->size;
|
2016-03-24 03:41:19 +01:00
|
|
|
}
|
|
|
|
}
|
2016-03-24 16:33:28 +01:00
|
|
|
|
|
|
|
return $toZip;
|
2016-03-24 03:41:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getInvoiceDocumentsZip($invitationKey){
|
|
|
|
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
|
|
|
|
|
|
|
Session::put('invitation_key', $invitationKey); // track current invitation
|
|
|
|
|
|
|
|
$invoice = $invitation->invoice;
|
|
|
|
|
2016-03-24 16:33:28 +01:00
|
|
|
$toZip = $this->getInvoiceZipDocuments($invoice);
|
2016-03-24 03:41:19 +01:00
|
|
|
|
|
|
|
if(!count($toZip)){
|
|
|
|
return Response::view('error', array('error'=>'No documents small enough'), 404);
|
|
|
|
}
|
|
|
|
|
2016-03-24 16:33:28 +01:00
|
|
|
$zip = new ZipArchive($invitation->account->name.' Invoice '.$invoice->invoice_number.'.zip');
|
2016-03-24 03:41:19 +01:00
|
|
|
return Response::stream(function() use ($toZip, $zip) {
|
2016-03-24 16:33:28 +01:00
|
|
|
foreach($toZip as $name=>$document){
|
|
|
|
$fileStream = $document->getStream();
|
|
|
|
if($fileStream){
|
|
|
|
$zip->init_file_stream_transfer($name, $document->size, array('time'=>$document->created_at->timestamp));
|
|
|
|
while ($buffer = fread($fileStream, 256000))$zip->stream_file_part($buffer);
|
|
|
|
fclose($fileStream);
|
|
|
|
$zip->complete_file_stream();
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
$zip->add_file($name, $document->getRaw());
|
2016-03-24 03:41:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
$zip->finish();
|
|
|
|
}, 200);
|
|
|
|
}
|
2016-03-24 02:25:33 +01:00
|
|
|
|
|
|
|
public function getDocument($invitationKey, $publicId){
|
|
|
|
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
|
|
|
|
return $this->returnError();
|
|
|
|
}
|
|
|
|
|
|
|
|
Session::put('invitation_key', $invitationKey); // track current invitation
|
|
|
|
|
|
|
|
$clientId = $invitation->invoice->client_id;
|
|
|
|
$document = Document::scope($publicId, $invitation->account_id)->firstOrFail();
|
|
|
|
|
|
|
|
$authorized = false;
|
|
|
|
if($document->expense && $document->expense->client_id == $invitation->invoice->client_id){
|
|
|
|
$authorized = true;
|
|
|
|
} else if($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id){
|
|
|
|
$authorized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$authorized){
|
|
|
|
return Response::view('error', array('error'=>'Not authorized'), 403);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DocumentController::getDownloadResponse($document);
|
|
|
|
}
|
2015-10-13 17:44:01 +02:00
|
|
|
|
2016-01-20 09:41:57 +01:00
|
|
|
}
|