From b87203d6abe25aebf53e993f7b2f519403f56f9b Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Fri, 10 Jul 2026 11:26:06 +0700 Subject: [PATCH] feat: implement permission-based messaging for purchase and stock verification actions, enhancing user feedback based on roles --- .../Manage/Purchase/PurchaseController.php | 19 ++++++-- .../Manage/Stock/RetailStockController.php | 2 +- .../Admin/Manage/Stock/StockController.php | 7 ++- app/Services/Manage/StockService.php | 39 +++++++++++---- tests/Feature/Admin/Manage/StockTest.php | 48 +++++++++++++++++++ 5 files changed, 102 insertions(+), 13 deletions(-) diff --git a/app/Http/Controllers/Admin/Manage/Purchase/PurchaseController.php b/app/Http/Controllers/Admin/Manage/Purchase/PurchaseController.php index a6debc3..a382dbc 100644 --- a/app/Http/Controllers/Admin/Manage/Purchase/PurchaseController.php +++ b/app/Http/Controllers/Admin/Manage/Purchase/PurchaseController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Admin\Manage\Purchase; +use App\Enums\Permission; use App\Http\Controllers\Concerns\FlashesEntityMessage; use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Controller; @@ -46,7 +47,11 @@ public function store(PurchaseRequest $request): RedirectResponse { $this->purchaseService->create($request->validated(), $request->user()); - $this->flashSuccess('Belanja berhasil diajukan dan menunggu verifikasi owner.'); + if ($request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { + $this->flashCreated('Belanja'); + } else { + $this->flashSuccess('Belanja berhasil diajukan dan menunggu verifikasi owner.'); + } return redirect()->route('admin.manage.purchases.index'); } @@ -64,7 +69,11 @@ public function update(PurchaseRequest $request, Purchase $purchase): RedirectRe { $this->purchaseService->update($purchase, $request->validated(), $request->user()); - $this->flashSuccess('Perubahan belanja berhasil diajukan dan menunggu verifikasi owner.'); + if ($request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { + $this->flashUpdated('Belanja'); + } else { + $this->flashSuccess('Perubahan belanja berhasil diajukan dan menunggu verifikasi owner.'); + } return redirect()->route('admin.manage.purchases.index'); } @@ -73,7 +82,11 @@ public function destroy(Request $request, Purchase $purchase): RedirectResponse { $this->purchaseService->delete($purchase, $request->user()); - $this->flashSuccess('Penghapusan belanja berhasil diajukan dan menunggu verifikasi owner.'); + if ($request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { + $this->flashDeleted('Belanja'); + } else { + $this->flashSuccess('Penghapusan belanja berhasil diajukan dan menunggu verifikasi owner.'); + } return redirect()->route('admin.manage.purchases.index'); } diff --git a/app/Http/Controllers/Admin/Manage/Stock/RetailStockController.php b/app/Http/Controllers/Admin/Manage/Stock/RetailStockController.php index c37c9aa..eeb334f 100644 --- a/app/Http/Controllers/Admin/Manage/Stock/RetailStockController.php +++ b/app/Http/Controllers/Admin/Manage/Stock/RetailStockController.php @@ -26,7 +26,7 @@ public function transfer(RetailStockTransferRequest $request): JsonResponse return response()->json([ 'success' => true, - 'message' => 'Pengajuan transfer stok ecer berhasil dikirim dan menunggu verifikasi owner.', + 'message' => 'Transfer stok ecer berhasil dilakukan.', ]); } } diff --git a/app/Http/Controllers/Admin/Manage/Stock/StockController.php b/app/Http/Controllers/Admin/Manage/Stock/StockController.php index b94a1b9..62daf7d 100644 --- a/app/Http/Controllers/Admin/Manage/Stock/StockController.php +++ b/app/Http/Controllers/Admin/Manage/Stock/StockController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Admin\Manage\Stock; +use App\Enums\Permission; use App\Http\Controllers\Concerns\FlashesEntityMessage; use App\Http\Controllers\Controller; use App\Http\Requests\Admin\Manage\StockVerifyRequest; @@ -40,7 +41,11 @@ public function verify(StockVerifyRequest $request, Cutting $cutting): RedirectR $request->validated('result_prices'), ); - $this->flashSuccess('Verifikasi berhasil diajukan. Menunggu persetujuan owner.'); + if ($request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { + $this->flashSuccess('Verifikasi berhasil disimpan. Stok produk telah ditambahkan ke toko.'); + } else { + $this->flashSuccess('Verifikasi berhasil diajukan. Menunggu persetujuan owner.'); + } return redirect()->route('admin.manage.stocks.index'); } diff --git a/app/Services/Manage/StockService.php b/app/Services/Manage/StockService.php index 2c6579f..28f675a 100644 --- a/app/Services/Manage/StockService.php +++ b/app/Services/Manage/StockService.php @@ -3,6 +3,7 @@ namespace App\Services\Manage; use App\Enums\CuttingStatus; +use App\Enums\Permission; use App\Models\Cutting; use App\Models\CuttingMaterial; use App\Models\CuttingResult; @@ -85,8 +86,10 @@ public function submitVerification( ]); } + $isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value); + try { - DB::transaction(function () use ($cutting, $user, $verificationNote, $results, $resultPrices): void { + DB::transaction(function () use ($cutting, $user, $verificationNote, $results, $resultPrices, $isOwner): void { $cutting->load(['materials.rawMaterialPrice', 'results']); if ($results !== null) { @@ -111,7 +114,15 @@ public function submitVerification( } $cutting->submitted_by_id = $user->id; - $cutting->status = CuttingStatus::PENDING_VERIFICATION; + + if ($isOwner) { + $this->applyProductStockOnVerify($cutting); + $this->applyResultPricesToProducts($cutting); + $cutting->status = CuttingStatus::VERIFIED; + } else { + $cutting->status = CuttingStatus::PENDING_VERIFICATION; + } + $cutting->save(); }); } catch (ValidationException $e) { @@ -128,14 +139,26 @@ public function submitVerification( $description = $cutting->description ?? '-'; - $this->pushNotificationService->sendToRoles( - '📦 Verifikasi Stok Menunggu Persetujuan', - "Cutting dengan deskripsi '{$description}' telah diajukan verifikasi dan menunggu persetujuan owner.", - ['owner', 'developer', 'direktur'], - route('admin.manage.stocks.index'), - ); + if ($isOwner) { + $this->pushNotificationService->sendToRoles( + '📦 Stok Cutting Diverifikasi', + "Cutting dengan deskripsi '{$description}' telah disetujui owner dan stok produk telah ditambahkan ke toko.", + ['owner', 'developer', 'direktur'], + route('admin.manage.stocks.index'), + ); + } else { + $this->pushNotificationService->sendToRoles( + '📦 Verifikasi Stok Menunggu Persetujuan', + "Cutting dengan deskripsi '{$description}' telah diajukan verifikasi dan menunggu persetujuan owner.", + ['owner', 'developer', 'direktur'], + route('admin.manage.stocks.index'), + ); + } $this->cacheForgetByPattern('manage:stocks:*'); + if ($isOwner) { + $this->cacheForgetByPattern('prices:*'); + } } public function approveVerification( diff --git a/tests/Feature/Admin/Manage/StockTest.php b/tests/Feature/Admin/Manage/StockTest.php index d6f42b7..c038e85 100644 --- a/tests/Feature/Admin/Manage/StockTest.php +++ b/tests/Feature/Admin/Manage/StockTest.php @@ -313,4 +313,52 @@ function createCompletedCuttingSetup(): array ]) ->assertForbidden(); }); + + test('owner can verify stock directly without pending verification', function () { + $user = createStockUserWithPermission( + PermissionEnum::STOCKS_VIEW, + PermissionEnum::CUTTINGS_VERIFY, + PermissionEnum::OWNER_VERIFICATIONS_VERIFY + ); + + $setup = createCompletedCuttingSetup(); + $cutting = $setup['cutting']; + + $payload = [ + 'verification_note' => 'Verified directly by owner', + 'results' => [ + [ + 'product_variant_id' => $setup['variant']->id, + 'good' => 6, + 'reject' => 1, + ], + ], + 'result_prices' => [ + [ + 'product_variant_id' => $setup['variant']->id, + 'prices' => [ + [ + 'type' => 'harga_modal', + 'price' => 50000, + ], + [ + 'type' => 'retail', + 'price' => 75000, + ], + ], + ], + ], + ]; + + $this->actingAs($user) + ->post(route('admin.manage.stocks.verify', $cutting), $payload) + ->assertRedirect(route('admin.manage.stocks.index')); + + $cutting->refresh(); + $this->assertEquals(CuttingStatus::VERIFIED, $cutting->status); + + $setup['variant']->refresh(); + // Base stock was 10. Added good stock is 6. + $this->assertEquals(16, $setup['variant']->stock); + }); });