refactor: simplify raw material creation, update, and deletion processes by removing owner verification checks and enhancing user feedback
This commit is contained in:
parent
bb74fb49c8
commit
e431cbb54b
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers\Admin\Master;
|
||||
|
||||
use App\Enums\Permission;
|
||||
use App\Enums\RawMaterialUnit;
|
||||
use App\Http\Controllers\Concerns\FlashesEntityMessage;
|
||||
use App\Http\Controllers\Concerns\ParsesDataTableQuery;
|
||||
@ -56,12 +55,7 @@ public function create(): Response
|
||||
public function store(RawMaterialRequest $request): RedirectResponse
|
||||
{
|
||||
$this->rawMaterialService->create($request->validated(), $request->user());
|
||||
|
||||
if ($request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) {
|
||||
$this->flashCreated('Bahan baku');
|
||||
} else {
|
||||
$this->flashSuccess('Bahan baku berhasil diajukan dan menunggu verifikasi owner.');
|
||||
}
|
||||
$this->flashCreated('Bahan baku');
|
||||
|
||||
return redirect()->route('admin.master.raw_materials.index');
|
||||
}
|
||||
@ -77,12 +71,7 @@ public function edit(RawMaterial $rawMaterial): Response
|
||||
public function update(RawMaterialRequest $request, RawMaterial $rawMaterial): RedirectResponse
|
||||
{
|
||||
$this->rawMaterialService->update($rawMaterial, $request->validated(), $request->user());
|
||||
|
||||
if ($request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) {
|
||||
$this->flashUpdated('Bahan baku');
|
||||
} else {
|
||||
$this->flashSuccess('Perubahan bahan baku berhasil diajukan dan menunggu verifikasi owner.');
|
||||
}
|
||||
$this->flashUpdated('Bahan baku');
|
||||
|
||||
return redirect()->route('admin.master.raw_materials.index');
|
||||
}
|
||||
@ -90,12 +79,7 @@ public function update(RawMaterialRequest $request, RawMaterial $rawMaterial): R
|
||||
public function destroy(Request $request, RawMaterial $rawMaterial): RedirectResponse
|
||||
{
|
||||
$this->rawMaterialService->delete($rawMaterial, $request->user());
|
||||
|
||||
if ($request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) {
|
||||
$this->flashDeleted('Bahan baku');
|
||||
} else {
|
||||
$this->flashSuccess('Penghapusan bahan baku berhasil diajukan dan menunggu verifikasi owner.');
|
||||
}
|
||||
$this->flashDeleted('Bahan baku');
|
||||
|
||||
return redirect()->route('admin.master.raw_materials.index');
|
||||
}
|
||||
@ -103,12 +87,7 @@ public function destroy(Request $request, RawMaterial $rawMaterial): RedirectRes
|
||||
public function toggleStatus(ToggleStatusRequest $request, RawMaterial $rawMaterial): RedirectResponse
|
||||
{
|
||||
$this->rawMaterialService->toggleStatus($rawMaterial, $request->validated(), $request->user());
|
||||
|
||||
if ($request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) {
|
||||
$this->flashStatusUpdated('bahan baku');
|
||||
} else {
|
||||
$this->flashSuccess('Perubahan status bahan baku berhasil diajukan dan menunggu verifikasi owner.');
|
||||
}
|
||||
$this->flashStatusUpdated('bahan baku');
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
@ -3,8 +3,6 @@
|
||||
namespace App\Services\Master;
|
||||
|
||||
use App\Enums\OwnerVerificationAction;
|
||||
use App\Enums\OwnerVerificationStatus;
|
||||
use App\Enums\Permission;
|
||||
use App\Enums\RawMaterialUnit;
|
||||
use App\Models\OwnerVerificationRequest;
|
||||
use App\Models\RawMaterial;
|
||||
@ -34,7 +32,6 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $st
|
||||
{
|
||||
$query = RawMaterial::query()
|
||||
->with([
|
||||
'pendingOwnerVerificationRequest.submittedBy.profile',
|
||||
'prices' => fn ($query) => $query
|
||||
->orderBy('created_at')
|
||||
->with('media')
|
||||
@ -85,18 +82,6 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $st
|
||||
$price->unsetRelation('rawMaterial');
|
||||
});
|
||||
|
||||
$pendingRequest = $rawMaterial->pendingOwnerVerificationRequest;
|
||||
|
||||
$rawMaterial->setAttribute('has_pending_request', $pendingRequest !== null);
|
||||
$rawMaterial->setAttribute('pending_request_id', $pendingRequest?->id);
|
||||
$rawMaterial->setAttribute('pending_request_action', $pendingRequest?->action->value);
|
||||
$rawMaterial->setAttribute('pending_request_action_label', $pendingRequest?->action->label());
|
||||
$rawMaterial->setAttribute('pending_request_submitted_by_name', $pendingRequest?->submittedBy?->profile?->full_name ?? $pendingRequest?->submittedBy?->username);
|
||||
$rawMaterial->setAttribute(
|
||||
'display_is_active',
|
||||
$pendingRequest?->pendingToggleIsActive() ?? $rawMaterial->is_active,
|
||||
);
|
||||
|
||||
return $rawMaterial;
|
||||
});
|
||||
}
|
||||
@ -118,229 +103,90 @@ public function findForEdit(RawMaterial $rawMaterial): RawMaterial
|
||||
|
||||
public function create(array $validated, User $user): void
|
||||
{
|
||||
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||
|
||||
$rawMaterial = $this->runInTransaction(
|
||||
function () use ($validated, $user, $isOwner): RawMaterial {
|
||||
function () use ($validated): RawMaterial {
|
||||
$rawMaterial = RawMaterial::create([
|
||||
'name' => $validated['name'],
|
||||
'unit' => $validated['unit'],
|
||||
'is_active' => $isOwner,
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
foreach ($validated['prices'] as $index => $priceData) {
|
||||
$this->createPrice($rawMaterial, $priceData, $index);
|
||||
}
|
||||
|
||||
if (! $isOwner) {
|
||||
OwnerVerificationRequest::create([
|
||||
'action' => OwnerVerificationAction::CREATE,
|
||||
'status' => OwnerVerificationStatus::PENDING,
|
||||
'subject_type' => RawMaterial::class,
|
||||
'subject_id' => $rawMaterial->id,
|
||||
'submitted_by_id' => $user->id,
|
||||
'payload' => [
|
||||
'old' => null,
|
||||
'new' => $this->snapshotRawMaterial($rawMaterial->fresh(['prices'])),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return $rawMaterial;
|
||||
},
|
||||
'Gagal membuat bahan baku',
|
||||
);
|
||||
|
||||
if ($isOwner) {
|
||||
$this->cacheForgetByPattern('master:raw_materials:*');
|
||||
}
|
||||
$this->cacheForgetByPattern('master:raw_materials:*');
|
||||
|
||||
if (! $isOwner) {
|
||||
$this->notifyForPendingRequest(
|
||||
$user,
|
||||
'Tambah Bahan Baku',
|
||||
"Pengajuan tambah bahan baku '{$validated['name']}' menunggu verifikasi owner.",
|
||||
route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]),
|
||||
(string) $rawMaterial->id,
|
||||
);
|
||||
}
|
||||
$this->notifyOwner(
|
||||
'Tambah Bahan Baku',
|
||||
"Bahan baku '{$validated['name']}' telah ditambahkan oleh {$user->name}.",
|
||||
route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]),
|
||||
);
|
||||
}
|
||||
|
||||
public function update(RawMaterial $rawMaterial, array $validated, User $user): void
|
||||
{
|
||||
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||
|
||||
$this->runInTransaction(
|
||||
function () use ($validated, $rawMaterial, $user, $isOwner): void {
|
||||
if ($isOwner) {
|
||||
$payload = $this->enrichPayload($this->buildPayloadFromValidated($validated));
|
||||
$this->applyPayloadToRawMaterial($rawMaterial, $payload);
|
||||
function () use ($validated, $rawMaterial): void {
|
||||
$payload = $this->enrichPayload($this->buildPayloadFromValidated($validated));
|
||||
$this->applyPayloadToRawMaterial($rawMaterial, $payload);
|
||||
|
||||
foreach ($validated['prices'] as $index => $priceData) {
|
||||
if (! empty($priceData['id'])) {
|
||||
$price = $rawMaterial->prices()->find($priceData['id']);
|
||||
if ($price) {
|
||||
$this->syncPriceImages($price, $priceData, $index);
|
||||
}
|
||||
} else {
|
||||
$this->createPrice($rawMaterial, $priceData, $index);
|
||||
foreach ($validated['prices'] as $index => $priceData) {
|
||||
if (! empty($priceData['id'])) {
|
||||
$price = $rawMaterial->prices()->find($priceData['id']);
|
||||
if ($price) {
|
||||
$this->syncPriceImages($price, $priceData, $index);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$verificationRequest = OwnerVerificationRequest::create([
|
||||
'action' => OwnerVerificationAction::UPDATE,
|
||||
'status' => OwnerVerificationStatus::PENDING,
|
||||
'subject_type' => RawMaterial::class,
|
||||
'subject_id' => $rawMaterial->id,
|
||||
'submitted_by_id' => $user->id,
|
||||
'payload' => [
|
||||
'old' => $this->snapshotRawMaterial($rawMaterial),
|
||||
'new' => $this->enrichPayload($this->buildPayloadFromValidated($validated)),
|
||||
],
|
||||
]);
|
||||
|
||||
foreach ($validated['prices'] as $index => $priceData) {
|
||||
$isNewPrice = empty($priceData['id']);
|
||||
$this->syncRequestPriceImages($verificationRequest, $priceData, $index, required: $isNewPrice);
|
||||
} else {
|
||||
$this->createPrice($rawMaterial, $priceData, $index);
|
||||
}
|
||||
}
|
||||
},
|
||||
'Gagal memperbarui bahan baku',
|
||||
);
|
||||
|
||||
if ($isOwner) {
|
||||
$this->cacheForgetByPattern('master:raw_materials:*');
|
||||
}
|
||||
$this->cacheForgetByPattern('master:raw_materials:*');
|
||||
|
||||
if (! $isOwner) {
|
||||
$changedVariants = [];
|
||||
foreach ($validated['prices'] as $priceData) {
|
||||
if (! empty($priceData['id'])) {
|
||||
$originalPrice = $rawMaterial->prices->firstWhere('id', $priceData['id']);
|
||||
if ($originalPrice) {
|
||||
$isChanged = false;
|
||||
if ($originalPrice->variant !== $priceData['variant']) {
|
||||
$isChanged = true;
|
||||
}
|
||||
if ($originalPrice->price !== (int) $priceData['price']) {
|
||||
$isChanged = true;
|
||||
}
|
||||
if (rtrim(rtrim(number_format((float) $originalPrice->stock, 4, '.', ''), '0'), '.') !== rtrim(rtrim(number_format((float) $priceData['stock'], 4, '.', ''), '0'), '.')) {
|
||||
$isChanged = true;
|
||||
}
|
||||
|
||||
if ($isChanged) {
|
||||
$changedVariants[] = $priceData['variant'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$changedVariants[] = $priceData['variant'];
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($changedVariants)) {
|
||||
$variantsStr = implode(', ', $changedVariants);
|
||||
$this->notifyForPendingRequest(
|
||||
$user,
|
||||
'Ubah Varian Bahan Baku',
|
||||
"Pengajuan ubah varian '{$variantsStr}' pada bahan baku '{$rawMaterial->name}' menunggu verifikasi owner.",
|
||||
route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]),
|
||||
(string) $rawMaterial->id,
|
||||
);
|
||||
} else {
|
||||
$this->notifyForPendingRequest(
|
||||
$user,
|
||||
'Ubah Bahan Baku',
|
||||
"Pengajuan ubah bahan baku '{$rawMaterial->name}' menunggu verifikasi owner.",
|
||||
route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]),
|
||||
(string) $rawMaterial->id,
|
||||
);
|
||||
}
|
||||
}
|
||||
$this->notifyOwner(
|
||||
'Ubah Bahan Baku',
|
||||
"Bahan baku '{$rawMaterial->name}' telah diperbarui oleh {$user->name}.",
|
||||
route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]),
|
||||
);
|
||||
}
|
||||
|
||||
public function delete(RawMaterial $rawMaterial, User $user): void
|
||||
{
|
||||
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||
$name = $rawMaterial->name;
|
||||
|
||||
if ($isOwner) {
|
||||
$this->applyDeleteSubject($rawMaterial);
|
||||
$this->cacheForgetByPattern('master:raw_materials:*');
|
||||
$this->applyDeleteSubject($rawMaterial);
|
||||
$this->cacheForgetByPattern('master:raw_materials:*');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->runInTransaction(
|
||||
function () use ($rawMaterial, $user): void {
|
||||
OwnerVerificationRequest::create([
|
||||
'action' => OwnerVerificationAction::DELETE,
|
||||
'status' => OwnerVerificationStatus::PENDING,
|
||||
'subject_type' => RawMaterial::class,
|
||||
'subject_id' => $rawMaterial->id,
|
||||
'submitted_by_id' => $user->id,
|
||||
'payload' => [
|
||||
'old' => $this->snapshotRawMaterial($rawMaterial),
|
||||
'new' => null,
|
||||
],
|
||||
]);
|
||||
},
|
||||
'Gagal mengajukan penghapusan bahan baku',
|
||||
);
|
||||
|
||||
$this->notifyForPendingRequest(
|
||||
$user,
|
||||
$this->notifyOwner(
|
||||
'Hapus Bahan Baku',
|
||||
"Pengajuan hapus bahan baku '{$rawMaterial->name}' menunggu verifikasi owner.",
|
||||
route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]),
|
||||
(string) $rawMaterial->id,
|
||||
"Bahan baku '{$name}' telah dihapus oleh {$user->name}.",
|
||||
route('admin.master.raw_materials.index'),
|
||||
);
|
||||
}
|
||||
|
||||
public function toggleStatus(RawMaterial $rawMaterial, array $validated, User $user): void
|
||||
{
|
||||
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||
$rawMaterial->update([
|
||||
'is_active' => (bool) $validated['is_active'],
|
||||
]);
|
||||
|
||||
if ($isOwner) {
|
||||
$rawMaterial->update([
|
||||
'is_active' => (bool) $validated['is_active'],
|
||||
]);
|
||||
|
||||
$this->cacheForgetByPattern('master:raw_materials:*');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->runInTransaction(
|
||||
function () use ($rawMaterial, $validated, $user): void {
|
||||
OwnerVerificationRequest::create([
|
||||
'action' => OwnerVerificationAction::TOGGLE_STATUS,
|
||||
'status' => OwnerVerificationStatus::PENDING,
|
||||
'subject_type' => RawMaterial::class,
|
||||
'subject_id' => $rawMaterial->id,
|
||||
'submitted_by_id' => $user->id,
|
||||
'payload' => [
|
||||
'old' => [
|
||||
'name' => $rawMaterial->name,
|
||||
'is_active' => $rawMaterial->is_active,
|
||||
],
|
||||
'new' => [
|
||||
'name' => $rawMaterial->name,
|
||||
'is_active' => (bool) $validated['is_active'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
},
|
||||
'Gagal mengajukan perubahan status bahan baku',
|
||||
);
|
||||
$this->cacheForgetByPattern('master:raw_materials:*');
|
||||
|
||||
$statusLabel = $validated['is_active'] ? 'aktif' : 'nonaktif';
|
||||
|
||||
$this->notifyForPendingRequest(
|
||||
$user,
|
||||
$this->notifyOwner(
|
||||
'Ubah Status Bahan Baku',
|
||||
"Pengajuan ubah status bahan baku '{$rawMaterial->name}' menjadi {$statusLabel} menunggu verifikasi owner.",
|
||||
"Status bahan baku '{$rawMaterial->name}' telah diubah menjadi {$statusLabel} oleh {$user->name}.",
|
||||
route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]),
|
||||
(string) $rawMaterial->id,
|
||||
);
|
||||
}
|
||||
|
||||
@ -384,25 +230,13 @@ public function clearVerificationRequestMedia(OwnerVerificationRequest $verifica
|
||||
}
|
||||
}
|
||||
|
||||
private function notifyForPendingRequest(User $user, string $typeLabel, string $body, string $submitterUrl, ?string $search = null): void
|
||||
private function notifyOwner(string $typeLabel, string $body, string $url): void
|
||||
{
|
||||
$ownerUrl = route('admin.master.raw_materials.index');
|
||||
if ($search !== null) {
|
||||
$ownerUrl = route('admin.master.raw_materials.index', ['search_id' => $search]);
|
||||
}
|
||||
|
||||
$this->pushNotificationService->sendToRoles(
|
||||
"📦 {$typeLabel} Menunggu Persetujuan Owner",
|
||||
"📦 {$typeLabel}",
|
||||
$body,
|
||||
['owner', 'developer', 'direktur'],
|
||||
$ownerUrl,
|
||||
);
|
||||
|
||||
$this->pushNotificationService->sendToUser(
|
||||
'📤 Pengajuan Terkirim',
|
||||
$body,
|
||||
$user->id,
|
||||
$submitterUrl,
|
||||
$url,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -154,31 +154,19 @@
|
||||
->name('store');
|
||||
|
||||
Route::get('{rawMaterial}/edit', [RawMaterialController::class, 'edit'])
|
||||
->middleware([
|
||||
'permission:'.Permission::RAW_MATERIALS_UPDATE->value,
|
||||
'no_pending_owner_verification:rawMaterial',
|
||||
])
|
||||
->middleware('permission:'.Permission::RAW_MATERIALS_UPDATE->value)
|
||||
->name('edit');
|
||||
|
||||
Route::put('{rawMaterial}', [RawMaterialController::class, 'update'])
|
||||
->middleware([
|
||||
'permission:'.Permission::RAW_MATERIALS_UPDATE->value,
|
||||
'no_pending_owner_verification:rawMaterial',
|
||||
])
|
||||
->middleware('permission:'.Permission::RAW_MATERIALS_UPDATE->value)
|
||||
->name('update');
|
||||
|
||||
Route::patch('{rawMaterial}/toggle-status', [RawMaterialController::class, 'toggleStatus'])
|
||||
->middleware([
|
||||
'permission:'.Permission::RAW_MATERIALS_TOGGLE_STATUS->value,
|
||||
'no_pending_owner_verification:rawMaterial',
|
||||
])
|
||||
->middleware('permission:'.Permission::RAW_MATERIALS_TOGGLE_STATUS->value)
|
||||
->name('toggle_status');
|
||||
|
||||
Route::delete('{rawMaterial}', [RawMaterialController::class, 'destroy'])
|
||||
->middleware([
|
||||
'permission:'.Permission::RAW_MATERIALS_DELETE->value,
|
||||
'no_pending_owner_verification:rawMaterial',
|
||||
])
|
||||
->middleware('permission:'.Permission::RAW_MATERIALS_DELETE->value)
|
||||
->name('destroy');
|
||||
|
||||
Route::get('{rawMaterial}', [RawMaterialController::class, 'show'])->name('show');
|
||||
|
||||
@ -228,7 +228,7 @@ function createRawMaterialVerifierUser(): User
|
||||
// ─── Store ────────────────────────────────────────────────
|
||||
|
||||
describe('Raw Material Store', function () {
|
||||
test('authenticated user with permission can submit raw material creation request', function () {
|
||||
test('authenticated user with permission can create raw material', function () {
|
||||
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
|
||||
|
||||
$this->actingAs($user)
|
||||
@ -244,13 +244,7 @@ function createRawMaterialVerifierUser(): User
|
||||
$this->assertDatabaseHas('raw_materials', [
|
||||
'name' => 'Kain Sutra',
|
||||
'unit' => RawMaterialUnit::METER->value,
|
||||
'is_active' => false,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('owner_verification_requests', [
|
||||
'subject_type' => RawMaterial::class,
|
||||
'action' => OwnerVerificationAction::CREATE->value,
|
||||
'status' => OwnerVerificationStatus::PENDING->value,
|
||||
'is_active' => true,
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user