From 21e2ec04bd9458fd280d8f46f52746684c355e1c Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 24 Nov 2024 17:59:12 +0700 Subject: [PATCH] feat(expense): crud,roite model binding, custom js untuk modal dan membuat observer untuk penghapusan gambar --- .../Admin/Finance/ExpenseController.php | 67 ++++++++ .../Admin/Master/CustomerController.php | 4 +- .../Requests/Admin/Finance/ExpenseRequest.php | 43 +++++ app/Models/Expense.php | 3 + app/Observers/ExpenseObserver.php | 51 ++++++ app/Providers/RouteServiceProvider.php | 2 + public/assets/admin/js/custom/expense.js | 30 ++++ .../pages/admin/finance/expenses.blade.php | 154 ++++++++++++++++++ .../views/partials/admin/_sidebar.blade.php | 12 ++ routes/web.php | 10 ++ 10 files changed, 374 insertions(+), 2 deletions(-) create mode 100644 app/Http/Controllers/Admin/Finance/ExpenseController.php create mode 100644 app/Http/Requests/Admin/Finance/ExpenseRequest.php create mode 100644 app/Observers/ExpenseObserver.php create mode 100644 public/assets/admin/js/custom/expense.js create mode 100644 resources/views/pages/admin/finance/expenses.blade.php diff --git a/app/Http/Controllers/Admin/Finance/ExpenseController.php b/app/Http/Controllers/Admin/Finance/ExpenseController.php new file mode 100644 index 0000000..001d2a8 --- /dev/null +++ b/app/Http/Controllers/Admin/Finance/ExpenseController.php @@ -0,0 +1,67 @@ + 'Pengeluaran', + 'expenses' => Expense::latest()->get(), + ]); + } + + public function store(ExpenseRequest $request): RedirectResponse + { + $validatedData = $request->validated(); + + DB::transaction(function () use ($validatedData) { + $newExpense = Expense::create(array_merge($validatedData, [ + 'user_id' => Auth::id(), + 'barbershop_id' => Auth::user()->barbershop_id, + ])); + $this->uploadAttachment($validatedData['proof'], 'expenses', Expense::class, $newExpense->id); + }); + + notify()->success('Data berhasil ditambahkan', 'Berhasil'); + + return back(); + } + + public function update(Expense $expense, ExpenseRequest $request): RedirectResponse + { + $validatedData = $request->validated(); + + DB::transaction(function () use ($validatedData, $expense) { + $expense->update($validatedData); + if (isset($validatedData['proof'])) { + $this->uploadAttachment($validatedData['proof'], 'expenses', Expense::class, $expense->id); + } + }); + + notify()->success('Data berhasil diubah', 'Berhasil'); + + return back(); + } + + public function delete(Expense $expense): RedirectResponse + { + $expense->delete(); + + notify()->success('Data berhasil dihapus', 'Berhasil'); + + return back(); + } +} diff --git a/app/Http/Controllers/Admin/Master/CustomerController.php b/app/Http/Controllers/Admin/Master/CustomerController.php index e2e0c0d..614396e 100644 --- a/app/Http/Controllers/Admin/Master/CustomerController.php +++ b/app/Http/Controllers/Admin/Master/CustomerController.php @@ -33,7 +33,7 @@ public function store(CustomerRequest $request): RedirectResponse notify()->success('Data berhasil ditambahkan', 'Berhasil'); - return redirect('dashboard/master/customers'); + return back(); } public function update(Customer $customer, CustomerRequest $request): RedirectResponse @@ -44,7 +44,7 @@ public function update(Customer $customer, CustomerRequest $request): RedirectRe notify()->success('Data berhasil diubah', 'Berhasil'); - return redirect('dashboard/master/customers'); + return back(); } public function delete(Customer $customer): RedirectResponse diff --git a/app/Http/Requests/Admin/Finance/ExpenseRequest.php b/app/Http/Requests/Admin/Finance/ExpenseRequest.php new file mode 100644 index 0000000..a2a7566 --- /dev/null +++ b/app/Http/Requests/Admin/Finance/ExpenseRequest.php @@ -0,0 +1,43 @@ +merge([ + 'amount' => removeRupiahFormatting($this->amount), + ]); + } + + public function rules(): array + { + $isEdit = $this->isMethod('put'); + + return [ + 'name' => ['required', 'string', 'max:100'], + 'amount' => ['required', 'numeric', 'min:0'], + 'proof' => $isEdit + ? ['nullable', 'image', 'mimes:jpeg,png,jpg,gif,svg', 'max:2048'] + : ['required', 'image', 'mimes:jpeg,png,jpg,gif,svg', 'max:2048'], + ]; + } + + protected function failedValidation(Validator $validator): void + { + $this->handleValidationFailure($validator); + } +} diff --git a/app/Models/Expense.php b/app/Models/Expense.php index fd66e0a..106d293 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -2,12 +2,15 @@ namespace App\Models; +use App\Observers\ExpenseObserver; +use Illuminate\Database\Eloquent\Attributes\ObservedBy; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\MorphOne; use Illuminate\Database\Eloquent\SoftDeletes; +#[ObservedBy([ExpenseObserver::class])] class Expense extends Model { use HasFactory, SoftDeletes; diff --git a/app/Observers/ExpenseObserver.php b/app/Observers/ExpenseObserver.php new file mode 100644 index 0000000..dff45be --- /dev/null +++ b/app/Observers/ExpenseObserver.php @@ -0,0 +1,51 @@ +attachment && $expense->attachment->formatted_attachment) { + Storage::delete("expenses/{$expense->attachment->formatted_attachment}"); + } + } + + /** + * Handle the Expense "restored" event. + */ + public function restored(Expense $expense): void + { + // + } + + /** + * Handle the Expense "force deleted" event. + */ + public function forceDeleted(Expense $expense): void + { + // + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 42ba323..ee8793b 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -4,6 +4,7 @@ use App\Models\Barbershop; use App\Models\Customer; +use App\Models\Expense; use App\Models\Service; use App\Models\User; use Illuminate\Support\Facades\Route; @@ -28,5 +29,6 @@ public function boot(): void Route::bind('user', fn (string $user) => User::findOrFail(decryptId($user))); Route::bind('customer', fn (string $customer) => Customer::findOrFail(decryptId($customer))); Route::bind('service', fn (string $service) => Service::findOrFail(decryptId($service))); + Route::bind('expense', fn (string $expense) => Expense::findOrFail(decryptId($expense))); } } diff --git a/public/assets/admin/js/custom/expense.js b/public/assets/admin/js/custom/expense.js new file mode 100644 index 0000000..12a74e3 --- /dev/null +++ b/public/assets/admin/js/custom/expense.js @@ -0,0 +1,30 @@ +$(document).ready(function () { + $("#createModal").on("show.bs.modal", function (event) { + const button = $(event.relatedTarget); + const data = { + modalTitle: button.data("modal-title"), + url: button.data("url"), + method: button.data("method"), + + name: button.data("name"), + amount: button.data("amount"), + }; + + $(".modal-title").text(data.modalTitle); + $("#form").attr('action', data.url); + $("#form-method").val(data.method); + + if (data.method === 'put') { + $("#name").val(data.name); + $("#amount").val(data.amount); + } + }); + + $('#createModal').on('hidden.bs.modal', function () { + const method = $("#form-method").val(); + if (method === 'put') { + $("#name").val(''); + $("#amount").val(''); + } + }); +}); diff --git a/resources/views/pages/admin/finance/expenses.blade.php b/resources/views/pages/admin/finance/expenses.blade.php new file mode 100644 index 0000000..af76d31 --- /dev/null +++ b/resources/views/pages/admin/finance/expenses.blade.php @@ -0,0 +1,154 @@ +@extends('layouts.admin') +@section('styles') + +@endsection +@section('app') +
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + @foreach ($expenses as $expense) + + + + + + + + + @endforeach + +
NoNamaJumlahBuktiTanggalAksi
{{ $loop->iteration }}{{ $expense->name }}{{ formatToRupiah($expense->amount) ?? '-' }} + @if ($expense->attachment && $expense->attachment->formatted_attachment) + attachment->formatted_attachment}") }}"> + attachment->formatted_attachment}") }}" + alt="{{ $expense->name }}" width="77" height="77"> + + @else + + Default Image + + @endif + {{ formatDateIndo($expense->created_at) }} +
    +
  • + + + +
  • +
  • +
    + @csrf + @method('delete') + + + +
    +
  • +
