From 129aaf8d1bf6cd083188f7f8a874657284b6ed01 Mon Sep 17 00:00:00 2001 From: Duca Paul Date: Mon, 8 Jan 2018 15:07:37 +0200 Subject: [PATCH 01/16] Implementing Notification Templates --- .../NotificationTemplateCrudController.php | 169 ++++++++++++++++++ .../Admin/OrderStatusCrudController.php | 14 ++ .../Requests/NotificationTemplateRequest.php | 55 ++++++ app/Http/helpers.php | 26 +++ app/Mail/OrderStatusChanged.php | 47 +++++ app/Models/NotificationTemplate.php | 60 +++++++ app/Models/Order.php | 56 +++++- app/Models/Product.php | 3 +- app/User.php | 24 ++- ...07_create_notification_templates_table.php | 4 +- ..._03_000009_create_order_statuses_table.php | 1 + database/seeds/PermissionsTableSeeder.php | 5 + resources/lang/en/notification_templates.php | 11 ++ resources/lang/en/order.php | 1 + .../notification_template/footer.blade.php | 0 .../notification_template/header.blade.php | 0 .../notification_template/layout.blade.php | 1 + .../backpack/base/inc/sidebar.blade.php | 8 +- .../crud/fields/client_address.blade.php | 1 - .../notification_list_variables.blade.php | 78 ++++++++ ...rray_notification_template_model.blade.php | 67 +++++++ .../backpack/crud/fields/slug.blade.php | 41 +++++ routes/web.php | 8 +- 23 files changed, 662 insertions(+), 18 deletions(-) create mode 100644 app/Http/Controllers/Admin/NotificationTemplateCrudController.php create mode 100644 app/Http/Requests/NotificationTemplateRequest.php create mode 100644 app/Mail/OrderStatusChanged.php create mode 100644 app/Models/NotificationTemplate.php create mode 100644 resources/lang/en/notification_templates.php create mode 100644 resources/views/email/notification_template/footer.blade.php create mode 100644 resources/views/email/notification_template/header.blade.php create mode 100644 resources/views/email/notification_template/layout.blade.php create mode 100644 resources/views/vendor/backpack/crud/fields/notification_list_variables.blade.php create mode 100644 resources/views/vendor/backpack/crud/fields/select2_from_array_notification_template_model.blade.php create mode 100644 resources/views/vendor/backpack/crud/fields/slug.blade.php diff --git a/app/Http/Controllers/Admin/NotificationTemplateCrudController.php b/app/Http/Controllers/Admin/NotificationTemplateCrudController.php new file mode 100644 index 0000000..83bc144 --- /dev/null +++ b/app/Http/Controllers/Admin/NotificationTemplateCrudController.php @@ -0,0 +1,169 @@ +crud->setModel('App\Models\NotificationTemplate'); + $this->crud->setRoute(config('backpack.base.route_prefix') . '/notification-templates'); + $this->crud->setEntityNameStrings(trans('notification_templates.notification_template'), trans('notification_templates.notification_templates')); + + /* + |-------------------------------------------------------------------------- + | COLUMNS + |-------------------------------------------------------------------------- + */ + $this->crud->addColumns([ + [ + 'name' => 'name', + 'label' => trans('notification_templates.name'), + ], + [ + 'name' => 'slug', + 'label' => trans('notification_templates.slug'), + ], + [ + 'name' => 'body', + 'label' => trans('notification_templates.body'), + ], + ]); + + /* + |-------------------------------------------------------------------------- + | PERMISSIONS + |------------------------------------------------------------------------- + */ + $this->setPermissions(); + + /* + |-------------------------------------------------------------------------- + | FIELDS + |-------------------------------------------------------------------------- + */ + $this->setFields(); + + } + + public function setPermissions() + { + // Get authenticated user + $user = auth()->user(); + + // Deny all accesses + $this->crud->denyAccess(['list', 'create', 'update', 'delete']); + + // Allow list access + if ($user->can('list_notification_templates')) { + $this->crud->allowAccess('list'); + } + + // Allow create access + if ($user->can('create_notification_template')) { + $this->crud->allowAccess('create'); + } + + // Allow update access + if ($user->can('update_notification_template')) { + $this->crud->allowAccess('update'); + } + + // Uncomment if you want to allow delete functionality + // Allow delete access + // if ($user->can('delete_notification_template')) { + // $this->crud->allowAccess('delete'); + // } + } + + public function setFields() + { + $availableModels = [ + 'User' => 'App\Models\User', + 'Order' => 'App\Models\Order' + ]; + + $this->crud->addFields([ + [ + 'name' => 'name', + 'label' => trans('notification_templates.name'), + 'type' => 'text', + ], + [ + 'name' => 'slug', + 'label' => trans('notification_templates.slug'), + 'type' => 'slug', + // 'attributes' => ['disabled' => 'disabled'] + ], + [ + 'name' => 'model', + 'label' => trans('notification_templates.model'), + 'type' => 'select2_from_array_notification_template_model', + 'options' => $availableModels + ], + [ + 'name' => 'body', + 'label' => trans('notification_templates.body'), + 'type' => 'ckeditor', + 'wrapperAttributes' => [ + 'class' => 'form-group col-md-9 col-xs-12' + ] + ], + [ + 'name' => 'notification_list_variables', + 'label' => trans('notification_templates.available_variables'), + 'type' => 'notification_list_variables', + 'wrapperAttributes' => [ + 'class' => 'form-group available-variables col-md-3 col-xs-12' + ] + ], + ]); + } + + public function listModelVars(Request $request) + { + $modelClass = 'App\\Models\\'.$request->input('model'); + + if ($request->input('model') === 'User') { + $modelClass = 'App\\'.$request->input('model'); + } + + if (class_exists($modelClass)) { + $model = new $modelClass; + + return response()->json($model->notificationVars); + } + + return null; + } + + public function store(StoreRequest $request) + { + // your additional operations before save here + $redirect_location = parent::storeCrud(); + // your additional operations after save here + // use $this->data['entry'] or $this->crud->entry + return $redirect_location; + } + + public function update(UpdateRequest $request) + { + // your additional operations before save here + $redirect_location = parent::updateCrud(); + // your additional operations after save here + // use $this->data['entry'] or $this->crud->entry + return $redirect_location; + } +} diff --git a/app/Http/Controllers/Admin/OrderStatusCrudController.php b/app/Http/Controllers/Admin/OrderStatusCrudController.php index 697b14b..a1ea57b 100644 --- a/app/Http/Controllers/Admin/OrderStatusCrudController.php +++ b/app/Http/Controllers/Admin/OrderStatusCrudController.php @@ -32,6 +32,12 @@ public function setUp() [ 'name' => 'name', 'label' => trans('order.status_name'), + ], + [ + 'name' => 'notification', + 'label' => trans('order.notification'), + 'type' => 'boolean', + 'options' => [0 => 'Disabled', 1 => 'Enabled'] ] ]); @@ -94,6 +100,14 @@ public function setFields() 'name' => 'name', 'label' => trans('order.status_name'), 'type' => 'text', + ], + [ + 'name' => 'notification', + 'type' => 'select_from_array', + 'options' => [ + 1 => 'Enabled', + 0 => 'Disabled' + ] ] ]); } diff --git a/app/Http/Requests/NotificationTemplateRequest.php b/app/Http/Requests/NotificationTemplateRequest.php new file mode 100644 index 0000000..a7ce887 --- /dev/null +++ b/app/Http/Requests/NotificationTemplateRequest.php @@ -0,0 +1,55 @@ + 'required|unique:notification_templates,slug,'.$this->segment(3) + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/app/Http/helpers.php b/app/Http/helpers.php index 38014b7..a1c1902 100644 --- a/app/Http/helpers.php +++ b/app/Http/helpers.php @@ -12,4 +12,30 @@ function getRelationType($relation = null) { function decimalFormat($number = 0, $decimals = 2) { return number_format((float)$number, $decimals, '.', ''); +} + +// Get models +function getModels($path, $exception = []){ + $out = []; + $results = scandir($path); + foreach ($results as $result) { + if ($result === '.' or $result === '..') continue; + $filename = $path . '/' . $result; + if (is_dir($filename)) { + $out = array_merge($out, getModels($filename)); + } else { + $out[] = substr($filename,0,-4); + } + } + return $out; +} + +function getStringBetween($string, $start, $end){ + $string = ' ' . $string; + $ini = strpos($string, $start); + if ($ini == 0) return ''; + $ini += strlen($start); + $len = strpos($string, $end, $ini) - $ini; + + return substr($string, $ini, $len); } \ No newline at end of file diff --git a/app/Mail/OrderStatusChanged.php b/app/Mail/OrderStatusChanged.php new file mode 100644 index 0000000..2d33e8b --- /dev/null +++ b/app/Mail/OrderStatusChanged.php @@ -0,0 +1,47 @@ +template = NotificationTemplate::where('slug', 'orderStatusChange')->first(); + $this->model = $order; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + $variables = $this->model->notificationVariables(); + + $patterns = collect($variables)->map(function ($variable, $key) { + return '/(\{{2}\s?'.$key.'\s?\}{2})/mi'; + }); + + $body = preg_replace($patterns->toArray(), $variables, $this->template->body); + + return $this->view('email.notification_template.layout', compact('body')); + } +} diff --git a/app/Models/NotificationTemplate.php b/app/Models/NotificationTemplate.php new file mode 100644 index 0000000..03fbea9 --- /dev/null +++ b/app/Models/NotificationTemplate.php @@ -0,0 +1,60 @@ + $this->user->salutation, + 'userName' => $this->user->name, + 'userEmail' => $this->user->email, + 'total' => $this->total(), + 'carrier' => $this->carrier()->first()->name, + 'status' => $this->status->name + ]; + } - $products = $this->products->each(function ($product) use (&$total) { - $total += ($product->pivot->price_with_tax*$product->pivot->quantity); + /* + |-------------------------------------------------------------------------- + | EVENTS + |-------------------------------------------------------------------------- + */ + protected static function boot() + { + parent::boot(); + + static::updating(function($order) { + // Send notification when order status was changed + $oldStatus = $order->getOriginal(); + if ($order->status_id != $oldStatus['status_id'] && $order->status->notification != 0) { + return \Mail::to($order->user->email)->send(new OrderStatusChanged($order)); + } }); + } - $carrierPrice = $this->carrier->price; - - return decimalFormat($total+$carrierPrice); + /* + |-------------------------------------------------------------------------- + | FUNCTIONS + |-------------------------------------------------------------------------- + */ + public function total() + { + return decimalFormat($this->products->sum(function ($product) { + return $product->pivot->price_with_tax * $product->pivot->quantity; + }, 0) + $this->carrier->price); } /* diff --git a/app/Models/Product.php b/app/Models/Product.php index 8bca27f..a604494 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -100,7 +100,6 @@ public function group() return $this->belongsTo('App\Models\ProductGroup'); } - public function cartRules() { return $this->belongsToMany('App\Models\CartRule'); @@ -111,7 +110,7 @@ public function specificPrice() return $this->belongsTo('App\Models\SpecificPrice'); } - + /* |-------------------------------------------------------------------------- diff --git a/app/User.php b/app/User.php index 40692ed..21afac9 100644 --- a/app/User.php +++ b/app/User.php @@ -36,6 +36,28 @@ class User extends Authenticatable 'remember_token', ]; + public $notificationVars = [ + 'userSalutation', + 'userName', + 'userEmail', + 'age', + ]; + + /* + |-------------------------------------------------------------------------- + | NOTIFICATIONS VARIABLES + |-------------------------------------------------------------------------- + */ + public function notificationVariables() + { + return [ + 'userSalutation' => $this->user->salutation, + 'userName' => $this->user->name, + 'userEmail' => $this->user->email, + 'age' => $this->age(), + ]; + } + /* |-------------------------------------------------------------------------- @@ -78,7 +100,7 @@ public function cartRules() { return $this->belongsToMany('App\Models\CartRule'); } - + /* |-------------------------------------------------------------------------- | SCOPES diff --git a/database/migrations/2017_07_03_000007_create_notification_templates_table.php b/database/migrations/2017_07_03_000007_create_notification_templates_table.php index c8ff3ec..33070e7 100644 --- a/database/migrations/2017_07_03_000007_create_notification_templates_table.php +++ b/database/migrations/2017_07_03_000007_create_notification_templates_table.php @@ -17,7 +17,9 @@ public function up() $table->engine = 'InnoDB'; $table->increments('id'); $table->string('name', 255)->nullable()->default(null); - $table->longText('content')->nullable()->default(null); + $table->string('slug', 255)->unique()->nullable()->default(null); + $table->string('model', 255)->nullable()->default(null); + $table->longText('body')->nullable()->default(null); }); } diff --git a/database/migrations/2017_07_03_000009_create_order_statuses_table.php b/database/migrations/2017_07_03_000009_create_order_statuses_table.php index 1255462..fc1e844 100644 --- a/database/migrations/2017_07_03_000009_create_order_statuses_table.php +++ b/database/migrations/2017_07_03_000009_create_order_statuses_table.php @@ -17,6 +17,7 @@ public function up() $table->engine = 'InnoDB'; $table->increments('id'); $table->string('name', 50)->nullable()->default(null); + $table->integer('notification', 1)->default(1); }); } diff --git a/database/seeds/PermissionsTableSeeder.php b/database/seeds/PermissionsTableSeeder.php index b934451..47c0d3a 100644 --- a/database/seeds/PermissionsTableSeeder.php +++ b/database/seeds/PermissionsTableSeeder.php @@ -71,6 +71,11 @@ public function run() ['name' => 'create_specific_price'], ['name' => 'update_specific_price'], ['name' => 'delete_specific_price'], + + ['name' => 'list_notification_templates'], + ['name' => 'create_notification_template'], + ['name' => 'update_notification_template'], + ['name' => 'delete_notification_template'], ]; DB::table('permissions')->insert($permissions); diff --git a/resources/lang/en/notification_templates.php b/resources/lang/en/notification_templates.php new file mode 100644 index 0000000..3f80c2c --- /dev/null +++ b/resources/lang/en/notification_templates.php @@ -0,0 +1,11 @@ + 'Notification Template', + 'notification_templates' => 'Notification Templates', + 'name' => 'Name', + 'slug' => 'Slug', + 'model' => 'Model', + 'body' => 'Body', + 'available_variables' => 'Available variables', +]; \ No newline at end of file diff --git a/resources/lang/en/order.php b/resources/lang/en/order.php index 295bbc3..f06e9fa 100644 --- a/resources/lang/en/order.php +++ b/resources/lang/en/order.php @@ -8,6 +8,7 @@ 'order_statuses' => 'Order Statuses', 'status' => 'Status', 'status_name' => 'Status Name', + 'notification' => 'Notification', 'no_status_history' => 'No status history', 'no_order_statuses' => 'No order statuses defined', 'update_status' => 'Update status', diff --git a/resources/views/email/notification_template/footer.blade.php b/resources/views/email/notification_template/footer.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/resources/views/email/notification_template/header.blade.php b/resources/views/email/notification_template/header.blade.php new file mode 100644 index 0000000..e69de29 diff --git a/resources/views/email/notification_template/layout.blade.php b/resources/views/email/notification_template/layout.blade.php new file mode 100644 index 0000000..c6e6075 --- /dev/null +++ b/resources/views/email/notification_template/layout.blade.php @@ -0,0 +1 @@ +{!! $body !!} \ No newline at end of file diff --git a/resources/views/vendor/backpack/base/inc/sidebar.blade.php b/resources/views/vendor/backpack/base/inc/sidebar.blade.php index dda2d70..dbf419a 100644 --- a/resources/views/vendor/backpack/base/inc/sidebar.blade.php +++ b/resources/views/vendor/backpack/base/inc/sidebar.blade.php @@ -19,7 +19,7 @@ - + @can('list_categories')
  • {{ trans('category.categories') }}
  • @endcan @@ -65,7 +65,11 @@ @can('list_specific_prices')
  • {{ trans('specificprice.specific_prices') }}
  • @endcan - + + @can('list_notification_templates') +
  • {{ trans('notification_templates.notification_templates') }}
  • + @endcan +
  • Users, Roles, Permissions