From e4b0c84180f1c0b08055310c2b58636f00fc4f76 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Mon, 25 Nov 2024 17:31:13 +0700 Subject: [PATCH] feat(payroll): crud,route model binding,custom js dan lainnya yang berkaitan dengan gaji --- .../Admin/Finance/PayrollController.php | 95 +++++++++++++ .../Requests/Admin/Finance/PayrollRequest.php | 54 ++++++++ app/Models/Payroll.php | 2 + app/Providers/RouteServiceProvider.php | 2 + ...024_11_18_172841_create_payrolls_table.php | 2 + public/assets/admin/js/custom/payroll.js | 69 ++++++++++ .../admin/finance/payroll/create.blade.php | 130 ++++++++++++++++++ .../admin/finance/payroll/edit.blade.php | 126 +++++++++++++++++ .../admin/finance/payroll/index.blade.php | 86 ++++++++++++ .../views/partials/admin/_sidebar.blade.php | 7 + routes/web.php | 11 ++ 11 files changed, 584 insertions(+) create mode 100644 app/Http/Controllers/Admin/Finance/PayrollController.php create mode 100644 app/Http/Requests/Admin/Finance/PayrollRequest.php create mode 100644 public/assets/admin/js/custom/payroll.js create mode 100644 resources/views/pages/admin/finance/payroll/create.blade.php create mode 100644 resources/views/pages/admin/finance/payroll/edit.blade.php create mode 100644 resources/views/pages/admin/finance/payroll/index.blade.php diff --git a/app/Http/Controllers/Admin/Finance/PayrollController.php b/app/Http/Controllers/Admin/Finance/PayrollController.php new file mode 100644 index 0000000..a0a9a01 --- /dev/null +++ b/app/Http/Controllers/Admin/Finance/PayrollController.php @@ -0,0 +1,95 @@ + 'Gaji', + 'payrolls' => Payroll::latest()->get(), + ]); + } + + public function create(): View + { + return view('pages.admin.finance.payroll.create', [ + 'pageTitle' => 'Tambah Gaji', + 'employees' => User::query()->barbershop()->latest()->get(), + ]); + } + + public function store(PayrollRequest $request): RedirectResponse + { + $validatedData = $request->validated(); + Payroll::create(array_merge($validatedData, [ + 'user_id' => Auth::id(), + 'employee_id' => $validatedData['employee'], + 'barbershop_id' => Auth::user()->barbershop_id, + ])); + + notify()->success('Data berhasil ditambahkan', 'Berhasil'); + + return redirect('dashboard/finance/payrolls'); + } + + public function edit(Payroll $payroll): View + { + return view('pages.admin.finance.payroll.edit', [ + 'pageTitle' => 'Edit Gaji', + 'employees' => User::query()->barbershop()->latest()->get(), + 'payroll' => $payroll, + ]); + } + + public function update(Payroll $payroll, PayrollRequest $request): RedirectResponse + { + $validatedData = $request->validated(); + + $payroll->update($validatedData); + + notify()->success('Data berhasil diubah', 'Berhasil'); + + return redirect('dashboard/finance/payrolls'); + } + + public function delete(Payroll $payroll): RedirectResponse + { + $payroll->delete(); + + notify()->success('Data berhasil dihapus', 'Berhasil'); + + return back(); + } + + public function getSalaryEmployee(string $employeeId): JsonResponse + { + $baseSalary = User::find($employeeId)->base_salary; + $latestPayroll = Payroll::where('user_id', $employeeId)->latest()->first(); + $shavingResults = Transaction::where('user_id', $employeeId) + ->when($latestPayroll, function ($query) use ($latestPayroll) { + $query->whereBetween('created_at', [$latestPayroll->created_at, now()]); + }) + ->sum('total'); + + return response()->json([ + 'status' => true, + 'message' => 'Data retrieved successfully', + 'data' => [ + 'baseSalary' => formatToRupiah($baseSalary), + 'shavingResults' => formatToRupiah($shavingResults), + ], + ]); + } +} diff --git a/app/Http/Requests/Admin/Finance/PayrollRequest.php b/app/Http/Requests/Admin/Finance/PayrollRequest.php new file mode 100644 index 0000000..b51f618 --- /dev/null +++ b/app/Http/Requests/Admin/Finance/PayrollRequest.php @@ -0,0 +1,54 @@ +merge([ + 'amount' => removeRupiahFormatting($this->amount), + 'incentive' => removeRupiahFormatting($this->incentive), + 'cut' => removeRupiahFormatting($this->cut), + 'shaving_result' => removeRupiahFormatting($this->shaving_result), + 'total' => removeRupiahFormatting($this->total), + ]); + } + + public function rules(): array + { + $rules = [ + 'amount' => ['required', 'numeric', 'min:0', 'max:99999999.99'], + 'incentive' => ['required', 'numeric', 'min:0', 'max:99999999.99'], + 'cut' => ['required', 'numeric', 'min:0', 'max:99999999.99'], + 'total' => ['required', 'numeric', 'min:0', 'max:99999999.99'], + 'shaving_result' => ['required', 'numeric', 'min:0', 'max:99999999.99'], + 'percentage_shaving' => ['required', 'numeric', 'min:0', 'max:100'], + 'description' => ['required', 'string', 'max:65535'], + ]; + + if (! $this->isMethod('put')) { + $rules['employee'] = ['required', Rule::exists('users', 'id')]; + } + + return $rules; + } + + protected function failedValidation(Validator $validator): void + { + $this->handleValidationFailure($validator); + } +} diff --git a/app/Models/Payroll.php b/app/Models/Payroll.php index 5791fd0..ab1730f 100644 --- a/app/Models/Payroll.php +++ b/app/Models/Payroll.php @@ -18,7 +18,9 @@ class Payroll extends Model 'barbershop_id', 'amount', 'incentive', + 'shaving_result', 'cut', + 'percentage_shaving', 'total', 'description', ]; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index ee8793b..b008cb1 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -5,6 +5,7 @@ use App\Models\Barbershop; use App\Models\Customer; use App\Models\Expense; +use App\Models\Payroll; use App\Models\Service; use App\Models\User; use Illuminate\Support\Facades\Route; @@ -30,5 +31,6 @@ public function boot(): void 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))); + Route::bind('payroll', fn (string $payroll) => Payroll::findOrFail(decryptId($payroll))); } } diff --git a/database/migrations/2024_11_18_172841_create_payrolls_table.php b/database/migrations/2024_11_18_172841_create_payrolls_table.php index ca96e23..e23e732 100644 --- a/database/migrations/2024_11_18_172841_create_payrolls_table.php +++ b/database/migrations/2024_11_18_172841_create_payrolls_table.php @@ -19,6 +19,8 @@ public function up(): void $table->decimal('amount', 10, 2)->comment('Base salary'); $table->decimal('incentive', 10, 2); $table->decimal('cut', 10, 2); + $table->decimal('shaving_result', 10, 2); + $table->decimal('percentage_shaving', 5, 2); $table->decimal('total', 10, 2); $table->text('description'); $table->timestamps(); diff --git a/public/assets/admin/js/custom/payroll.js b/public/assets/admin/js/custom/payroll.js new file mode 100644 index 0000000..cabc766 --- /dev/null +++ b/public/assets/admin/js/custom/payroll.js @@ -0,0 +1,69 @@ +$(document).ready(function () { + let shavingResults = parseFloat(unformatRupiah($('#shaving_result').val())) || 0; + if ($('#employee').val()) { + $('#percentage_shaving').prop('readonly', false); + } + + $('#employee').on('change', function () { + let employeeId = $(this).val(); + + if (!employeeId) { + $('#percentage_shaving').prop('readonly', true); + $('#percentage_shaving').val(''); + return; + } + + $.ajax({ + url: `/dashboard/finance/payroll/get-salary/${employeeId}`, + method: 'GET', + success: function (response) { + if (response.status) { + $('#amount').val(response.data.baseSalary || '0'); + $('#shaving_result').val(response.data.shavingResults || '0'); + + shavingResults = parseFloat(unformatRupiah(response.data.shavingResults)) || 0; + + $('#percentage_shaving').prop('readonly', false); + + calculateTotal(); + } + }, + error: function (xhr, status, error) { + Swal.fire({ + icon: 'error', + title: 'Oops...', + text: 'Terjadi kesalahan saat mengambil data karyawan! Silakan coba lagi. Jika masalah berlanjut, hubungi administrator.', + }); + + $('#percentage_shaving').prop('readonly', true); + $('#percentage_shaving').val(''); + } + }); + }); + + $('#amount, #incentive, #cut, #percentage_shaving').on('input', function () { + calculateTotal(); + }); + + function calculateTotal() { + let amount = parseInt(unformatRupiah($('#amount').val())) || 0; + let incentive = parseInt(unformatRupiah($('#incentive').val())) || 0; + let cut = parseInt(unformatRupiah($('#cut').val())) || 0; + let percentage = parseFloat($('#percentage_shaving').val()) || 0; + + let percentageAmount = (shavingResults * percentage) / 100; + + let total = amount + incentive + percentageAmount - cut; + $('#total').val('Rp' + formatRupiah(total)); + } + + function formatRupiah(angka) { + if (!angka) return '0'; + return new Intl.NumberFormat('id-ID').format(angka); + } + + function unformatRupiah(rupiahStr) { + if (!rupiahStr) return '0'; + return rupiahStr.replace(/\D/g, ''); + } +}); diff --git a/resources/views/pages/admin/finance/payroll/create.blade.php b/resources/views/pages/admin/finance/payroll/create.blade.php new file mode 100644 index 0000000..9887855 --- /dev/null +++ b/resources/views/pages/admin/finance/payroll/create.blade.php @@ -0,0 +1,130 @@ +@extends('layouts.admin') +@section('styles') + +@endsection +@section('app') +
+
+
+ Kembali +
+
+
+
+
+ @csrf +
+ + + @error('employee') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('amount') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('incentive') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('cut') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('shaving_result') +
+ {{ $message }} +
+ @enderror +
+
+ +
+ + +
+ @error('percentage_shaving') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('total') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('description') +
+ {{ $message }} +
+ @enderror +
+
+ +
+
+
+
+
+@endsection +@section('afterScripts') + + + + + + +@endsection diff --git a/resources/views/pages/admin/finance/payroll/edit.blade.php b/resources/views/pages/admin/finance/payroll/edit.blade.php new file mode 100644 index 0000000..0c1db45 --- /dev/null +++ b/resources/views/pages/admin/finance/payroll/edit.blade.php @@ -0,0 +1,126 @@ +@extends('layouts.admin') +@section('styles') + +@endsection +@section('app') +
+
+
+ Kembali +
+
+
+
+
+ @csrf + @method('put') +
+ + + @error('employee') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('amount') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('incentive') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('cut') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('shaving_result') +
+ {{ $message }} +
+ @enderror +
+
+ +
+ + +
+ @error('percentage_shaving') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('total') +
+ {{ $message }} +
+ @enderror +
+
+ + + @error('description') +
+ {{ $message }} +
+ @enderror +
+
+ +
+
+
+
+
+@endsection +@section('afterScripts') + + + + + + +@endsection diff --git a/resources/views/pages/admin/finance/payroll/index.blade.php b/resources/views/pages/admin/finance/payroll/index.blade.php new file mode 100644 index 0000000..929323d --- /dev/null +++ b/resources/views/pages/admin/finance/payroll/index.blade.php @@ -0,0 +1,86 @@ +@extends('layouts.admin') +@section('styles') + +@endsection +@section('app') +
+
+
+
+
+ Tambah +
+
+
+
+
+ + + + + + + + + + + + + + + + + + @foreach ($payrolls as $payroll) + + + + + + + + + + + + + + @endforeach + +
NoPegawaiJumlahInsentifPotonganHasil MencukurPersentase MencukurTotalKeteranganTanggalAksi
{{ $loop->iteration }}{{ $payroll->employee->biography->full_name }}{{ formatToRupiah($payroll->amount) }}{{ formatToRupiah($payroll->incetive) }}{{ formatToRupiah($payroll->cut) }}{{ formatToRupiah($payroll->shaving_result) }}{{ $payroll->percentage_shaving }} %{{ formatToRupiah($payroll->total) }}{{ $payroll->description }}{{ formatDateIndo($payroll->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 af2e5e5..b1c5e38 100644 --- a/resources/views/partials/admin/_sidebar.blade.php +++ b/resources/views/partials/admin/_sidebar.blade.php @@ -94,6 +94,13 @@ Pengeluaran +
diff --git a/routes/web.php b/routes/web.php index 14dd40f..d3c8e67 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,6 +3,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\Finance\PayrollController; use App\Http\Controllers\Admin\Master\BarbershopController; use App\Http\Controllers\Admin\Master\CustomerController; use App\Http\Controllers\Admin\Master\ServiceController; @@ -68,5 +69,15 @@ Route::put('update/{expense}', [ExpenseController::class, 'update'])->name('finance.expense.update'); Route::delete('delete/{expense}', [ExpenseController::class, 'delete'])->name('finance.expense.delete'); }); + + Route::get('/payrolls', [PayrollController::class, 'index'])->name('finance.payrolls'); + Route::prefix('payroll')->group(function () { + Route::get('create', [PayrollController::class, 'create'])->name('finance.payroll.create'); + Route::post('store', [PayrollController::class, 'store'])->name('finance.payroll.store'); + Route::get('edit/{payroll}', [PayrollController::class, 'edit'])->name('finance.payroll.edit'); + Route::put('update/{payroll}', [PayrollController::class, 'update'])->name('finance.payroll.update'); + Route::delete('delete/{payroll}', [PayrollController::class, 'delete'])->name('finance.payroll.delete'); + Route::get('get-salary/{employeeId}', [PayrollController::class, 'getSalaryEmployee'])->name('finance.payroll.getSalaryEmployee'); + }); }); });