feat: enhance cutting status management by adding verified status transition and refining user permissions for verification actions
This commit is contained in:
parent
573e81193a
commit
aeb7d1f292
@ -46,7 +46,7 @@ public function canTransitionTo(self $status): bool
|
|||||||
{
|
{
|
||||||
return match ($this) {
|
return match ($this) {
|
||||||
self::IN_PROGRESS => $status === self::COMPLETED,
|
self::IN_PROGRESS => $status === self::COMPLETED,
|
||||||
self::COMPLETED => in_array($status, [self::PENDING_VERIFICATION, self::REJECTED, self::IN_PROGRESS], true),
|
self::COMPLETED => in_array($status, [self::PENDING_VERIFICATION, self::REJECTED, self::IN_PROGRESS, self::VERIFIED], true),
|
||||||
self::PENDING_VERIFICATION => in_array($status, [self::VERIFIED, self::REJECTED, self::COMPLETED], true),
|
self::PENDING_VERIFICATION => in_array($status, [self::VERIFIED, self::REJECTED, self::COMPLETED], true),
|
||||||
self::REJECTED => $status === self::IN_PROGRESS,
|
self::REJECTED => $status === self::IN_PROGRESS,
|
||||||
default => false,
|
default => false,
|
||||||
@ -80,7 +80,15 @@ public function availableActions(): array
|
|||||||
'icon_only' => false,
|
'icon_only' => false,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
self::COMPLETED => [],
|
self::COMPLETED => [
|
||||||
|
[
|
||||||
|
'status' => self::VERIFIED->value,
|
||||||
|
'label' => 'Verifikasi',
|
||||||
|
'destructive' => false,
|
||||||
|
'permission' => Permission::CUTTINGS_VERIFY->value,
|
||||||
|
'icon_only' => false,
|
||||||
|
],
|
||||||
|
],
|
||||||
self::PENDING_VERIFICATION => [],
|
self::PENDING_VERIFICATION => [],
|
||||||
self::REJECTED => [
|
self::REJECTED => [
|
||||||
[
|
[
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
use App\Enums\CuttingStatus;
|
use App\Enums\CuttingStatus;
|
||||||
use App\Enums\Permission;
|
use App\Enums\Permission;
|
||||||
use App\Enums\PriceType;
|
use App\Enums\PriceType;
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Models\Cutting;
|
use App\Models\Cutting;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
@ -83,6 +84,14 @@ public function withValidator(Validator $validator): void
|
|||||||
$validator->errors()->add('status', 'Status cutting tidak dapat diubah.');
|
$validator->errors()->add('status', 'Status cutting tidak dapat diubah.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only owner/developer can verify directly from COMPLETED status
|
||||||
|
if ($cutting->status === CuttingStatus::COMPLETED && $status === CuttingStatus::VERIFIED) {
|
||||||
|
$user = $this->user();
|
||||||
|
if (! $user || ! $user->hasRole([Role::OWNER->value, Role::DEVELOPER->value])) {
|
||||||
|
$validator->errors()->add('status', 'Hanya owner yang dapat langsung memverifikasi cutting.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($status === CuttingStatus::REJECTED && trim((string) $this->input('reason')) === '') {
|
if ($status === CuttingStatus::REJECTED && trim((string) $this->input('reason')) === '') {
|
||||||
$validator->errors()->add('reason', 'Alasan penolakan wajib diisi.');
|
$validator->errors()->add('reason', 'Alasan penolakan wajib diisi.');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Services\Manage;
|
namespace App\Services\Manage;
|
||||||
|
|
||||||
use App\Enums\CuttingStatus;
|
use App\Enums\CuttingStatus;
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Models\Cutting;
|
use App\Models\Cutting;
|
||||||
use App\Models\CuttingMaterial;
|
use App\Models\CuttingMaterial;
|
||||||
use App\Models\CuttingResult;
|
use App\Models\CuttingResult;
|
||||||
@ -58,12 +59,7 @@ public function paginateForIndex(array $tableQuery, User $user): LengthAwarePagi
|
|||||||
->paginate(25)
|
->paginate(25)
|
||||||
->withQueryString()
|
->withQueryString()
|
||||||
->through(function (Cutting $cutting) use ($user) {
|
->through(function (Cutting $cutting) use ($user) {
|
||||||
$actions = collect($cutting->status->availableActions())
|
$cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user));
|
||||||
->filter(fn (array $action) => $user->can($action['permission']))
|
|
||||||
->values()
|
|
||||||
->all();
|
|
||||||
|
|
||||||
$cutting->setAttribute('available_actions', $actions);
|
|
||||||
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
||||||
$this->appendCostPreview($cutting);
|
$this->appendCostPreview($cutting);
|
||||||
|
|
||||||
@ -85,12 +81,7 @@ public function getInProgressCuttings(User $user): Collection
|
|||||||
->latest()
|
->latest()
|
||||||
->get()
|
->get()
|
||||||
->each(function (Cutting $cutting) use ($user): void {
|
->each(function (Cutting $cutting) use ($user): void {
|
||||||
$actions = collect($cutting->status->availableActions())
|
$cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user));
|
||||||
->filter(fn (array $action) => $user->can($action['permission']))
|
|
||||||
->values()
|
|
||||||
->all();
|
|
||||||
|
|
||||||
$cutting->setAttribute('available_actions', $actions);
|
|
||||||
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
||||||
$this->appendCostPreview($cutting);
|
$this->appendCostPreview($cutting);
|
||||||
});
|
});
|
||||||
@ -110,12 +101,7 @@ public function getCompletedCuttings(User $user): Collection
|
|||||||
->latest()
|
->latest()
|
||||||
->get()
|
->get()
|
||||||
->each(function (Cutting $cutting) use ($user): void {
|
->each(function (Cutting $cutting) use ($user): void {
|
||||||
$actions = collect($cutting->status->availableActions())
|
$cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user));
|
||||||
->filter(fn (array $action) => $user->can($action['permission']))
|
|
||||||
->values()
|
|
||||||
->all();
|
|
||||||
|
|
||||||
$cutting->setAttribute('available_actions', $actions);
|
|
||||||
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
||||||
$this->appendCostPreview($cutting);
|
$this->appendCostPreview($cutting);
|
||||||
});
|
});
|
||||||
@ -891,6 +877,25 @@ private function formatMaterialUsageSummary(Cutting $cutting): string
|
|||||||
->join(', ');
|
->join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<array{status: string, label: string, destructive: bool, permission: string, icon_only: bool}>
|
||||||
|
*/
|
||||||
|
private function filterActionsForUser(Cutting $cutting, User $user): array
|
||||||
|
{
|
||||||
|
return collect($cutting->status->availableActions())
|
||||||
|
->filter(fn (array $action) => $user->can($action['permission']))
|
||||||
|
->filter(function (array $action) use ($cutting, $user): bool {
|
||||||
|
// Only owner/developer can verify directly from COMPLETED status
|
||||||
|
if ($cutting->status === CuttingStatus::COMPLETED && $action['status'] === CuttingStatus::VERIFIED->value) {
|
||||||
|
return $user->hasRole([Role::OWNER->value, Role::DEVELOPER->value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
}
|
||||||
|
|
||||||
private function appendCostPreview(Cutting $cutting): void
|
private function appendCostPreview(Cutting $cutting): void
|
||||||
{
|
{
|
||||||
$cutting->setAttribute('total_result_pieces', (int) $cutting->results->sum('cutting_result'));
|
$cutting->setAttribute('total_result_pieces', (int) $cutting->results->sum('cutting_result'));
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Enums\OwnerVerificationAction;
|
use App\Enums\OwnerVerificationAction;
|
||||||
use App\Enums\OwnerVerificationStatus;
|
use App\Enums\OwnerVerificationStatus;
|
||||||
|
use App\Enums\Permission;
|
||||||
use App\Models\OwnerVerificationRequest;
|
use App\Models\OwnerVerificationRequest;
|
||||||
use App\Models\Purchase;
|
use App\Models\Purchase;
|
||||||
use App\Models\PurchaseItem;
|
use App\Models\PurchaseItem;
|
||||||
@ -201,8 +202,10 @@ public function removeDraftItem(User $user, RawMaterialPrice $rawMaterialPrice):
|
|||||||
|
|
||||||
public function create(array $validated, User $user): Purchase
|
public function create(array $validated, User $user): Purchase
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$purchase = DB::transaction(function () use ($validated, $user): Purchase {
|
$purchase = DB::transaction(function () use ($validated, $user, $isOwner): Purchase {
|
||||||
|
|
||||||
$draftItems = $this->draftItemsQuery($user)
|
$draftItems = $this->draftItemsQuery($user)
|
||||||
->lockForUpdate()
|
->lockForUpdate()
|
||||||
@ -239,6 +242,11 @@ public function create(array $validated, User $user): Purchase
|
|||||||
|
|
||||||
$purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);
|
$purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);
|
||||||
|
|
||||||
|
if ($isOwner) {
|
||||||
|
foreach ($purchase->items as $item) {
|
||||||
|
$this->incrementStock($item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
OwnerVerificationRequest::create([
|
OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::CREATE,
|
'action' => OwnerVerificationAction::CREATE,
|
||||||
'status' => OwnerVerificationStatus::PENDING,
|
'status' => OwnerVerificationStatus::PENDING,
|
||||||
@ -250,13 +258,14 @@ public function create(array $validated, User $user): Purchase
|
|||||||
'new' => $this->snapshotPurchase($purchase),
|
'new' => $this->snapshotPurchase($purchase),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return $purchase;
|
return $purchase;
|
||||||
});
|
});
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::error('Gagal mengajukan pembelian: '.$e->getMessage(), [
|
Log::error('Gagal membuat pembelian: '.$e->getMessage(), [
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -265,6 +274,7 @@ public function create(array $validated, User $user): Purchase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $isOwner) {
|
||||||
$this->notifyForPendingRequest(
|
$this->notifyForPendingRequest(
|
||||||
$user,
|
$user,
|
||||||
'Tambah Belanja',
|
'Tambah Belanja',
|
||||||
@ -272,16 +282,26 @@ public function create(array $validated, User $user): Purchase
|
|||||||
route('admin.manage.purchases.index', ['search' => $purchase->supplier->name]),
|
route('admin.manage.purchases.index', ['search' => $purchase->supplier->name]),
|
||||||
$purchase->supplier->name,
|
$purchase->supplier->name,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return $purchase;
|
return $purchase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Purchase $purchase, array $validated, User $user): void
|
public function update(Purchase $purchase, array $validated, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
$purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);
|
$purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB::transaction(function () use ($purchase, $validated, $user): void {
|
DB::transaction(function () use ($purchase, $validated, $user, $isOwner): void {
|
||||||
|
if ($isOwner) {
|
||||||
|
$payload = $this->buildPayloadFromValidated($validated);
|
||||||
|
$this->applyPayloadToPurchase($purchase, $payload);
|
||||||
|
|
||||||
|
if (($validated['photos'] ?? null) !== null || ($validated['remove_media_ids'] ?? []) !== []) {
|
||||||
|
$this->syncPhotos($purchase, $validated);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$verificationRequest = OwnerVerificationRequest::create([
|
$verificationRequest = OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::UPDATE,
|
'action' => OwnerVerificationAction::UPDATE,
|
||||||
'status' => OwnerVerificationStatus::PENDING,
|
'status' => OwnerVerificationStatus::PENDING,
|
||||||
@ -297,11 +317,12 @@ public function update(Purchase $purchase, array $validated, User $user): void
|
|||||||
if (($validated['photos'] ?? null) !== null || ($validated['remove_media_ids'] ?? []) !== []) {
|
if (($validated['photos'] ?? null) !== null || ($validated['remove_media_ids'] ?? []) !== []) {
|
||||||
$this->syncRequestPhotos($verificationRequest, $validated);
|
$this->syncRequestPhotos($verificationRequest, $validated);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::error('Gagal mengajukan perubahan belanja: '.$e->getMessage(), [
|
Log::error('Gagal memperbarui pembelian: '.$e->getMessage(), [
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -310,6 +331,7 @@ public function update(Purchase $purchase, array $validated, User $user): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $isOwner) {
|
||||||
$purchase->load('supplier');
|
$purchase->load('supplier');
|
||||||
|
|
||||||
$this->notifyForPendingRequest(
|
$this->notifyForPendingRequest(
|
||||||
@ -320,9 +342,18 @@ public function update(Purchase $purchase, array $validated, User $user): void
|
|||||||
$purchase->supplier->name,
|
$purchase->supplier->name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function delete(Purchase $purchase, User $user): void
|
public function delete(Purchase $purchase, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
|
if ($isOwner) {
|
||||||
|
$this->executeDelete($purchase);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);
|
$purchase->load(['supplier', 'items.rawMaterialPrice.rawMaterial:id,name']);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Enums\OwnerVerificationAction;
|
use App\Enums\OwnerVerificationAction;
|
||||||
use App\Enums\OwnerVerificationStatus;
|
use App\Enums\OwnerVerificationStatus;
|
||||||
|
use App\Enums\Permission;
|
||||||
use App\Models\OwnerVerificationRequest;
|
use App\Models\OwnerVerificationRequest;
|
||||||
use App\Models\ProductVariant;
|
use App\Models\ProductVariant;
|
||||||
use App\Models\StockRetailHistory;
|
use App\Models\StockRetailHistory;
|
||||||
@ -19,7 +20,7 @@ public function __construct(
|
|||||||
private readonly PushNotificationService $pushNotificationService,
|
private readonly PushNotificationService $pushNotificationService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function transfer(int $variantId, int $quantity, User $user, ?string $notes = null): OwnerVerificationRequest
|
public function transfer(int $variantId, int $quantity, User $user, ?string $notes = null): ?OwnerVerificationRequest
|
||||||
{
|
{
|
||||||
if ($quantity <= 0) {
|
if ($quantity <= 0) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
@ -35,6 +36,14 @@ public function transfer(int $variantId, int $quantity, User $user, ?string $not
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
|
if ($isOwner) {
|
||||||
|
$this->executeTransfer($variant, $quantity, $user, $notes);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$existingPending = OwnerVerificationRequest::query()
|
$existingPending = OwnerVerificationRequest::query()
|
||||||
->where('subject_type', ProductVariant::class)
|
->where('subject_type', ProductVariant::class)
|
||||||
->where('subject_id', $variant->id)
|
->where('subject_id', $variant->id)
|
||||||
@ -111,9 +120,20 @@ public function applyStockRetailTransfer(OwnerVerificationRequest $request): voi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($request, $quantity, $newData): void {
|
$variant = ProductVariant::query()->find($request->subject_id);
|
||||||
|
|
||||||
|
if (! $variant) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->executeTransfer($variant, $quantity, $request->submittedBy, $newData['notes'] ?? null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function executeTransfer(ProductVariant $variant, int $quantity, User $user, ?string $notes = null): void
|
||||||
|
{
|
||||||
|
DB::transaction(function () use ($variant, $quantity, $user, $notes): void {
|
||||||
$variant = ProductVariant::query()
|
$variant = ProductVariant::query()
|
||||||
->whereKey($request->subject_id)
|
->whereKey($variant->id)
|
||||||
->lockForUpdate()
|
->lockForUpdate()
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
|
|
||||||
@ -125,13 +145,13 @@ public function applyStockRetailTransfer(OwnerVerificationRequest $request): voi
|
|||||||
|
|
||||||
StockRetailHistory::create([
|
StockRetailHistory::create([
|
||||||
'product_variant_id' => $variant->id,
|
'product_variant_id' => $variant->id,
|
||||||
'user_id' => $request->submitted_by_id,
|
'user_id' => $user->id,
|
||||||
'quantity' => $quantity,
|
'quantity' => $quantity,
|
||||||
'stock_before' => $stockBefore,
|
'stock_before' => $stockBefore,
|
||||||
'stock_retail_before' => $stockRetailBefore,
|
'stock_retail_before' => $stockRetailBefore,
|
||||||
'stock_after' => $stockBefore - $quantity,
|
'stock_after' => $stockBefore - $quantity,
|
||||||
'stock_retail_after' => $stockRetailBefore + $quantity,
|
'stock_retail_after' => $stockRetailBefore + $quantity,
|
||||||
'notes' => $newData['notes'] ?? null,
|
'notes' => $notes,
|
||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Enums\OwnerVerificationAction;
|
use App\Enums\OwnerVerificationAction;
|
||||||
use App\Enums\OwnerVerificationStatus;
|
use App\Enums\OwnerVerificationStatus;
|
||||||
|
use App\Enums\Permission;
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
use App\Models\OwnerVerificationRequest;
|
use App\Models\OwnerVerificationRequest;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
@ -115,12 +116,14 @@ public function findForEdit(Product $product): Product
|
|||||||
|
|
||||||
public function create(array $validated, User $user): void
|
public function create(array $validated, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB::transaction(function () use ($validated, $user): void {
|
DB::transaction(function () use ($validated, $user, $isOwner): void {
|
||||||
$product = Product::create([
|
$product = Product::create([
|
||||||
'name' => $validated['name'],
|
'name' => $validated['name'],
|
||||||
'description' => $validated['description'] ?? null,
|
'description' => $validated['description'] ?? null,
|
||||||
'is_active' => false,
|
'is_active' => $isOwner,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$product->categories()->sync($validated['category_ids'] ?? []);
|
$product->categories()->sync($validated['category_ids'] ?? []);
|
||||||
@ -135,6 +138,7 @@ public function create(array $validated, User $user): void
|
|||||||
$this->syncVariantImages($variant, $variantData, $index);
|
$this->syncVariantImages($variant, $variantData, $index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $isOwner) {
|
||||||
OwnerVerificationRequest::create([
|
OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::CREATE,
|
'action' => OwnerVerificationAction::CREATE,
|
||||||
'status' => OwnerVerificationStatus::PENDING,
|
'status' => OwnerVerificationStatus::PENDING,
|
||||||
@ -146,11 +150,12 @@ public function create(array $validated, User $user): void
|
|||||||
'new' => $this->snapshotProduct($product->fresh(['categories', 'variants'])),
|
'new' => $this->snapshotProduct($product->fresh(['categories', 'variants'])),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::error('Gagal mengajukan pembuatan produk: '.$e->getMessage(), [
|
Log::error('Gagal membuat produk: '.$e->getMessage(), [
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -159,6 +164,7 @@ public function create(array $validated, User $user): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $isOwner) {
|
||||||
$this->notifyForPendingRequest(
|
$this->notifyForPendingRequest(
|
||||||
$user,
|
$user,
|
||||||
'Tambah Produk',
|
'Tambah Produk',
|
||||||
@ -167,11 +173,34 @@ public function create(array $validated, User $user): void
|
|||||||
$validated['name'],
|
$validated['name'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function update(Product $product, array $validated, User $user): void
|
public function update(Product $product, array $validated, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB::transaction(function () use ($validated, $product, $user): void {
|
DB::transaction(function () use ($validated, $product, $user, $isOwner): void {
|
||||||
|
if ($isOwner) {
|
||||||
|
$payload = $this->enrichPayload($this->buildPayloadFromValidated($validated));
|
||||||
|
$this->applyPayloadToProduct($product, $payload);
|
||||||
|
|
||||||
|
foreach ($validated['variants'] as $index => $variantData) {
|
||||||
|
if (! empty($variantData['id'])) {
|
||||||
|
$variant = $product->variants()->find($variantData['id']);
|
||||||
|
if ($variant) {
|
||||||
|
$this->syncVariantImages($variant, $variantData, $index);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$variant = $product->variants()->create([
|
||||||
|
'name' => $variantData['name'],
|
||||||
|
'stock' => $variantData['stock'],
|
||||||
|
'stock_retail' => $variantData['stock_retail'],
|
||||||
|
]);
|
||||||
|
$this->syncVariantImages($variant, $variantData, $index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$verificationRequest = OwnerVerificationRequest::create([
|
$verificationRequest = OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::UPDATE,
|
'action' => OwnerVerificationAction::UPDATE,
|
||||||
'status' => OwnerVerificationStatus::PENDING,
|
'status' => OwnerVerificationStatus::PENDING,
|
||||||
@ -188,11 +217,12 @@ public function update(Product $product, array $validated, User $user): void
|
|||||||
$isNewVariant = empty($variantData['id']);
|
$isNewVariant = empty($variantData['id']);
|
||||||
$this->syncRequestVariantImages($verificationRequest, $variantData, $index, required: $isNewVariant);
|
$this->syncRequestVariantImages($verificationRequest, $variantData, $index, required: $isNewVariant);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::error('Gagal mengajukan perubahan produk: '.$e->getMessage(), [
|
Log::error('Gagal memperbarui produk: '.$e->getMessage(), [
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -201,6 +231,7 @@ public function update(Product $product, array $validated, User $user): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $isOwner) {
|
||||||
$this->notifyForPendingRequest(
|
$this->notifyForPendingRequest(
|
||||||
$user,
|
$user,
|
||||||
'Ubah Produk',
|
'Ubah Produk',
|
||||||
@ -209,9 +240,18 @@ public function update(Product $product, array $validated, User $user): void
|
|||||||
$product->name,
|
$product->name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function delete(Product $product, User $user): void
|
public function delete(Product $product, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
|
if ($isOwner) {
|
||||||
|
$this->applyDeleteSubject($product);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OwnerVerificationRequest::create([
|
OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::DELETE,
|
'action' => OwnerVerificationAction::DELETE,
|
||||||
@ -245,6 +285,16 @@ public function delete(Product $product, User $user): void
|
|||||||
|
|
||||||
public function toggleStatus(Product $product, array $validated, User $user): void
|
public function toggleStatus(Product $product, array $validated, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
|
if ($isOwner) {
|
||||||
|
$product->update([
|
||||||
|
'is_active' => (bool) $validated['is_active'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OwnerVerificationRequest::create([
|
OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::TOGGLE_STATUS,
|
'action' => OwnerVerificationAction::TOGGLE_STATUS,
|
||||||
@ -418,6 +468,11 @@ public function applyDelete(OwnerVerificationRequest $verificationRequest): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->applyDeleteSubject($product);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyDeleteSubject(Product $product): void
|
||||||
|
{
|
||||||
DB::transaction(function () use ($product): void {
|
DB::transaction(function () use ($product): void {
|
||||||
$product->variants()->each(function (ProductVariant $variant): void {
|
$product->variants()->each(function (ProductVariant $variant): void {
|
||||||
$variant->clearMediaCollection('images');
|
$variant->clearMediaCollection('images');
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Enums\OwnerVerificationAction;
|
use App\Enums\OwnerVerificationAction;
|
||||||
use App\Enums\OwnerVerificationStatus;
|
use App\Enums\OwnerVerificationStatus;
|
||||||
|
use App\Enums\Permission;
|
||||||
use App\Enums\RawMaterialUnit;
|
use App\Enums\RawMaterialUnit;
|
||||||
use App\Models\OwnerVerificationRequest;
|
use App\Models\OwnerVerificationRequest;
|
||||||
use App\Models\RawMaterial;
|
use App\Models\RawMaterial;
|
||||||
@ -109,18 +110,21 @@ public function findForEdit(RawMaterial $rawMaterial): RawMaterial
|
|||||||
|
|
||||||
public function create(array $validated, User $user): void
|
public function create(array $validated, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB::transaction(function () use ($validated, $user): void {
|
DB::transaction(function () use ($validated, $user, $isOwner): void {
|
||||||
$rawMaterial = RawMaterial::create([
|
$rawMaterial = RawMaterial::create([
|
||||||
'name' => $validated['name'],
|
'name' => $validated['name'],
|
||||||
'unit' => $validated['unit'],
|
'unit' => $validated['unit'],
|
||||||
'is_active' => false,
|
'is_active' => $isOwner,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
foreach ($validated['prices'] as $index => $priceData) {
|
foreach ($validated['prices'] as $index => $priceData) {
|
||||||
$this->createPrice($rawMaterial, $priceData, $index);
|
$this->createPrice($rawMaterial, $priceData, $index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $isOwner) {
|
||||||
OwnerVerificationRequest::create([
|
OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::CREATE,
|
'action' => OwnerVerificationAction::CREATE,
|
||||||
'status' => OwnerVerificationStatus::PENDING,
|
'status' => OwnerVerificationStatus::PENDING,
|
||||||
@ -132,11 +136,12 @@ public function create(array $validated, User $user): void
|
|||||||
'new' => $this->snapshotRawMaterial($rawMaterial->fresh(['prices'])),
|
'new' => $this->snapshotRawMaterial($rawMaterial->fresh(['prices'])),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::error('Gagal mengajukan pembuatan bahan baku: '.$e->getMessage(), [
|
Log::error('Gagal membuat bahan baku: '.$e->getMessage(), [
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -145,6 +150,7 @@ public function create(array $validated, User $user): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $isOwner) {
|
||||||
$this->notifyForPendingRequest(
|
$this->notifyForPendingRequest(
|
||||||
$user,
|
$user,
|
||||||
'Tambah Bahan Baku',
|
'Tambah Bahan Baku',
|
||||||
@ -153,11 +159,29 @@ public function create(array $validated, User $user): void
|
|||||||
$validated['name'],
|
$validated['name'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function update(RawMaterial $rawMaterial, array $validated, User $user): void
|
public function update(RawMaterial $rawMaterial, array $validated, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DB::transaction(function () use ($validated, $rawMaterial, $user): void {
|
DB::transaction(function () use ($validated, $rawMaterial, $user, $isOwner): void {
|
||||||
|
if ($isOwner) {
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$verificationRequest = OwnerVerificationRequest::create([
|
$verificationRequest = OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::UPDATE,
|
'action' => OwnerVerificationAction::UPDATE,
|
||||||
'status' => OwnerVerificationStatus::PENDING,
|
'status' => OwnerVerificationStatus::PENDING,
|
||||||
@ -174,11 +198,12 @@ public function update(RawMaterial $rawMaterial, array $validated, User $user):
|
|||||||
$isNewPrice = empty($priceData['id']);
|
$isNewPrice = empty($priceData['id']);
|
||||||
$this->syncRequestPriceImages($verificationRequest, $priceData, $index, required: $isNewPrice);
|
$this->syncRequestPriceImages($verificationRequest, $priceData, $index, required: $isNewPrice);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (ValidationException $e) {
|
} catch (ValidationException $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::error('Gagal mengajukan perubahan bahan baku: '.$e->getMessage(), [
|
Log::error('Gagal memperbarui bahan baku: '.$e->getMessage(), [
|
||||||
'trace' => $e->getTraceAsString(),
|
'trace' => $e->getTraceAsString(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -187,6 +212,7 @@ public function update(RawMaterial $rawMaterial, array $validated, User $user):
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! $isOwner) {
|
||||||
$this->notifyForPendingRequest(
|
$this->notifyForPendingRequest(
|
||||||
$user,
|
$user,
|
||||||
'Ubah Bahan Baku',
|
'Ubah Bahan Baku',
|
||||||
@ -195,9 +221,18 @@ public function update(RawMaterial $rawMaterial, array $validated, User $user):
|
|||||||
$rawMaterial->name,
|
$rawMaterial->name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function delete(RawMaterial $rawMaterial, User $user): void
|
public function delete(RawMaterial $rawMaterial, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
|
if ($isOwner) {
|
||||||
|
$this->applyDeleteSubject($rawMaterial);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OwnerVerificationRequest::create([
|
OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::DELETE,
|
'action' => OwnerVerificationAction::DELETE,
|
||||||
@ -231,6 +266,16 @@ public function delete(RawMaterial $rawMaterial, User $user): void
|
|||||||
|
|
||||||
public function toggleStatus(RawMaterial $rawMaterial, array $validated, User $user): void
|
public function toggleStatus(RawMaterial $rawMaterial, array $validated, User $user): void
|
||||||
{
|
{
|
||||||
|
$isOwner = $user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value);
|
||||||
|
|
||||||
|
if ($isOwner) {
|
||||||
|
$rawMaterial->update([
|
||||||
|
'is_active' => (bool) $validated['is_active'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OwnerVerificationRequest::create([
|
OwnerVerificationRequest::create([
|
||||||
'action' => OwnerVerificationAction::TOGGLE_STATUS,
|
'action' => OwnerVerificationAction::TOGGLE_STATUS,
|
||||||
@ -366,6 +411,11 @@ public function applyDelete(OwnerVerificationRequest $verificationRequest): void
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->applyDeleteSubject($rawMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyDeleteSubject(RawMaterial $rawMaterial): void
|
||||||
|
{
|
||||||
DB::transaction(function () use ($rawMaterial): void {
|
DB::transaction(function () use ($rawMaterial): void {
|
||||||
$rawMaterial->prices()->each(function (RawMaterialPrice $price): void {
|
$rawMaterial->prices()->each(function (RawMaterialPrice $price): void {
|
||||||
$price->clearMediaCollection('images');
|
$price->clearMediaCollection('images');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user