+
+
+
+
+
+
+ + +
+@endsection +@section('afterScripts') + + + + + + +@endsection diff --git a/resources/views/partials/admin/_sidebar.blade.php b/resources/views/partials/admin/_sidebar.blade.php index 1f4af96..af2e5e5 100644 --- a/resources/views/partials/admin/_sidebar.blade.php +++ b/resources/views/partials/admin/_sidebar.blade.php @@ -82,6 +82,18 @@ Layanan + +
diff --git a/routes/web.php b/routes/web.php index 4039c35..14dd40f 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ use App\Http\Controllers\Admin\Auth\LoginController; use App\Http\Controllers\Admin\Dashboard\OverviewController; +use App\Http\Controllers\Admin\Finance\ExpenseController; use App\Http\Controllers\Admin\Master\BarbershopController; use App\Http\Controllers\Admin\Master\CustomerController; use App\Http\Controllers\Admin\Master\ServiceController; @@ -59,4 +60,13 @@ Route::delete('delete/{service}', [ServiceController::class, 'delete'])->name('master.service.delete'); }); }); + + Route::prefix('finance')->group(function () { + Route::get('/expenses', [ExpenseController::class, 'index'])->name('finance.expenses'); + Route::prefix('expense')->group(function () { + Route::post('store', [ExpenseController::class, 'store'])->name('finance.expense.store'); + Route::put('update/{expense}', [ExpenseController::class, 'update'])->name('finance.expense.update'); + Route::delete('delete/{expense}', [ExpenseController::class, 'delete'])->name('finance.expense.delete'); + }); + }); });