diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index b3eaa66b7e..52b2568eb6 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -218,12 +218,21 @@ class ClientController extends BaseController { $action = Input::get('action'); $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); + + if ($action == 'purge' && ! auth()->user()->is_admin) { + return redirect('dashboard')->withError(trans('texts.not_authorized')); + } + $count = $this->clientService->bulk($ids, $action); $message = Utils::pluralize($action.'d_client', $count); Session::flash('message', $message); - return $this->returnBulk(ENTITY_CLIENT, $action, $ids); + if ($action == 'purge') { + return redirect('dashboard')->withMessage($message); + } else { + return $this->returnBulk(ENTITY_CLIENT, $action, $ids); + } } public function statement($clientPublicId, $statusId = false, $startDate = false, $endDate = false) diff --git a/app/Jobs/PurgeClientData.php b/app/Jobs/PurgeClientData.php new file mode 100644 index 0000000000..464a6a411c --- /dev/null +++ b/app/Jobs/PurgeClientData.php @@ -0,0 +1,44 @@ +client = $client; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $invoices = $this->client->invoices()->withTrashed()->get(); + $expenses = $this->client->expenses()->withTrashed()->get(); + + foreach ($invoices as $invoice) { + foreach ($invoice->documents as $document) { + $document->delete(); + } + } + foreach ($expenses as $expense) { + foreach ($expense->documents as $document) { + $document->delete(); + } + } + + $this->client->forceDelete(); + + HistoryUtils::deleteHistory($this->client); + } +} diff --git a/app/Ninja/Repositories/ActivityRepository.php b/app/Ninja/Repositories/ActivityRepository.php index 7c94cf7265..f086d8c6e6 100644 --- a/app/Ninja/Repositories/ActivityRepository.php +++ b/app/Ninja/Repositories/ActivityRepository.php @@ -30,7 +30,7 @@ class ActivityRepository $activity->activity_type_id = $activityTypeId; $activity->adjustment = $balanceChange; - $activity->client_id = $client ? $client->id : 0; + $activity->client_id = $client ? $client->id : null; $activity->balance = $client ? ($client->balance + $balanceChange) : 0; $activity->notes = $notes ?: ''; diff --git a/app/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php index 9b41cc206a..a4ea88091b 100644 --- a/app/Ninja/Repositories/ClientRepository.php +++ b/app/Ninja/Repositories/ClientRepository.php @@ -2,6 +2,7 @@ namespace App\Ninja\Repositories; +use App\Jobs\PurgeClientData; use App\Events\ClientWasCreated; use App\Events\ClientWasUpdated; use App\Models\Client; @@ -75,6 +76,11 @@ class ClientRepository extends BaseRepository return $query; } + public function purge($client) + { + dispatch(new PurgeClientData($client)); + } + public function save($data, $client = null) { $publicId = isset($data['public_id']) ? $data['public_id'] : false; diff --git a/database/migrations/2018_03_08_150414_add_slack_notifications.php b/database/migrations/2018_03_08_150414_add_slack_notifications.php index 75a097976c..fc3e64651c 100644 --- a/database/migrations/2018_03_08_150414_add_slack_notifications.php +++ b/database/migrations/2018_03_08_150414_add_slack_notifications.php @@ -25,6 +25,27 @@ class AddSlackNotifications extends Migration $table->boolean('auto_archive_quote')->default(false)->nullable(); $table->boolean('auto_email_invoice')->default(true)->nullable(); }); + + Schema::table('expenses', function ($table) { + $table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + }); + + Schema::table('activities', function ($table) { + $table->integer('task_id')->unsigned()->change(); + }); + + DB::statement('UPDATE activities SET client_id = NULL WHERE client_id = 0'); + + Schema::table('activities', function ($table) { + $table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + $table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + $table->foreign('payment_id')->references('id')->on('payments')->onDelete('cascade'); + $table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + $table->foreign('credit_id')->references('id')->on('credits')->onDelete('cascade'); + $table->foreign('task_id')->references('id')->on('tasks')->onDelete('cascade'); + $table->foreign('invitation_id')->references('id')->on('invitations')->onDelete('cascade'); + $table->foreign('expense_id')->references('id')->on('expenses')->onDelete('cascade'); + }); } /** diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index df95e495c2..7302896b9b 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -2786,6 +2786,9 @@ $LANG = array( 'invoice_workflow' => 'Invoice Workflow', 'quote_workflow' => 'Quote Workflow', 'client_must_be_active' => 'Error: the client must be active', + 'purge_client' => 'Purge Client', + 'purged_client' => 'Successfully purged client', + 'purge_client_warning' => 'All related records (invoices, tasks, expenses, documents, etc) will also be deleted.' ); diff --git a/resources/views/clients/show.blade.php b/resources/views/clients/show.blade.php index bbebc9d46b..dc1373276f 100644 --- a/resources/views/clients/show.blade.php +++ b/resources/views/clients/show.blade.php @@ -52,6 +52,8 @@ ->withContents([ ($client->trashed() ? false : ['label' => trans('texts.archive_client'), 'url' => "javascript:onArchiveClick()"]), ['label' => trans('texts.delete_client'), 'url' => "javascript:onDeleteClick()"], + auth()->user()->is_admin ? \DropdownButton::DIVIDER : false, + auth()->user()->is_admin ? ['label' => trans('texts.purge_client'), 'url' => "javascript:onPurgeClick()"] : false, ] )->split() !!} @endcan @@ -394,13 +396,20 @@ $('.mainForm').submit(); } - function onDeleteClick() { + function onDeleteClick() { sweetConfirm(function() { $('#action').val('delete'); $('.mainForm').submit(); }); } + function onPurgeClick() { + sweetConfirm(function() { + $('#action').val('purge'); + $('.mainForm').submit(); + }, "{{ trans('texts.purge_client_warning') . "\\n\\n" . trans('texts.no_undo') }}"); + } + function showEmailHistory(email) { window.emailBounceId = false; $('#emailHistoryModal .panel-body').html("{{ trans('texts.loading') }}...");