diff --git a/app/Abstracts/BulkAction.php b/app/Abstracts/BulkAction.php
index 6ad86c0c8..b7c5fb10c 100644
--- a/app/Abstracts/BulkAction.php
+++ b/app/Abstracts/BulkAction.php
@@ -2,6 +2,8 @@
namespace App\Abstracts;
+use App\Jobs\Common\CreateMediableForDownload;
+use App\Jobs\Common\CreateZipForDownload;
use App\Jobs\Common\DeleteContact;
use App\Jobs\Common\UpdateContact;
use App\Jobs\Banking\DeleteTransaction;
@@ -11,6 +13,8 @@ use App\Traits\Translations;
use App\Utilities\Export;
use App\Utilities\Import;
use Illuminate\Support\Arr;
+use Illuminate\Support\Facades\Bus;
+use Throwable;
abstract class BulkAction
{
@@ -39,6 +43,11 @@ abstract class BulkAction
'message' => 'bulk_actions.message.export',
'type' => 'download'
],
+ 'download' => [
+ 'name' => 'general.download',
+ 'message' => 'bulk_actions.message.download',
+ 'type' => 'download',
+ ],
];
public $icons = [
@@ -47,6 +56,7 @@ abstract class BulkAction
'delete' => 'delete',
'duplicate' => 'file_copy',
'export' => 'file_download',
+ 'download' => 'folder_zip',
'reconcile' => 'published_with_changes',
'unreconcile' => 'layers_clear',
'received' => 'call_received',
@@ -276,4 +286,43 @@ abstract class BulkAction
{
return Export::toExcel($class, $translation, $extension);
}
+
+ /**
+ * Download the pdf file or catch errors
+ *
+ * @param $class
+ * @param $file_name
+ * @param $translation
+ *
+ * @return mixed
+ */
+ public function downloadPdf($selected, $class, $file_name, $translation)
+ {
+ try {
+ if (should_queue()) {
+ $batch[] = new CreateZipForDownload($selected, $class, $file_name);
+
+ $batch[] = new CreateMediableForDownload(user(), $file_name, $translation);
+
+ Bus::chain($batch)->onQueue('default')->dispatch();
+
+ $message = trans('messages.success.download_queued', ['type' => $translation]);
+
+ flash($message)->success();
+
+ return back();
+ } else {
+ $this->dispatch(new CreateZipForDownload($selected, $class, $file_name));
+
+ $folder_path = 'app/temp/' . company_id() . '/bulk_actions/';
+
+ return response()->download(get_storage_path($folder_path . $file_name . '.zip'))->deleteFileAfterSend(true);
+ }
+ } catch (Throwable $e) {
+ report($e);
+ flash($e->getMessage())->error()->important();
+
+ return back();
+ }
+ }
}
diff --git a/app/BulkActions/Sales/Invoices.php b/app/BulkActions/Sales/Invoices.php
index 00d202788..3eff38a3c 100644
--- a/app/BulkActions/Sales/Invoices.php
+++ b/app/BulkActions/Sales/Invoices.php
@@ -3,14 +3,14 @@
namespace App\BulkActions\Sales;
use App\Abstracts\BulkAction;
-use App\Events\Document\DocumentCancelled;
-use App\Events\Document\DocumentCreated;
-use App\Events\Document\DocumentMarkedSent;
-use App\Events\Document\PaymentReceived;
-use App\Exports\Sales\Invoices\Invoices as Export;
-use App\Jobs\Document\UpdateDocument;
-use App\Jobs\Document\DeleteDocument;
use App\Models\Document\Document;
+use App\Jobs\Document\DeleteDocument;
+use App\Jobs\Common\CreateZipForDownload;
+use App\Jobs\Document\UpdateDocument;
+use App\Events\Document\DocumentCreated;
+use App\Events\Document\DocumentCancelled;
+use App\Events\Document\DocumentMarkedSent;
+use App\Exports\Sales\Invoices\Invoices as Export;
class Invoices extends BulkAction
{
@@ -56,6 +56,12 @@ class Invoices extends BulkAction
'message' => 'bulk_actions.message.export',
'type' => 'download',
],
+ 'download' => [
+ 'icon' => 'folder_zip',
+ 'name' => 'general.download',
+ 'message' => 'bulk_actions.message.download',
+ 'type' => 'download',
+ ],
];
public function edit($request)
@@ -150,5 +156,17 @@ class Invoices extends BulkAction
$selected = $this->getSelectedInput($request);
return $this->exportExcel(new Export($selected), trans_choice('general.invoices', 2));
- }
+ }
+
+ public function download($request)
+ {
+ $selected = $this->getSelectedRecords($request);
+
+ $file_name = Document::INVOICE_TYPE . '-'. date('Y-m-d-H-i-s');
+
+ $class = '\App\Jobs\Document\DownloadDocument';
+
+ return $this->downloadPdf($selected, $class, $file_name, trans_choice('general.invoices', 2));
+ }
}
+
\ No newline at end of file
diff --git a/app/Http/Controllers/Sales/Invoices.php b/app/Http/Controllers/Sales/Invoices.php
index d51729ae9..673495390 100644
--- a/app/Http/Controllers/Sales/Invoices.php
+++ b/app/Http/Controllers/Sales/Invoices.php
@@ -10,6 +10,7 @@ use App\Imports\Sales\Invoices\Invoices as Import;
use App\Jobs\Document\CreateDocument;
use App\Jobs\Document\DeleteDocument;
use App\Jobs\Document\DuplicateDocument;
+use App\Jobs\Document\DownloadDocument;
use App\Jobs\Document\SendDocument;
use App\Jobs\Document\UpdateDocument;
use App\Models\Document\Document;
@@ -327,19 +328,6 @@ class Invoices extends Controller
{
event(new \App\Events\Document\DocumentPrinting($invoice));
- $currency_style = true;
-
- $view = view($invoice->template_path, compact('invoice', 'currency_style'))->render();
-
- $html = mb_convert_encoding($view, 'HTML-ENTITIES', 'UTF-8');
-
- $pdf = app('dompdf.wrapper');
- $pdf->loadHTML($html);
-
- //$pdf->setPaper('A4', 'portrait');
-
- $file_name = $this->getDocumentFileName($invoice);
-
- return $pdf->download($file_name);
+ return $this->dispatch(new DownloadDocument($invoice, null, null, false, 'download'));
}
}
diff --git a/app/Jobs/Common/CreateMediableForDownload.php b/app/Jobs/Common/CreateMediableForDownload.php
new file mode 100644
index 000000000..03413d00d
--- /dev/null
+++ b/app/Jobs/Common/CreateMediableForDownload.php
@@ -0,0 +1,113 @@
+user = $user;
+ $this->file_name = $file_name;
+ $this->translation = $translation;
+
+ $this->onQueue('jobs');
+ }
+
+ /**
+ * Execute the job.
+ *
+ * @return void
+ */
+ public function handle()
+ {
+ try {
+ $media = $this->getQueuedMedia();
+
+ $this->user->attachMedia($media, 'download');
+
+ $download_url = route('uploads.download', ['id' => $media->id, 'company_id' => company_id()]);
+
+ $this->user->notify(new DownloadCompleted($this->translation, $this->file_name, $download_url));
+ } catch (\Throwable $exception) {
+ report($exception);
+
+ $this->user->notify(new DownloadFailed($exception->getMessage()));
+
+ throw $exception;
+ }
+ }
+
+ public function getQueuedMedia()
+ {
+ return config('excel.temporary_files.remote_disk') !== null
+ ? $this->getRemoteQueuedMedia()
+ : $this->getLocalQueuedMedia();
+ }
+
+ public function getLocalQueuedMedia()
+ {
+ $folder_path = 'app/temp/' . company_id() . '/bulk_actions/';
+
+ $source = storage_path($folder_path . $this->file_name . '.zip');
+
+ $destination = $this->getMediaFolder('bulk_actions');
+
+ $media = MediaUploader::makePrivate()
+ ->beforeSave(function(MediaModel $media) {
+ $media->company_id = company_id();
+ })
+ ->fromSource($source)
+ ->toDirectory($destination)
+ ->upload();
+
+ File::delete($source);
+
+ return $media;
+ }
+
+ public function getRemoteQueuedMedia()
+ {
+ $disk = config('excel.temporary_files.remote_disk');
+ $prefix = config('excel.temporary_files.remote_prefix');
+
+ $content = Storage::disk($disk)->get($this->file_name);
+
+ $file_name = str_replace([$prefix, '.xlsx', '.xls'], '', $this->file_name);
+
+ $destination = $this->getMediaFolder('bulk_actions');
+
+ $media = MediaUploader::makePrivate()
+ ->beforeSave(function(MediaModel $media) {
+ $media->company_id = company_id();
+ })
+ ->fromString($content)
+ ->useFilename($file_name)
+ ->toDirectory($destination)
+ ->upload();
+
+ Storage::disk($disk)->delete($this->file_name);
+
+ return $media;
+ }
+}
diff --git a/app/Jobs/Common/CreateZipForDownload.php b/app/Jobs/Common/CreateZipForDownload.php
new file mode 100644
index 000000000..6a3102ab7
--- /dev/null
+++ b/app/Jobs/Common/CreateZipForDownload.php
@@ -0,0 +1,60 @@
+selected = $selected;
+ $this->class = $class;
+ $this->file_name = $file_name;
+
+ $this->onQueue('jobs');
+ }
+
+ public function handle()
+ {
+ $zip_archive = new ZipArchive();
+
+ $folder_path = 'app/temp/' . company_id() . '/bulk_actions/';
+
+ File::ensureDirectoryExists(get_storage_path($folder_path));
+
+ $zip_path = get_storage_path($folder_path . $this->file_name . '.zip');
+
+ $zip_archive->open($zip_path, ZipArchive::CREATE | ZipArchive::OVERWRITE);
+
+ $total = count($this->selected);
+ $current = 0;
+
+ foreach ($this->selected as $selected) {
+ $current++;
+
+ if ($current === $total) {
+ $this->dispatch(new $this->class($selected, $folder_path, $zip_archive, true));
+ } else {
+ $this->dispatch(new $this->class($selected, $folder_path, $zip_archive));
+ }
+ }
+
+ return $zip_path;
+ }
+}
diff --git a/app/Jobs/Document/DownloadDocument.php b/app/Jobs/Document/DownloadDocument.php
new file mode 100644
index 000000000..9c70f7130
--- /dev/null
+++ b/app/Jobs/Document/DownloadDocument.php
@@ -0,0 +1,76 @@
+document = $document;
+ $this->folder_path = $folder_path;
+ $this->zip_archive = $zip_archive;
+ $this->close_zip = $close_zip;
+ $this->method = $method;
+ }
+
+ public function handle()
+ {
+ event(new DocumentPrinting($this->document));
+
+ $data = [
+ $this->document->type => $this->document,
+ 'currency_style' => true
+ ];
+
+ $view = view($this->document->template_path, $data)->render();
+
+ $html = mb_convert_encoding($view, 'HTML-ENTITIES', 'UTF-8');
+
+ $pdf = app('dompdf.wrapper');
+ $pdf->loadHTML($html);
+
+ $file_name = $this->getDocumentFileName($this->document);
+
+ switch ($this->method) {
+ case 'download':
+ return $pdf->download($file_name);
+
+ break;
+ default:
+ if (empty($this->zip_archive)) {
+ return;
+ }
+
+ $pdf_path = get_storage_path($this->folder_path . $file_name);
+
+ // Save the PDF file into temp folder
+ $pdf->save($pdf_path);
+
+ $this->zip_archive->addFile($pdf_path, $file_name);
+
+ if ($this->close_zip) {
+ $this->zip_archive->close();
+ }
+
+ return;
+
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/Notifications/Common/DownloadCompleted.php b/app/Notifications/Common/DownloadCompleted.php
new file mode 100644
index 000000000..9ff34c764
--- /dev/null
+++ b/app/Notifications/Common/DownloadCompleted.php
@@ -0,0 +1,80 @@
+translation = $translation;
+ $this->file_name = $file_name;
+ $this->download_url = $download_url;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable)
+ {
+ return (new MailMessage)
+ ->subject(trans('notifications.download.completed.title'))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.download.completed.description'))
+ ->action(trans('general.download'), $this->download_url);
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.download_completed.title'),
+ 'description' => trans('notifications.menu.download_completed.description', [
+ 'type' => $this->translation,
+ 'url' => $this->download_url,
+ ]),
+ 'translation' => $this->translation,
+ 'file_name' => $this->file_name,
+ 'download_url' => $this->download_url,
+ ];
+ }
+}
diff --git a/app/Notifications/Common/DownloadFailed.php b/app/Notifications/Common/DownloadFailed.php
new file mode 100644
index 000000000..5ac32e3d4
--- /dev/null
+++ b/app/Notifications/Common/DownloadFailed.php
@@ -0,0 +1,76 @@
+message = $message;
+
+ $this->onQueue('notifications');
+ }
+
+ /**
+ * Get the notification's channels.
+ *
+ * @param mixed $notifiable
+ * @return array|string
+ */
+ public function via($notifiable)
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Build the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable)
+ {
+ return (new MailMessage)
+ ->subject(trans('notifications.download.failed.title'))
+ ->line(new HtmlString('
'))
+ ->line(trans('notifications.download.failed.description'))
+ ->line(new HtmlString('
'))
+ ->line($this->message)
+ ->line(new HtmlString('
'));
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ 'title' => trans('notifications.menu.download_failed.title'),
+ 'description' => trans('notifications.menu.download_failed.description'),
+ 'message' => $this->message,
+ ];
+ }
+}
diff --git a/resources/lang/en-GB/bulk_actions.php b/resources/lang/en-GB/bulk_actions.php
index f9921dce4..a095a60dc 100644
--- a/resources/lang/en-GB/bulk_actions.php
+++ b/resources/lang/en-GB/bulk_actions.php
@@ -10,6 +10,7 @@ return [
'duplicate' => 'Are you sure you want to duplicate selected record?',
'delete' => 'Are you sure you want to delete selected record?|Are you sure you want to delete selected records?',
'export' => 'Are you sure you want to export selected record?|Are you sure you want to export selected records?',
+ 'download' => 'Are you sure you want to download selected record?|Are you sure you want to download selected records?',
'enable' => 'Are you sure you want to enable selected record?|Are you sure you want to enable selected records?',
'disable' => 'Are you sure you want to disable selected record?|Are you sure you want to disable selected records?',
'paid' => 'Are you sure you want to mark selected invoice as paid?|Are you sure you want to mark selected invoices as paid?',
diff --git a/resources/lang/en-GB/messages.php b/resources/lang/en-GB/messages.php
index 2b8daa842..0e655640b 100644
--- a/resources/lang/en-GB/messages.php
+++ b/resources/lang/en-GB/messages.php
@@ -12,6 +12,7 @@ return [
'import_queued' => ':type import has been scheduled! You will receive an email when it is finished.',
'exported' => ':type exported!',
'export_queued' => ':type export of the current page has been scheduled! You will receive an email when it is ready to download.',
+ 'download_queued' => ':type download of the current page has been scheduled! You will receive an email when it is ready to download.',
'enabled' => ':type enabled!',
'disabled' => ':type disabled!',
'connected' => ':type connected!',
diff --git a/resources/lang/en-GB/notifications.php b/resources/lang/en-GB/notifications.php
index 1a300ca3f..443246015 100644
--- a/resources/lang/en-GB/notifications.php
+++ b/resources/lang/en-GB/notifications.php
@@ -28,6 +28,24 @@ return [
],
+ 'download' => [
+
+ 'completed' => [
+
+ 'title' => 'Download is ready',
+ 'description' => 'The file is ready to download from the following link:',
+
+ ],
+
+ 'failed' => [
+
+ 'title' => 'Download failed',
+ 'description' => 'Not able to create the file due to the following issue:',
+
+ ],
+
+ ],
+
'import' => [
'completed' => [
@@ -76,6 +94,20 @@ return [
'menu' => [
+ 'download_completed' => [
+
+ 'title' => 'Download is ready',
+ 'description' => 'Your :type file is ready to download.',
+
+ ],
+
+ 'download_failed' => [
+
+ 'title' => 'Download failed',
+ 'description' => 'Not able to create the file due to several issues. Check out your email for the details.',
+
+ ],
+
'export_completed' => [
'title' => 'Export is ready',
diff --git a/resources/views/components/layouts/print/scripts.blade.php b/resources/views/components/layouts/print/scripts.blade.php
index aefeb326e..c8ca0a617 100644
--- a/resources/views/components/layouts/print/scripts.blade.php
+++ b/resources/views/components/layouts/print/scripts.blade.php
@@ -19,6 +19,9 @@
@stack('body_scripts')
-@livewireScripts
+//should queue control added for bulk action download
+@if (! should_queue())
+ @livewireScripts
+@endif
@stack('scripts_end')