From 31cbdf323f997d0256c3054cbdb71199d2f8597d Mon Sep 17 00:00:00 2001 From: pbao9 Date: Mon, 16 Feb 2026 17:04:27 +0700 Subject: [PATCH] feat: Implement soft deletes for customer, invoice, order, and transaction models, and add customer edit and trash management to the admin panel. --- .../Controllers/admin/CustomerController.php | 187 ++++++++++++++++-- app/Models/Customer.php | 3 +- app/Models/Invoice.php | 3 +- app/Models/Order.php | 3 +- app/Models/Transaction.php | 3 +- .../Customer/CustomerCachedRepository.php | 5 + .../Customer/CustomerRepository.php | 11 ++ .../Customer/CustomerRepositoryInterface.php | 1 + .../migrations/2024_01_31_145201_customer.php | 3 +- .../migrations/2024_01_31_155621_order.php | 1 + .../migrations/2024_01_31_155824_invoice.php | 1 + ...letes_to_customer_invoice_order_tables.php | 45 +++++ ...0_add_softdeletes_to_transaction_table.php | 21 ++ .../pages/block/customer/btn.blade.php | 2 + .../customer/datatable/action-trash.blade.php | 13 ++ .../pages/customer/datatable/action.blade.php | 47 +++++ .../pages/customer/datatable/modal.blade.php | 36 ++++ .../pages/customer/datatable/status.blade.php | 13 ++ .../pages/customer/edit.blade.php | 116 +++++++++++ .../pages/customer/index.blade.php | 27 +-- .../pages/customer/trash.blade.php | 46 +++++ routes/admin.php | 7 + 22 files changed, 560 insertions(+), 34 deletions(-) create mode 100644 database/migrations/2026_02_16_000000_add_softdeletes_to_customer_invoice_order_tables.php create mode 100644 database/migrations/2026_02_16_120000_add_softdeletes_to_transaction_table.php create mode 100644 resources/views/administrator/pages/block/customer/btn.blade.php create mode 100644 resources/views/administrator/pages/customer/datatable/action-trash.blade.php create mode 100644 resources/views/administrator/pages/customer/datatable/modal.blade.php create mode 100644 resources/views/administrator/pages/customer/datatable/status.blade.php create mode 100644 resources/views/administrator/pages/customer/edit.blade.php create mode 100644 resources/views/administrator/pages/customer/trash.blade.php diff --git a/app/Http/Controllers/admin/CustomerController.php b/app/Http/Controllers/admin/CustomerController.php index 33d7876..39d49c3 100644 --- a/app/Http/Controllers/admin/CustomerController.php +++ b/app/Http/Controllers/admin/CustomerController.php @@ -7,6 +7,9 @@ use App\Http\Facade\SignRSA; use App\Http\Requests\AddPayRequest; use App\Http\Requests\CreateCustomerRequest; use App\Jobs\Mail\PasswordRecoverJob; +use App\Models\Invoice; +use App\Models\Order; +use App\Models\Transaction; use App\Repositories\Customer\CustomerRepositoryInterface; use App\Repositories\Hosting\HostingRepositoryInterface; use App\Repositories\Invoice\InvoiceRepositoryInterface; @@ -32,7 +35,7 @@ use Yajra\DataTables\Facades\DataTables; class CustomerController extends Controller { - + public function __construct( public CustomerRepositoryInterface $customerRepository, public InvoiceItemRepositoryInterface $invoiceItemRepository, @@ -46,7 +49,8 @@ class CustomerController extends Controller public InvoiceRepositoryInterface $invoiceRepository, public TransactionRepositoryInterface $transactionRepository, public MailRepositoryInterface $mailRepository - ) {} + ) { + } public function index(Request $request) { @@ -222,7 +226,7 @@ class CustomerController extends Controller return redirect()->route('customer.index')->withErrors('No data found for this user'); } $customer = $this->customerRepository->find($userid); - if (! $customer) { + if (!$customer) { return redirect()->route('customer.index')->withErrors('Invalidated Request'); } @@ -231,15 +235,15 @@ class CustomerController extends Controller ['customer_id' => $userid], ['server'] ); - + $vpsServices = $this->vmwareRepository->filter( ['customer_id' => $userid], ['ipaddress.host.datacenter.vCenter', 'os.osGroup'] ); - + // Kết hợp và format dữ liệu $allService = collect(); - + foreach ($hostingServices as $hosting) { $allService->push((object) [ 'product_id' => $hosting->id, @@ -248,7 +252,7 @@ class CustomerController extends Controller 'description' => $hosting->name . ' (Hosting)' ]); } - + foreach ($vpsServices as $vps) { $allService->push((object) [ 'product_id' => $vps->id, @@ -257,7 +261,7 @@ class CustomerController extends Controller 'description' => $vps->name . ' (VPS)' ]); } - + // Lấy invoice_item cụ thể cho sản phẩm $invoice_item = $this->invoiceItemRepository->findBy( $userid, @@ -267,11 +271,11 @@ class CustomerController extends Controller 'value' => $userid ] ); - + $type = null; $product = null; $productName = ''; - + if ($invoice_item) { $product_id = $invoice_item->product_id ?? null; $product_module_id = $request->get('product') ?? $invoice_item->product_id ?? null; @@ -326,7 +330,7 @@ class CustomerController extends Controller public function storeCustomerProduct(Request $request) { - if (! $request->product_type) { + if (!$request->product_type) { return back()->with($request->except(['_token', '_method']))->withErrors('Invalid Request'); } @@ -335,7 +339,7 @@ class CustomerController extends Controller $rules = []; switch ($request->product_type) { case 3: - $rules = [ + $rules = [ 'product_id' => 'required', 'next_due_date' => 'required', 'next_payment' => 'required', @@ -360,7 +364,7 @@ class CustomerController extends Controller if ($validator->fails()) { return back()->withErrors($validator->errors()->first()); } - if (! $product) { + if (!$product) { return back()->withErrors('Product not found'); } try { @@ -418,7 +422,7 @@ class CustomerController extends Controller return redirect()->route('customer.index')->withErrors('No data found for this user'); } $customer = $this->customerRepository->find($userid); - if (! $customer) { + if (!$customer) { return redirect()->route('customer.index')->withErrors('Invalid Request'); } $domains = $this->moduleDomainRepository->filter( @@ -542,7 +546,7 @@ class CustomerController extends Controller $customer = $this->customerRepository->find($userid); - if (! $customer) { + if (!$customer) { return redirect()->route('customer.index')->withErrors('Invalid Request'); } @@ -713,7 +717,7 @@ class CustomerController extends Controller } $customer = $this->customerRepository->find($request->get('userid')); - if (! $customer) { + if (!$customer) { return back()->withErrors('Invalid request'); } Auth::guard('users')->login($customer); @@ -739,12 +743,163 @@ class CustomerController extends Controller ); return DataTables::eloquent($query) + ->addColumn('status', function ($d) { + return view('administrator.pages.customer.datatable.status', ['row' => $d])->render(); + }) ->addColumn( 'action', function ($d) { return view('administrator.pages.customer.datatable.action', ['row' => $d])->render(); } ) + ->rawColumns(['status', 'action']) ->make(true); } + + public function edit(int $id = 0) + { + $customer = $this->customerRepository->find($id); + + if (!$customer) { + return back()->withErrors('Invalid request.'); + } + + $title = 'Edit Customer'; + return view('administrator.pages.customer.edit', compact('title', 'customer')); + } + + public function update(int $id = 0, CreateCustomerRequest $request) + { + $customer = $this->customerRepository->find($id); + + if (!$customer) { + return back()->withErrors('Invalid request.'); + } + + $request->validated(); + + try { + DB::beginTransaction(); + + $data = $request->except(['_token', 'password']); + + if (!empty($request->password)) { + $data['password'] = password_hash($request->password, PASSWORD_BCRYPT); + } + + $this->customerRepository->update($id, $data); + + DB::commit(); + } catch (Exception $error) { + DB::rollBack(); + return back()->withErrors($error->getMessage()); + } + + return redirect()->route('customer.index')->with('success', 'Update customer successfully!'); + } + + public function destroy(int $id = 0) + { + $customer = $this->customerRepository->find($id); + + if (!$customer) { + return back()->withErrors('Invalid request.'); + } + + DB::beginTransaction(); + try { + Invoice::where('customer_id', $id)->delete(); + Order::where('customer_id', $id)->delete(); + Transaction::where('customer_id', $id)->delete(); + + $customer->delete(); + + DB::commit(); + } catch (Exception $error) { + DB::rollBack(); + return back()->withErrors($error->getMessage()); + } + + return redirect()->route('customer.index')->with('success', 'Deleted customer successfully!'); + } + + public function trash() + { + $title = 'Trash Customers'; + return view('administrator.pages.customer.trash', compact('title')); + } + + public function datatableTrash(Request $request) + { + $query = $this->customerRepository->onlyTrashed( + [], + ['hosting', 'vps', 'domain'] + ); + + return DataTables::eloquent($query) + ->addColumn('status', function ($d) { + return view('administrator.pages.customer.datatable.status', ['row' => $d])->render(); + }) + ->addColumn( + 'action', + function ($d) { + return view('administrator.pages.customer.datatable.action-trash', ['row' => $d])->render(); + } + ) + ->rawColumns(['status', 'action']) + ->make(true); + } + + public function restore(int $id = 0) + { + $customer = $this->customerRepository->find($id); + + if (!$customer) { + $customer = $this->customerRepository->onlyTrashed()->find($id); + } + + if (!$customer) { + return back()->withErrors('Invalid request.'); + } + + DB::beginTransaction(); + try { + $customer->restore(); + Invoice::withTrashed()->where('customer_id', $id)->restore(); + Order::withTrashed()->where('customer_id', $id)->restore(); + Transaction::withTrashed()->where('customer_id', $id)->restore(); + + DB::commit(); + } catch (Exception $error) { + DB::rollBack(); + return back()->withErrors($error->getMessage()); + } + + return back()->with('success', 'Restored customer successfully!'); + } + + public function forceDelete(int $id = 0) + { + $customer = $this->customerRepository->onlyTrashed()->find($id); + + if (!$customer) { + return back()->withErrors('Invalid request.'); + } + + DB::beginTransaction(); + try { + Invoice::withTrashed()->where('customer_id', $id)->forceDelete(); + Order::withTrashed()->where('customer_id', $id)->forceDelete(); + Transaction::withTrashed()->where('customer_id', $id)->forceDelete(); + + $customer->forceDelete(); + + DB::commit(); + } catch (Exception $error) { + DB::rollBack(); + return back()->withErrors($error->getMessage()); + } + + return back()->with('success', 'Permanently deleted customer!'); + } } diff --git a/app/Models/Customer.php b/app/Models/Customer.php index b18b149..d7fe73d 100644 --- a/app/Models/Customer.php +++ b/app/Models/Customer.php @@ -4,12 +4,13 @@ namespace App\Models; use Illuminate\Database\Eloquent\Concerns\HasUuids; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Laravel\Sanctum\HasApiTokens; class Customer extends Authenticatable { - use HasFactory, HasApiTokens, HasUuids; + use HasFactory, HasApiTokens, HasUuids, SoftDeletes; protected $table = 'customers'; diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index ab79a67..7f9e7e2 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -5,10 +5,11 @@ namespace App\Models; use App\Enums\Invoice\InvoiceStatus; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; class Invoice extends Model { - use HasFactory; + use HasFactory, SoftDeletes; protected $table = 'invoice'; public $timestamps = true; diff --git a/app/Models/Order.php b/app/Models/Order.php index f5b91a3..1c10913 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -4,10 +4,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; class Order extends Model { - use HasFactory; + use HasFactory, SoftDeletes; protected $table = 'order'; diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index 9b5c980..a4c7aed 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -4,10 +4,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; class Transaction extends Model { - use HasFactory; + use HasFactory, SoftDeletes; protected $table = 'transaction'; protected $fillable = [ diff --git a/app/Repositories/Customer/CustomerCachedRepository.php b/app/Repositories/Customer/CustomerCachedRepository.php index 53c90e1..936301e 100644 --- a/app/Repositories/Customer/CustomerCachedRepository.php +++ b/app/Repositories/Customer/CustomerCachedRepository.php @@ -67,4 +67,9 @@ class CustomerCachedRepository extends BaseCachedRepository implements CustomerR return $this->customerRepository->findBy($key, $value); }); } + + public function onlyTrashed(array $relationships = [], array $withCount = []) + { + return $this->customerRepository->onlyTrashed($relationships, $withCount); + } } diff --git a/app/Repositories/Customer/CustomerRepository.php b/app/Repositories/Customer/CustomerRepository.php index 3d0e8e7..e140a5d 100644 --- a/app/Repositories/Customer/CustomerRepository.php +++ b/app/Repositories/Customer/CustomerRepository.php @@ -125,4 +125,15 @@ class CustomerRepository extends BaseRepository implements CustomerRepositoryInt } return $this->model->where($key, $value)->first(); } + + public function onlyTrashed(array $relationships = [], array $withCount = []) + { + $query = $this->model->with($relationships); + + if (count($withCount) > 0) { + $query = $query->withCount($withCount); + } + + return $query->onlyTrashed(); + } } diff --git a/app/Repositories/Customer/CustomerRepositoryInterface.php b/app/Repositories/Customer/CustomerRepositoryInterface.php index 83631d2..4c83e67 100644 --- a/app/Repositories/Customer/CustomerRepositoryInterface.php +++ b/app/Repositories/Customer/CustomerRepositoryInterface.php @@ -15,4 +15,5 @@ interface CustomerRepositoryInterface extends BaseRepositoryInterface ); public function findWithRelationships(int $id = 0, array $relationships = [],array $withCount = [], array $withSum = []); public function findBy(string $key = '',string $value = ''); + public function onlyTrashed(array $relationships = [], array $withCount = []); } \ No newline at end of file diff --git a/database/migrations/2024_01_31_145201_customer.php b/database/migrations/2024_01_31_145201_customer.php index 79e45f5..5f44f7a 100644 --- a/database/migrations/2024_01_31_145201_customer.php +++ b/database/migrations/2024_01_31_145201_customer.php @@ -42,6 +42,7 @@ return new class extends Migration { $table->string('remember_token', 100)->nullable(); $table->tinyInteger('status')->default(1); $table->timestamps(); + $table->softDeletes(); $table->foreign('province_code') ->references('code') @@ -66,6 +67,6 @@ return new class extends Migration { public function down() { // - Schema::dropIfExists('customer'); + Schema::dropIfExists('customers'); } }; diff --git a/database/migrations/2024_01_31_155621_order.php b/database/migrations/2024_01_31_155621_order.php index 403e33d..e39224a 100644 --- a/database/migrations/2024_01_31_155621_order.php +++ b/database/migrations/2024_01_31_155621_order.php @@ -27,6 +27,7 @@ return new class extends Migration { $table->string('client_ip', 100)->nullable(); $table->tinyInteger('status')->default(0); $table->timestamps(); + $table->softDeletes(); }); } diff --git a/database/migrations/2024_01_31_155824_invoice.php b/database/migrations/2024_01_31_155824_invoice.php index 0d2990b..811fc7a 100644 --- a/database/migrations/2024_01_31_155824_invoice.php +++ b/database/migrations/2024_01_31_155824_invoice.php @@ -31,6 +31,7 @@ return new class extends Migration { $table->tinyInteger('status')->default(0); $table->timestamps(); + $table->softDeletes(); }); } diff --git a/database/migrations/2026_02_16_000000_add_softdeletes_to_customer_invoice_order_tables.php b/database/migrations/2026_02_16_000000_add_softdeletes_to_customer_invoice_order_tables.php new file mode 100644 index 0000000..d03acee --- /dev/null +++ b/database/migrations/2026_02_16_000000_add_softdeletes_to_customer_invoice_order_tables.php @@ -0,0 +1,45 @@ +softDeletes(); + }); + + Schema::table('invoice', function (Blueprint $table) { + $table->softDeletes(); + }); + + Schema::table('order', function (Blueprint $table) { + $table->softDeletes(); + }); + + Schema::table('transaction', function (Blueprint $table) { + $table->softDeletes(); + }); + } + + public function down() + { + Schema::table('customers', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + + Schema::table('invoice', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + + Schema::table('order', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + + Schema::table('transaction', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + } +}; diff --git a/database/migrations/2026_02_16_120000_add_softdeletes_to_transaction_table.php b/database/migrations/2026_02_16_120000_add_softdeletes_to_transaction_table.php new file mode 100644 index 0000000..4c141d3 --- /dev/null +++ b/database/migrations/2026_02_16_120000_add_softdeletes_to_transaction_table.php @@ -0,0 +1,21 @@ +softDeletes(); + }); + } + + public function down() + { + Schema::table('transaction', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + } +}; diff --git a/resources/views/administrator/pages/block/customer/btn.blade.php b/resources/views/administrator/pages/block/customer/btn.blade.php new file mode 100644 index 0000000..765c52e --- /dev/null +++ b/resources/views/administrator/pages/block/customer/btn.blade.php @@ -0,0 +1,2 @@ +Add Customer +Trash \ No newline at end of file diff --git a/resources/views/administrator/pages/customer/datatable/action-trash.blade.php b/resources/views/administrator/pages/customer/datatable/action-trash.blade.php new file mode 100644 index 0000000..84c7345 --- /dev/null +++ b/resources/views/administrator/pages/customer/datatable/action-trash.blade.php @@ -0,0 +1,13 @@ +
+ + +
+ +@include('administrator.pages.customer.datatable.modal', [ + 'deleteRoute' => 'customer.forceDelete', + 'itemLabel' => 'Customer', + 'itemId' => $row->id, + 'itemName' => $row->fullname, + 'modalId' => 'forceDeleteModal-' . $row->id +]) diff --git a/resources/views/administrator/pages/customer/datatable/action.blade.php b/resources/views/administrator/pages/customer/datatable/action.blade.php index e69de29..baa2383 100644 --- a/resources/views/administrator/pages/customer/datatable/action.blade.php +++ b/resources/views/administrator/pages/customer/datatable/action.blade.php @@ -0,0 +1,47 @@ + + + \ No newline at end of file diff --git a/resources/views/administrator/pages/customer/datatable/modal.blade.php b/resources/views/administrator/pages/customer/datatable/modal.blade.php new file mode 100644 index 0000000..cb1f10c --- /dev/null +++ b/resources/views/administrator/pages/customer/datatable/modal.blade.php @@ -0,0 +1,36 @@ + + diff --git a/resources/views/administrator/pages/customer/datatable/status.blade.php b/resources/views/administrator/pages/customer/datatable/status.blade.php new file mode 100644 index 0000000..4d490a2 --- /dev/null +++ b/resources/views/administrator/pages/customer/datatable/status.blade.php @@ -0,0 +1,13 @@ +@php + $status = App\Enums\Status::tryFrom($row->status); +@endphp + +@if($status) + + {{ $status->label() }} + +@else + + Unknown + +@endif \ No newline at end of file diff --git a/resources/views/administrator/pages/customer/edit.blade.php b/resources/views/administrator/pages/customer/edit.blade.php new file mode 100644 index 0000000..7277699 --- /dev/null +++ b/resources/views/administrator/pages/customer/edit.blade.php @@ -0,0 +1,116 @@ +@extends("administrator.layout.master") +@section("content") + @if(auth()->guard('admins')->user()->can("edit customer")) +
+
+ @csrf + @method('PUT') +
+
+
+ {{--Fullname--}} +
+ +
+ +
+
+ {{--Company--}} +
+ +
+ +
+
+ {{--Email--}} +
+ +
+ +
+
+ {{--Phone--}} +
+ +
+ +
+
+ {{--Password--}} +
+ +
+ +
+
+
+
+ {{--Address--}} +
+ +
+ +
+
+ {{--City--}} +
+ +
+ +
+
+ {{--State--}} +
+ +
+ +
+
+ {{--Postcode--}} +
+ +
+ +
+
+ {{--Country--}} +
+ +
+ +
+
+ {{--Marketing Emails--}} +
+ +
+ email_marketing) == 1)> + Send Client Marketing Emails +
+
+
+
+
+ +
+ +
+ @else +
+
Access Denied - You are not assigned to any Customer + management department
+
+ @endif +@endsection diff --git a/resources/views/administrator/pages/customer/index.blade.php b/resources/views/administrator/pages/customer/index.blade.php index 6b7fa3b..a55fcd1 100644 --- a/resources/views/administrator/pages/customer/index.blade.php +++ b/resources/views/administrator/pages/customer/index.blade.php @@ -7,9 +7,9 @@ @section('breadcrumb') @php - $breadcrumbItems = [ - ['label' => 'Customers', 'active' => true], - ]; +$breadcrumbItems = [ + ['label' => 'Customers', 'active' => true], +]; @endphp @endsection @@ -18,19 +18,20 @@ @if (auth()->guard('admins')->user()->can('manager customer'))
+ @include('administrator.pages.block.customer.btn')
+ ['key' => 'fullname', 'label' => 'Fullname'], + ['key' => 'company', 'label' => 'Company'], + ['key' => 'email', 'label' => 'Email'], + ['key' => 'hosting_count', 'label' => 'Hosting'], + ['key' => 'vps_count', 'label' => 'VPS'], + ['key' => 'domain_count', 'label' => 'Domain'], + ['key' => 'created_at', 'label' => 'Created'], + ['key' => 'status', 'label' => 'Status'], + ['key' => 'action', 'label' => 'Action'], + ]" />
@else diff --git a/resources/views/administrator/pages/customer/trash.blade.php b/resources/views/administrator/pages/customer/trash.blade.php new file mode 100644 index 0000000..43870f7 --- /dev/null +++ b/resources/views/administrator/pages/customer/trash.blade.php @@ -0,0 +1,46 @@ +@extends('administrator.layout.master') +@push('plugin-styles') + @foreach (config('assets.datatable.css') as $datatable) + + @endforeach +@endpush + +@section('breadcrumb') + @php +$breadcrumbItems = [ + ['label' => 'Customers', 'route' => route('customer.index')], + ['label' => 'Trash', 'active' => true], +]; + @endphp + +@endsection + +@section('content') + @if (auth()->guard('admins')->user()->can('manager customer')) +
+
+ Back to List +
+
+ +
+
+ @else +
+
Access Denied - You are not assigned to any Customer + management department
+
+ @endif +@endsection + +@push('plugin-scripts') + @foreach (config('assets.datatable.js') as $datatable) + + @endforeach +@endpush diff --git a/routes/admin.php b/routes/admin.php index 26f1c32..b490b70 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -110,6 +110,13 @@ Route::prefix('')->group(function () { //View All Client Route::prefix('customer')->controller(CustomerController::class)->group(function () { Route::get('list-customer', 'index')->name('customer.index'); + Route::get('edit/{id}', 'edit')->name('customer.edit'); + Route::put('edit/{id}', 'update')->name('customer.update'); + Route::delete('delete/{id}', 'destroy')->name('customer.destroy'); + Route::get('trash', 'trash')->name('customer.trash'); + Route::get('trash/datatable', 'datatableTrash')->name('customer.trash.datatable'); + Route::post('trash/restore/{id}', 'restore')->name('customer.restore'); + Route::delete('trash/force-delete/{id}', 'forceDelete')->name('customer.forceDelete'); Route::get('datatable', 'datatable')->name('customer.datatable'); Route::get('view-customer', 'getCustomerInfo')->name('customer.info'); Route::get('view-profile', 'getCustomerProfile')->name('customer.profile');