Merge pull request #3177 from CihanSenturk/added-bulk-action-download
Added bulk action download
This commit is contained in:
commit
ca9ff90caa
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs\Common;
|
||||
|
||||
use App\Abstracts\JobShouldQueue;
|
||||
use App\Models\Common\Media as MediaModel;
|
||||
use App\Notifications\Common\DownloadCompleted;
|
||||
use App\Notifications\Common\DownloadFailed;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use MediaUploader;
|
||||
|
||||
class CreateMediableForDownload extends JobShouldQueue
|
||||
{
|
||||
protected $user;
|
||||
|
||||
protected $file_name;
|
||||
|
||||
protected $translation;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param $user
|
||||
* @param $file_name
|
||||
* @param $translation
|
||||
*/
|
||||
public function __construct($user, $file_name, $translation)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs\Common;
|
||||
|
||||
use App\Abstracts\JobShouldQueue;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use ZipArchive;
|
||||
|
||||
class CreateZipForDownload extends JobShouldQueue
|
||||
{
|
||||
public $selected;
|
||||
|
||||
public $class;
|
||||
|
||||
public $file_name;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param $selected
|
||||
* @param $class
|
||||
* @param $file_name
|
||||
*/
|
||||
public function __construct($selected, $class, $file_name)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs\Document;
|
||||
|
||||
use App\Abstracts\Job;
|
||||
use App\Events\Document\DocumentPrinting;
|
||||
use App\Traits\Documents;
|
||||
|
||||
class DownloadDocument extends Job
|
||||
{
|
||||
use Documents;
|
||||
|
||||
public $document;
|
||||
|
||||
public $folder_path;
|
||||
|
||||
public $zip_archive;
|
||||
|
||||
public $close_zip;
|
||||
|
||||
public $method;
|
||||
|
||||
public function __construct($document, $folder_path = null, $zip_archive = null, $close_zip = false, $method = 'save')
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Common;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\HtmlString;
|
||||
|
||||
class DownloadCompleted extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
protected $translation;
|
||||
|
||||
protected $file_name;
|
||||
|
||||
protected $download_url;
|
||||
|
||||
/**
|
||||
* Create a notification instance.
|
||||
*
|
||||
* @param string $download_url
|
||||
*/
|
||||
public function __construct($translation, $file_name, $download_url)
|
||||
{
|
||||
$this->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('<br><br>'))
|
||||
->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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Common;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\HtmlString;
|
||||
|
||||
class DownloadFailed extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* The error exception.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* Create a notification instance.
|
||||
*
|
||||
* @param string $message
|
||||
*/
|
||||
public function __construct($message)
|
||||
{
|
||||
$this->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('<br><br>'))
|
||||
->line(trans('notifications.download.failed.description'))
|
||||
->line(new HtmlString('<br><br>'))
|
||||
->line($this->message)
|
||||
->line(new HtmlString('<br><br>'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ return [
|
|||
'duplicate' => 'Are you sure you want to <b>duplicate</b> selected record?',
|
||||
'delete' => 'Are you sure you want to <b>delete</b> selected record?|Are you sure you want to <b>delete</b> selected records?',
|
||||
'export' => 'Are you sure you want to <b>export</b> selected record?|Are you sure you want to <b>export</b> selected records?',
|
||||
'download' => 'Are you sure you want to <b>download</b> selected record?|Are you sure you want to <b>download</b> selected records?',
|
||||
'enable' => 'Are you sure you want to <b>enable</b> selected record?|Are you sure you want to <b>enable</b> selected records?',
|
||||
'disable' => 'Are you sure you want to <b>disable</b> selected record?|Are you sure you want to <b>disable</b> selected records?',
|
||||
'paid' => 'Are you sure you want to mark selected invoice as <b>paid</b>?|Are you sure you want to mark selected invoices as <b>paid</b>?',
|
||||
|
|
|
|||
|
|
@ -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!',
|
||||
|
|
|
|||
|
|
@ -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 <strong>:type</strong> file is ready to <a href=":url" target="_blank"><strong>download</strong></a>.',
|
||||
|
||||
],
|
||||
|
||||
'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',
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
@stack('body_scripts')
|
||||
|
||||
@livewireScripts
|
||||
//should queue control added for bulk action download
|
||||
@if (! should_queue())
|
||||
@livewireScripts
|
||||
@endif
|
||||
|
||||
@stack('scripts_end')
|
||||
|
|
|
|||
Loading…
Reference in New Issue