From 83b66c880b715449cb52ad1c11ac0d1a3024b9fb Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 20 Oct 2016 23:17:37 +0300 Subject: [PATCH] Track changes to expenses in activities --- app/Events/TaskWasArchived.php | 28 ++++++ app/Events/TaskWasDeleted.php | 28 ++++++ app/Events/TaskWasRestored.php | 29 ++++++ app/Http/Controllers/TaskController.php | 2 +- app/Http/routes.php | 22 ++--- app/Libraries/HistoryUtils.php | 10 ++- app/Listeners/ActivityListener.php | 79 ++++++++++++++++- app/Models/Activity.php | 9 +- app/Ninja/Datatables/ActivityDatatable.php | 4 +- app/Ninja/Repositories/ActivityRepository.php | 8 +- app/Ninja/Repositories/BaseRepository.php | 6 +- .../Repositories/DashboardRepository.php | 2 +- app/Ninja/Repositories/TaskRepository.php | 29 ++---- app/Providers/EventServiceProvider.php | 28 +++++- ...10_20_191150_add_expense_to_activities.php | 33 +++++++ resources/lang/en/texts.php | 18 ++-- resources/views/money_script.blade.php | 2 +- .../views/partials/white_label.blade.php | 88 +++++++++++++++++++ 18 files changed, 367 insertions(+), 58 deletions(-) create mode 100644 app/Events/TaskWasArchived.php create mode 100644 app/Events/TaskWasDeleted.php create mode 100644 app/Events/TaskWasRestored.php create mode 100644 database/migrations/2016_10_20_191150_add_expense_to_activities.php create mode 100644 resources/views/partials/white_label.blade.php diff --git a/app/Events/TaskWasArchived.php b/app/Events/TaskWasArchived.php new file mode 100644 index 000000000000..74a7d1e4f6be --- /dev/null +++ b/app/Events/TaskWasArchived.php @@ -0,0 +1,28 @@ +task = $task; + } + +} diff --git a/app/Events/TaskWasDeleted.php b/app/Events/TaskWasDeleted.php new file mode 100644 index 000000000000..3e41c77ff65c --- /dev/null +++ b/app/Events/TaskWasDeleted.php @@ -0,0 +1,28 @@ +task = $task; + } + +} diff --git a/app/Events/TaskWasRestored.php b/app/Events/TaskWasRestored.php new file mode 100644 index 000000000000..58891f6e3d85 --- /dev/null +++ b/app/Events/TaskWasRestored.php @@ -0,0 +1,29 @@ +task = $task; + } + +} diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index 2450ff51e665..bcc803243f99 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -294,7 +294,7 @@ class TaskController extends BaseController return Redirect::to("invoices/{$invoiceId}/edit")->with('tasks', $data); } } else { - $count = $this->taskRepo->bulk($ids, $action); + $count = $this->taskService->bulk($ids, $action); $message = Utils::pluralize($action.'d_task', $count); Session::flash('message', $message); diff --git a/app/Http/routes.php b/app/Http/routes.php index 2248f35a157e..9f4b6b9ed045 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -433,56 +433,50 @@ if (!defined('CONTACT_EMAIL')) { define('ACTIVITY_TYPE_CREATE_CLIENT', 1); define('ACTIVITY_TYPE_ARCHIVE_CLIENT', 2); define('ACTIVITY_TYPE_DELETE_CLIENT', 3); - define('ACTIVITY_TYPE_CREATE_INVOICE', 4); define('ACTIVITY_TYPE_UPDATE_INVOICE', 5); define('ACTIVITY_TYPE_EMAIL_INVOICE', 6); define('ACTIVITY_TYPE_VIEW_INVOICE', 7); define('ACTIVITY_TYPE_ARCHIVE_INVOICE', 8); define('ACTIVITY_TYPE_DELETE_INVOICE', 9); - define('ACTIVITY_TYPE_CREATE_PAYMENT', 10); //define('ACTIVITY_TYPE_UPDATE_PAYMENT', 11); define('ACTIVITY_TYPE_ARCHIVE_PAYMENT', 12); define('ACTIVITY_TYPE_DELETE_PAYMENT', 13); - define('ACTIVITY_TYPE_VOIDED_PAYMENT', 39); - define('ACTIVITY_TYPE_REFUNDED_PAYMENT', 40); - define('ACTIVITY_TYPE_FAILED_PAYMENT', 41); - define('ACTIVITY_TYPE_CREATE_CREDIT', 14); //define('ACTIVITY_TYPE_UPDATE_CREDIT', 15); define('ACTIVITY_TYPE_ARCHIVE_CREDIT', 16); define('ACTIVITY_TYPE_DELETE_CREDIT', 17); - define('ACTIVITY_TYPE_CREATE_QUOTE', 18); define('ACTIVITY_TYPE_UPDATE_QUOTE', 19); define('ACTIVITY_TYPE_EMAIL_QUOTE', 20); define('ACTIVITY_TYPE_VIEW_QUOTE', 21); define('ACTIVITY_TYPE_ARCHIVE_QUOTE', 22); define('ACTIVITY_TYPE_DELETE_QUOTE', 23); - define('ACTIVITY_TYPE_RESTORE_QUOTE', 24); define('ACTIVITY_TYPE_RESTORE_INVOICE', 25); define('ACTIVITY_TYPE_RESTORE_CLIENT', 26); define('ACTIVITY_TYPE_RESTORE_PAYMENT', 27); define('ACTIVITY_TYPE_RESTORE_CREDIT', 28); define('ACTIVITY_TYPE_APPROVE_QUOTE', 29); - - // Vendors define('ACTIVITY_TYPE_CREATE_VENDOR', 30); define('ACTIVITY_TYPE_ARCHIVE_VENDOR', 31); define('ACTIVITY_TYPE_DELETE_VENDOR', 32); define('ACTIVITY_TYPE_RESTORE_VENDOR', 33); - - // expenses define('ACTIVITY_TYPE_CREATE_EXPENSE', 34); define('ACTIVITY_TYPE_ARCHIVE_EXPENSE', 35); define('ACTIVITY_TYPE_DELETE_EXPENSE', 36); define('ACTIVITY_TYPE_RESTORE_EXPENSE', 37); - - // tasks + define('ACTIVITY_TYPE_VOIDED_PAYMENT', 39); + define('ACTIVITY_TYPE_REFUNDED_PAYMENT', 40); + define('ACTIVITY_TYPE_FAILED_PAYMENT', 41); define('ACTIVITY_TYPE_CREATE_TASK', 42); define('ACTIVITY_TYPE_UPDATE_TASK', 43); + define('ACTIVITY_TYPE_ARCHIVE_TASK', 44); + define('ACTIVITY_TYPE_DELETE_TASK', 45); + define('ACTIVITY_TYPE_RESTORE_TASK', 46); + define('ACTIVITY_TYPE_UPDATE_EXPENSE', 47); + define('DEFAULT_INVOICE_NUMBER', '0001'); define('RECENTLY_VIEWED_LIMIT', 20); diff --git a/app/Libraries/HistoryUtils.php b/app/Libraries/HistoryUtils.php index feb5d331d4b3..8d34c2bed60b 100644 --- a/app/Libraries/HistoryUtils.php +++ b/app/Libraries/HistoryUtils.php @@ -24,6 +24,8 @@ class HistoryUtils ACTIVITY_TYPE_CREATE_CLIENT, ACTIVITY_TYPE_CREATE_TASK, ACTIVITY_TYPE_UPDATE_TASK, + ACTIVITY_TYPE_CREATE_EXPENSE, + ACTIVITY_TYPE_UPDATE_EXPENSE, ACTIVITY_TYPE_CREATE_INVOICE, ACTIVITY_TYPE_UPDATE_INVOICE, ACTIVITY_TYPE_EMAIL_INVOICE, @@ -35,7 +37,7 @@ class HistoryUtils ]; $activities = Activity::scope() - ->with(['client.contacts', 'invoice', 'task']) + ->with(['client.contacts', 'invoice', 'task', 'expense']) ->whereIn('user_id', $userIds) ->whereIn('activity_type_id', $activityTypes) ->orderBy('id', 'asc') @@ -52,6 +54,12 @@ class HistoryUtils continue; } $entity->setRelation('client', $activity->client); + } else if ($activity->activity_type_id == ACTIVITY_TYPE_CREATE_EXPENSE || $activity->activity_type_id == ACTIVITY_TYPE_UPDATE_EXPENSE) { + $entity = $activity->expense; + if ( ! $entity) { + continue; + } + $entity->setRelation('client', $activity->client); } else { $entity = $activity->invoice; if ( ! $entity) { diff --git a/app/Listeners/ActivityListener.php b/app/Listeners/ActivityListener.php index 81810ffd2df2..c8fd439c90ed 100644 --- a/app/Listeners/ActivityListener.php +++ b/app/Listeners/ActivityListener.php @@ -1,7 +1,5 @@ activityRepo->create( + $event->task, + ACTIVITY_TYPE_ARCHIVE_TASK + ); + } + + public function deletedTask(TaskWasDeleted $event) + { + $this->activityRepo->create( + $event->task, + ACTIVITY_TYPE_DELETE_TASK + ); + } + + public function restoredTask(TaskWasRestored $event) + { + $this->activityRepo->create( + $event->task, + ACTIVITY_TYPE_RESTORE_TASK + ); + } + + + public function createdExpense(ExpenseWasCreated $event) + { + $this->activityRepo->create( + $event->expense, + ACTIVITY_TYPE_CREATE_EXPENSE + ); + } + + public function updatedExpense(ExpenseWasUpdated $event) + { + $this->activityRepo->create( + $event->expense, + ACTIVITY_TYPE_UPDATE_EXPENSE + ); + } + + public function archivedExpense(ExpenseWasArchived $event) + { + $this->activityRepo->create( + $event->expense, + ACTIVITY_TYPE_ARCHIVE_EXPENSE + ); + } + + public function deletedExpense(ExpenseWasDeleted $event) + { + $this->activityRepo->create( + $event->expense, + ACTIVITY_TYPE_DELETE_EXPENSE + ); + } + + public function restoredExpense(ExpenseWasRestored $event) + { + $this->activityRepo->create( + $event->expense, + ACTIVITY_TYPE_RESTORE_EXPENSE + ); + } + + } diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 5641967634d3..88a3aa1a9d43 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -83,6 +83,11 @@ class Activity extends Eloquent return $this->belongsTo('App\Models\Task')->withTrashed(); } + public function expense() + { + return $this->belongsTo('App\Models\Expense')->withTrashed(); + } + public function key() { return sprintf('%s-%s-%s', $this->activity_type_id, $this->client_id, $this->created_at->timestamp); @@ -101,9 +106,8 @@ class Activity extends Eloquent $contactId = $this->contact_id; $payment = $this->payment; $credit = $this->credit; + $expense = $this->expense; $isSystem = $this->is_system; - - /** @var Task $task */ $task = $this->task; $data = [ @@ -117,6 +121,7 @@ class Activity extends Eloquent 'adjustment' => $this->adjustment ? $account->formatMoney($this->adjustment, $this) : null, 'credit' => $credit ? $account->formatMoney($credit->amount, $client) : null, 'task' => $task ? link_to($task->getRoute(), substr($task->description, 0, 30).'...') : null, + 'expense' => $expense ? link_to($expense->getRoute(), substr($expense->public_notes, 0, 30).'...') : null, ]; return trans("texts.activity_{$activityTypeId}", $data); diff --git a/app/Ninja/Datatables/ActivityDatatable.php b/app/Ninja/Datatables/ActivityDatatable.php index cb87c26ae680..62fdc646d839 100644 --- a/app/Ninja/Datatables/ActivityDatatable.php +++ b/app/Ninja/Datatables/ActivityDatatable.php @@ -27,7 +27,9 @@ class ActivityDatatable extends EntityDatatable 'payment' => $model->payment ?: '', 'credit' => $model->payment_amount ? Utils::formatMoney($model->credit, $model->currency_id, $model->country_id) : '', 'payment_amount' => $model->payment_amount ? Utils::formatMoney($model->payment_amount, $model->currency_id, $model->country_id) : null, - 'adjustment' => $model->adjustment ? Utils::formatMoney($model->adjustment, $model->currency_id, $model->country_id) : null + 'adjustment' => $model->adjustment ? Utils::formatMoney($model->adjustment, $model->currency_id, $model->country_id) : null, + 'task' => $model->task_public_id ? link_to('/tasks/' . $model->task_public_id, substr($model->task_description, 0, 30).'...') : null, + 'expense' => $model->expense_public_id ? link_to('/expenses/' . $model->expense_public_id, substr($model->expense_public_notes, 0, 30).'...') : null, ]; return trans("texts.activity_{$model->activity_type_id}", $data); diff --git a/app/Ninja/Repositories/ActivityRepository.php b/app/Ninja/Repositories/ActivityRepository.php index 7ea2616b62f2..2a910707e44b 100644 --- a/app/Ninja/Repositories/ActivityRepository.php +++ b/app/Ninja/Repositories/ActivityRepository.php @@ -74,6 +74,8 @@ class ActivityRepository ->leftJoin('invoices', 'invoices.id', '=', 'activities.invoice_id') ->leftJoin('payments', 'payments.id', '=', 'activities.payment_id') ->leftJoin('credits', 'credits.id', '=', 'activities.credit_id') + ->leftJoin('tasks', 'tasks.id', '=', 'activities.task_id') + ->leftJoin('expenses', 'expenses.id', '=', 'activities.expense_id') ->where('clients.id', '=', $clientId) ->where('contacts.is_primary', '=', 1) ->whereNull('contacts.deleted_at') @@ -102,7 +104,11 @@ class ActivityRepository 'contacts.email as email', 'payments.transaction_reference as payment', 'payments.amount as payment_amount', - 'credits.amount as credit' + 'credits.amount as credit', + 'tasks.description as task_description', + 'tasks.public_id as task_public_id', + 'expenses.public_notes as expense_public_notes', + 'expenses.public_id as expense_public_id' ); } diff --git a/app/Ninja/Repositories/BaseRepository.php b/app/Ninja/Repositories/BaseRepository.php index 49f296ef1b84..6b213a25e2ae 100644 --- a/app/Ninja/Repositories/BaseRepository.php +++ b/app/Ninja/Repositories/BaseRepository.php @@ -8,7 +8,7 @@ class BaseRepository /** * @return null */ - public function getClassName() + public function getClassName() { return null; } @@ -40,7 +40,7 @@ class BaseRepository if ($entity->trashed()) { return; } - + $entity->delete(); $className = $this->getEventClass($entity, 'Archived'); @@ -83,7 +83,7 @@ class BaseRepository if ($entity->is_deleted) { return; } - + $entity->is_deleted = true; $entity->save(); diff --git a/app/Ninja/Repositories/DashboardRepository.php b/app/Ninja/Repositories/DashboardRepository.php index 5b04fbc03969..ffbbe348dd90 100644 --- a/app/Ninja/Repositories/DashboardRepository.php +++ b/app/Ninja/Repositories/DashboardRepository.php @@ -252,7 +252,7 @@ class DashboardRepository } return $activities->orderBy('activities.created_at', 'desc') - ->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'account', 'task') + ->with('client.contacts', 'user', 'invoice', 'payment', 'credit', 'account', 'task', 'expense') ->take(50) ->get(); } diff --git a/app/Ninja/Repositories/TaskRepository.php b/app/Ninja/Repositories/TaskRepository.php index 8cace32b830c..879cc5c1061f 100644 --- a/app/Ninja/Repositories/TaskRepository.php +++ b/app/Ninja/Repositories/TaskRepository.php @@ -5,8 +5,13 @@ use Session; use App\Models\Client; use App\Models\Task; -class TaskRepository +class TaskRepository extends BaseRepository { + public function getClassName() + { + return 'App\Models\Task'; + } + public function find($clientPublicId = null, $filter = null) { $query = \DB::table('tasks') @@ -112,26 +117,4 @@ class TaskRepository return $task; } - public function bulk($ids, $action) - { - $tasks = Task::withTrashed()->scope($ids)->get(); - - foreach ($tasks as $task) { - if ($action == 'restore') { - $task->restore(); - - $task->is_deleted = false; - $task->save(); - } else { - if ($action == 'delete') { - $task->is_deleted = true; - $task->save(); - } - - $task->delete(); - } - } - - return count($tasks); - } } diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index a383a3ad5e70..0561a1a1f629 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -157,9 +157,35 @@ class EventServiceProvider extends ServiceProvider { 'App\Events\TaskWasCreated' => [ 'App\Listeners\ActivityListener@createdTask', ], - 'App\Events\TaskWasUpdated' => [ + 'App\Events\TaskWasUpdated' => [ 'App\Listeners\ActivityListener@updatedTask', ], + 'App\Events\TaskWasRestored' => [ + 'App\Listeners\ActivityListener@restoredTask', + ], + 'App\Events\TaskWasArchived' => [ + 'App\Listeners\ActivityListener@archivedTask', + ], + 'App\Events\TaskWasDeleted' => [ + 'App\Listeners\ActivityListener@deletedTask', + ], + + // Expense events + 'App\Events\ExpenseWasCreated' => [ + 'App\Listeners\ActivityListener@createdExpense', + ], + 'App\Events\ExpenseWasUpdated' => [ + 'App\Listeners\ActivityListener@updatedExpense', + ], + 'App\Events\ExpenseWasRestored' => [ + 'App\Listeners\ActivityListener@restoredExpense', + ], + 'App\Events\ExpenseWasArchived' => [ + 'App\Listeners\ActivityListener@archivedExpense', + ], + 'App\Events\ExpenseWasDeleted' => [ + 'App\Listeners\ActivityListener@deletedExpense', + ], // Update events \Codedge\Updater\Events\UpdateAvailable::class => [ diff --git a/database/migrations/2016_10_20_191150_add_expense_to_activities.php b/database/migrations/2016_10_20_191150_add_expense_to_activities.php new file mode 100644 index 000000000000..08e6bfa7e978 --- /dev/null +++ b/database/migrations/2016_10_20_191150_add_expense_to_activities.php @@ -0,0 +1,33 @@ +unsignedInteger('expense_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('activities', function($table) + { + $table->dropColumn('expense_id'); + }); + } +} diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 2bc00fe5a916..3ff726baabb7 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -767,16 +767,20 @@ $LANG = array( 'activity_27' => ':user restored payment :payment', 'activity_28' => ':user restored :credit credit', 'activity_29' => ':contact approved quote :quote', - 'activity_30' => ':user created :vendor', - 'activity_31' => ':user created :vendor', - 'activity_32' => ':user created :vendor', - 'activity_33' => ':user created :vendor', + 'activity_30' => ':user created vendor :vendor', + 'activity_31' => ':user archived vendor :vendor', + 'activity_32' => ':user deleted vendor :vendor', + 'activity_33' => ':user restored vendor :vendor', 'activity_34' => ':user created expense :expense', - 'activity_35' => ':user created :vendor', - 'activity_36' => ':user created :vendor', - 'activity_37' => ':user created :vendor', + 'activity_35' => ':user archived expense :expense', + 'activity_36' => ':user deleted expense :expense', + 'activity_37' => ':user restored expense :expense', 'activity_42' => ':user created task ":task"', 'activity_43' => ':user updated task ":task"', + 'activity_44' => ':user archived task ":task"', + 'activity_45' => ':user deleted task ":task"', + 'activity_46' => ':user restored task ":task"', + 'activity_47' => ':user updated expense ":expense"', 'payment' => 'Payment', 'system' => 'System', 'signature' => 'Email Signature', diff --git a/resources/views/money_script.blade.php b/resources/views/money_script.blade.php index 46b1ecf3b56a..dac7e1693383 100644 --- a/resources/views/money_script.blade.php +++ b/resources/views/money_script.blade.php @@ -56,7 +56,7 @@ countryId = account.country_id; } - if ( ! decorator) { + if (account && ! decorator) { decorator = account.show_currency_code ? 'code' : 'symbol'; } diff --git a/resources/views/partials/white_label.blade.php b/resources/views/partials/white_label.blade.php new file mode 100644 index 000000000000..3fe208481066 --- /dev/null +++ b/resources/views/partials/white_label.blade.php @@ -0,0 +1,88 @@ +{{ trans('texts.powered_by') }} +{{-- Per our license, please do not remove or modify this section. --}} +{!! link_to('https://www.invoiceninja.com/?utm_source=powered_by', 'InvoiceNinja.com', ['target' => '_blank', 'title' => 'invoiceninja.com']) !!} - +{!! link_to(RELEASES_URL, 'v' . NINJA_VERSION, ['target' => '_blank', 'title' => trans('texts.trello_roadmap')]) !!} | +@if (Auth::user()->account->hasFeature(FEATURE_WHITE_LABEL)) + {{ trans('texts.white_labeled') }} +@else + {{ trans('texts.white_label_link') }} + + + + + +@endif + + +