feat: implement owner verification actions in various management tables and enhance request handling in the OwnerVerificationRowActions component
This commit is contained in:
parent
d5ca41a764
commit
5cffe43a07
@ -63,7 +63,9 @@ public function approveCutting(ApproveVerificationRequest $request, Cutting $cut
|
|||||||
|
|
||||||
$this->flashSuccess('Verifikasi cutting berhasil disetujui. Stok produk telah ditambahkan ke toko.');
|
$this->flashSuccess('Verifikasi cutting berhasil disetujui. Stok produk telah ditambahkan ke toko.');
|
||||||
|
|
||||||
return redirect()->route('admin.manage.owner_verifications.index');
|
$fallback = route('admin.manage.owner_verifications.index');
|
||||||
|
|
||||||
|
return back(302, [], $fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rejectCutting(RejectVerificationRequest $request, Cutting $cutting): RedirectResponse
|
public function rejectCutting(RejectVerificationRequest $request, Cutting $cutting): RedirectResponse
|
||||||
@ -76,7 +78,9 @@ public function rejectCutting(RejectVerificationRequest $request, Cutting $cutti
|
|||||||
|
|
||||||
$this->flashSuccess('Verifikasi cutting berhasil ditolak.');
|
$this->flashSuccess('Verifikasi cutting berhasil ditolak.');
|
||||||
|
|
||||||
return redirect()->route('admin.manage.owner_verifications.index');
|
$fallback = route('admin.manage.owner_verifications.index');
|
||||||
|
|
||||||
|
return back(302, [], $fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function approveRequest(
|
public function approveRequest(
|
||||||
@ -91,7 +95,9 @@ public function approveRequest(
|
|||||||
|
|
||||||
$this->flashSuccess('Verifikasi berhasil disetujui.');
|
$this->flashSuccess('Verifikasi berhasil disetujui.');
|
||||||
|
|
||||||
return redirect()->route('admin.manage.owner_verifications.index');
|
$fallback = route('admin.manage.owner_verifications.index');
|
||||||
|
|
||||||
|
return back(302, [], $fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rejectRequest(
|
public function rejectRequest(
|
||||||
@ -106,6 +112,8 @@ public function rejectRequest(
|
|||||||
|
|
||||||
$this->flashSuccess('Verifikasi berhasil ditolak.');
|
$this->flashSuccess('Verifikasi berhasil ditolak.');
|
||||||
|
|
||||||
return redirect()->route('admin.manage.owner_verifications.index');
|
$fallback = route('admin.manage.owner_verifications.index');
|
||||||
|
|
||||||
|
return back(302, [], $fallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,6 +70,7 @@ public function paginateForIndex(array $tableQuery): LengthAwarePaginator
|
|||||||
$pendingRequest = $purchase->pendingOwnerVerificationRequest;
|
$pendingRequest = $purchase->pendingOwnerVerificationRequest;
|
||||||
|
|
||||||
$purchase->setAttribute('has_pending_request', $pendingRequest !== null);
|
$purchase->setAttribute('has_pending_request', $pendingRequest !== null);
|
||||||
|
$purchase->setAttribute('pending_request_id', $pendingRequest?->id);
|
||||||
$purchase->setAttribute('pending_request_action', $pendingRequest?->action->value);
|
$purchase->setAttribute('pending_request_action', $pendingRequest?->action->value);
|
||||||
$purchase->setAttribute('pending_request_action_label', $pendingRequest?->action->label());
|
$purchase->setAttribute('pending_request_action_label', $pendingRequest?->action->label());
|
||||||
|
|
||||||
|
|||||||
@ -77,6 +77,7 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $ca
|
|||||||
$pendingRequest = $product->pendingOwnerVerificationRequest;
|
$pendingRequest = $product->pendingOwnerVerificationRequest;
|
||||||
|
|
||||||
$product->setAttribute('has_pending_request', $pendingRequest !== null);
|
$product->setAttribute('has_pending_request', $pendingRequest !== null);
|
||||||
|
$product->setAttribute('pending_request_id', $pendingRequest?->id);
|
||||||
$product->setAttribute('pending_request_action', $pendingRequest?->action->value);
|
$product->setAttribute('pending_request_action', $pendingRequest?->action->value);
|
||||||
$product->setAttribute('pending_request_action_label', $pendingRequest?->action->label());
|
$product->setAttribute('pending_request_action_label', $pendingRequest?->action->label());
|
||||||
$product->setAttribute(
|
$product->setAttribute(
|
||||||
|
|||||||
@ -85,6 +85,7 @@ public function paginateForIndex(array $tableQuery, string $isActive, string $st
|
|||||||
$pendingRequest = $rawMaterial->pendingOwnerVerificationRequest;
|
$pendingRequest = $rawMaterial->pendingOwnerVerificationRequest;
|
||||||
|
|
||||||
$rawMaterial->setAttribute('has_pending_request', $pendingRequest !== null);
|
$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', $pendingRequest?->action->value);
|
||||||
$rawMaterial->setAttribute('pending_request_action_label', $pendingRequest?->action->label());
|
$rawMaterial->setAttribute('pending_request_action_label', $pendingRequest?->action->label());
|
||||||
$rawMaterial->setAttribute(
|
$rawMaterial->setAttribute(
|
||||||
|
|||||||
@ -0,0 +1,135 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from '@inertiajs/vue3';
|
||||||
|
import { X } from '@lucide/vue';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { toast } from 'vue-sonner';
|
||||||
|
import { RowApproveAction, RowRejectAction } from '@/components/button';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
import {
|
||||||
|
Field,
|
||||||
|
FieldError,
|
||||||
|
FieldLabel,
|
||||||
|
} from '@/components/ui/field';
|
||||||
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
|
import { useCan } from '@/composables/useCan';
|
||||||
|
import { approve, reject, approve_request, reject_request } from '@/routes/admin/manage/owner_verifications';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
type: 'request' | 'cutting';
|
||||||
|
id: number;
|
||||||
|
title?: string;
|
||||||
|
subjectLabel?: string;
|
||||||
|
actionLabel?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { can } = useCan();
|
||||||
|
|
||||||
|
const rejectDialogOpen = ref(false);
|
||||||
|
|
||||||
|
const approveForm = useForm({});
|
||||||
|
const rejectForm = useForm({
|
||||||
|
reason: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const approveUrl = computed(() => (
|
||||||
|
props.type === 'cutting'
|
||||||
|
? approve.url(props.id)
|
||||||
|
: approve_request.url(props.id)
|
||||||
|
));
|
||||||
|
|
||||||
|
const rejectUrl = computed(() => (
|
||||||
|
props.type === 'cutting'
|
||||||
|
? reject.url(props.id)
|
||||||
|
: reject_request.url(props.id)
|
||||||
|
));
|
||||||
|
|
||||||
|
const canApprove = computed(() => can('owner_verifications.verify'));
|
||||||
|
const canReject = computed(() => can('owner_verifications.reject'));
|
||||||
|
|
||||||
|
function submitApprove() {
|
||||||
|
approveForm
|
||||||
|
.post(approveUrl.value, {
|
||||||
|
preserveScroll: true,
|
||||||
|
onError: (errors: Record<string, string>) => {
|
||||||
|
if (errors.system) {
|
||||||
|
toast.error(errors.system);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitReject() {
|
||||||
|
rejectForm
|
||||||
|
.post(rejectUrl.value, {
|
||||||
|
preserveScroll: true,
|
||||||
|
onSuccess: () => {
|
||||||
|
rejectDialogOpen.value = false;
|
||||||
|
rejectForm.reset();
|
||||||
|
},
|
||||||
|
onError: (errors: Record<string, string>) => {
|
||||||
|
if (errors.system) {
|
||||||
|
toast.error(errors.system);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<template v-if="canApprove">
|
||||||
|
<RowApproveAction size="sm" tooltip="Setujui" :disabled="approveForm.processing" @click="submitApprove" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="canReject">
|
||||||
|
<RowRejectAction size="sm" tooltip="Tolak" :disabled="rejectForm.processing" @click="rejectDialogOpen = true" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<Dialog v-model:open="rejectDialogOpen">
|
||||||
|
<DialogContent class="sm:max-w-lg">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Tolak Verifikasi</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div v-if="subjectLabel || title || actionLabel" class="rounded-md border p-3 text-xs space-y-2">
|
||||||
|
<div v-if="subjectLabel">
|
||||||
|
<span class="text-muted-foreground">Modul:</span>
|
||||||
|
<span class="ml-1 font-medium">{{ subjectLabel }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="title">
|
||||||
|
<span class="text-muted-foreground">Item:</span>
|
||||||
|
<span class="ml-1 font-medium">{{ title }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="actionLabel">
|
||||||
|
<span class="text-muted-foreground">Aksi:</span>
|
||||||
|
<span class="ml-1 font-medium">{{ actionLabel }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="owner-verification-reject-reason">Alasan Penolakan</FieldLabel>
|
||||||
|
<Textarea id="owner-verification-reject-reason" v-model="rejectForm.reason"
|
||||||
|
placeholder="Jelaskan alasan penolakan..." rows="3" />
|
||||||
|
<FieldError :errors="rejectForm.errors.reason ? [rejectForm.errors.reason] : []" />
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DialogFooter>
|
||||||
|
<Button type="button" variant="outline" @click="rejectDialogOpen = false">
|
||||||
|
Batal
|
||||||
|
</Button>
|
||||||
|
<Button type="button" variant="destructive" :disabled="rejectForm.processing" @click="submitReject">
|
||||||
|
<X class="size-4" />
|
||||||
|
Tolak
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
@ -1,6 +1,7 @@
|
|||||||
export const CuttingStatus = {
|
export const CuttingStatus = {
|
||||||
IN_PROGRESS: 'in_progress',
|
IN_PROGRESS: 'in_progress',
|
||||||
COMPLETED: 'completed',
|
COMPLETED: 'completed',
|
||||||
|
PENDING_VERIFICATION: 'pending_verification',
|
||||||
VERIFIED: 'verified',
|
VERIFIED: 'verified',
|
||||||
REJECTED: 'rejected',
|
REJECTED: 'rejected',
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { toast } from 'vue-sonner';
|
|||||||
import { RowDeleteAction, RowEditAction, RowStatusAction } from '@/components/button';
|
import { RowDeleteAction, RowEditAction, RowStatusAction } from '@/components/button';
|
||||||
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
import ConfirmDialog from '@/components/ConfirmDialog.vue';
|
||||||
import { RupiahInput } from '@/components/form/rupiah-input';
|
import { RupiahInput } from '@/components/form/rupiah-input';
|
||||||
|
import OwnerVerificationRowActions from '@/components/owner-verification/OwnerVerificationRowActions.vue';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
@ -286,6 +287,10 @@ function actionIcon(status: string) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-wrap items-center justify-end gap-1">
|
<div class="flex flex-wrap items-center justify-end gap-1">
|
||||||
|
<OwnerVerificationRowActions v-if="cutting.status === CuttingStatus.PENDING_VERIFICATION" type="cutting"
|
||||||
|
:id="cutting.id" :title="cutting.description ?? `Cutting #${cutting.id}`" subject-label="Cutting"
|
||||||
|
action-label="Verifikasi Stok" />
|
||||||
|
|
||||||
<template v-for="action in availableActions" :key="action.status">
|
<template v-for="action in availableActions" :key="action.status">
|
||||||
<RowStatusAction v-if="canPerformAction(action)" :size="'sm'" :icon="actionIcon(action.status)"
|
<RowStatusAction v-if="canPerformAction(action)" :size="'sm'" :icon="actionIcon(action.status)"
|
||||||
:label="action.label" :destructive="action.destructive" @click="openStatusConfirm(action)" />
|
:label="action.label" :destructive="action.destructive" @click="openStatusConfirm(action)" />
|
||||||
|
|||||||
@ -1,25 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useForm } from '@inertiajs/vue3';
|
import { RowDetailAction } from '@/components/button';
|
||||||
import { X } from '@lucide/vue';
|
import OwnerVerificationRowActions from '@/components/owner-verification/OwnerVerificationRowActions.vue';
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
import { toast } from 'vue-sonner';
|
|
||||||
import { RowApproveAction, RowDetailAction, RowRejectAction } from '@/components/button';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
} from '@/components/ui/dialog';
|
|
||||||
import {
|
|
||||||
Field,
|
|
||||||
FieldError,
|
|
||||||
FieldLabel,
|
|
||||||
} from '@/components/ui/field';
|
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
|
||||||
import { useCan } from '@/composables/useCan';
|
|
||||||
import { approve, reject, approve_request, reject_request } from '@/routes/admin/manage/owner_verifications';
|
|
||||||
import type { OwnerVerificationItem } from '@/types/owner-verification';
|
import type { OwnerVerificationItem } from '@/types/owner-verification';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@ -29,125 +10,13 @@ const props = defineProps<{
|
|||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
view: [];
|
view: [];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { can } = useCan();
|
|
||||||
|
|
||||||
const rejectDialogOpen = ref(false);
|
|
||||||
|
|
||||||
const approveForm = useForm({});
|
|
||||||
const rejectForm = useForm({
|
|
||||||
reason: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
const approveUrl = computed(() => (
|
|
||||||
props.item.source === 'cutting'
|
|
||||||
? approve.url(props.item.id)
|
|
||||||
: approve_request.url(props.item.id)
|
|
||||||
));
|
|
||||||
|
|
||||||
const rejectUrl = computed(() => (
|
|
||||||
props.item.source === 'cutting'
|
|
||||||
? reject.url(props.item.id)
|
|
||||||
: reject_request.url(props.item.id)
|
|
||||||
));
|
|
||||||
|
|
||||||
function submitApprove() {
|
|
||||||
approveForm
|
|
||||||
.post(approveUrl.value, {
|
|
||||||
preserveScroll: true,
|
|
||||||
onError: (errors: Record<string, string>) => {
|
|
||||||
if (errors.system) {
|
|
||||||
toast.error(errors.system);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitReject() {
|
|
||||||
rejectForm
|
|
||||||
.post(rejectUrl.value, {
|
|
||||||
preserveScroll: true,
|
|
||||||
onSuccess: () => {
|
|
||||||
rejectDialogOpen.value = false;
|
|
||||||
rejectForm.reset();
|
|
||||||
},
|
|
||||||
onError: (errors: Record<string, string>) => {
|
|
||||||
if (errors.system) {
|
|
||||||
toast.error(errors.system);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center justify-end gap-1">
|
<div class="flex items-center justify-end gap-1">
|
||||||
<RowDetailAction tooltip="Lihat" @click="emit('view')" />
|
<RowDetailAction tooltip="Lihat" @click="emit('view')" />
|
||||||
|
|
||||||
<template v-if="item.is_pending && can('owner_verifications.verify')">
|
<OwnerVerificationRowActions v-if="item.is_pending" :type="item.source === 'cutting' ? 'cutting' : 'request'"
|
||||||
<RowApproveAction
|
:id="item.id" :title="item.title" :subject-label="item.subject_label" :action-label="item.action_label" />
|
||||||
size="sm"
|
|
||||||
tooltip="Setujui"
|
|
||||||
:disabled="approveForm.processing"
|
|
||||||
@click="submitApprove"
|
|
||||||
/>
|
|
||||||
<RowRejectAction
|
|
||||||
size="sm"
|
|
||||||
tooltip="Tolak"
|
|
||||||
:disabled="rejectForm.processing"
|
|
||||||
@click="rejectDialogOpen = true"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Dialog v-model:open="rejectDialogOpen">
|
|
||||||
<DialogContent class="sm:max-w-lg">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Tolak Verifikasi</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
|
|
||||||
<div class="space-y-4">
|
|
||||||
<div class="rounded-md border p-3 text-xs space-y-2">
|
|
||||||
<div>
|
|
||||||
<span class="text-muted-foreground">Modul:</span>
|
|
||||||
<span class="ml-1 font-medium">{{ item.subject_label }}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="text-muted-foreground">Item:</span>
|
|
||||||
<span class="ml-1 font-medium">{{ item.title }}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="text-muted-foreground">Aksi:</span>
|
|
||||||
<span class="ml-1 font-medium">{{ item.action_label }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Field>
|
|
||||||
<FieldLabel for="reject-reason">Alasan Penolakan</FieldLabel>
|
|
||||||
<Textarea
|
|
||||||
id="reject-reason"
|
|
||||||
v-model="rejectForm.reason"
|
|
||||||
placeholder="Jelaskan alasan penolakan..."
|
|
||||||
rows="3"
|
|
||||||
/>
|
|
||||||
<FieldError :errors="rejectForm.errors.reason ? [rejectForm.errors.reason] : []" />
|
|
||||||
</Field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<DialogFooter>
|
|
||||||
<Button type="button" variant="outline" @click="rejectDialogOpen = false">
|
|
||||||
Batal
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="destructive"
|
|
||||||
:disabled="rejectForm.processing"
|
|
||||||
@click="submitReject"
|
|
||||||
>
|
|
||||||
<X class="size-4" />
|
|
||||||
Tolak
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||||
|
import OwnerVerificationRowActions from '@/components/owner-verification/OwnerVerificationRowActions.vue';
|
||||||
import { useCan } from '@/composables/useCan';
|
import { useCan } from '@/composables/useCan';
|
||||||
import type { PurchaseListItem } from '@/types/purchase';
|
|
||||||
import { edit, destroy } from '@/routes/admin/manage/purchases';
|
import { edit, destroy } from '@/routes/admin/manage/purchases';
|
||||||
|
import type { PurchaseListItem } from '@/types/purchase';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
purchase: PurchaseListItem;
|
purchase: PurchaseListItem;
|
||||||
@ -13,20 +14,18 @@ const { can } = useCan();
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center justify-end gap-1">
|
<div class="flex items-center justify-end gap-1">
|
||||||
<RowEditAction
|
<OwnerVerificationRowActions v-if="purchase.has_pending_request && purchase.pending_request_id" type="request"
|
||||||
v-if="can('purchases.update')"
|
:id="purchase.pending_request_id"
|
||||||
:href="edit.url(purchase.id)"
|
:title="`${purchase.total_formatted} — ${purchase.supplier?.name ?? purchase.supplier_name ?? 'Supplier'}`"
|
||||||
|
subject-label="Belanja" :action-label="purchase.pending_request_action_label" />
|
||||||
|
|
||||||
|
<RowEditAction v-if="can('purchases.update')" :href="edit.url(purchase.id)"
|
||||||
:disabled="purchase.has_pending_request"
|
:disabled="purchase.has_pending_request"
|
||||||
:tooltip="purchase.has_pending_request ? 'Menunggu verifikasi owner' : 'Ubah'"
|
:tooltip="purchase.has_pending_request ? 'Menunggu verifikasi owner' : 'Ubah'" />
|
||||||
/>
|
<RowDeleteAction v-if="can('purchases.delete')" :action-url="destroy.url(purchase.id)"
|
||||||
<RowDeleteAction
|
|
||||||
v-if="can('purchases.delete')"
|
|
||||||
:action-url="destroy.url(purchase.id)"
|
|
||||||
:disabled="purchase.has_pending_request"
|
:disabled="purchase.has_pending_request"
|
||||||
:tooltip="purchase.has_pending_request ? 'Menunggu verifikasi owner' : 'Hapus'"
|
:tooltip="purchase.has_pending_request ? 'Menunggu verifikasi owner' : 'Hapus'" title="Hapus belanja?"
|
||||||
title="Hapus belanja?"
|
|
||||||
:description="`Pengajuan hapus belanja ${purchase.total_formatted} dari ${purchase.supplier?.name ?? purchase.supplier_name} akan dikirim ke owner untuk verifikasi.`"
|
:description="`Pengajuan hapus belanja ${purchase.total_formatted} dari ${purchase.supplier?.name ?? purchase.supplier_name} akan dikirim ke owner untuk verifikasi.`"
|
||||||
error-message="Gagal mengajukan penghapusan belanja."
|
error-message="Gagal mengajukan penghapusan belanja." />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||||
|
import OwnerVerificationRowActions from '@/components/owner-verification/OwnerVerificationRowActions.vue';
|
||||||
import { useCan } from '@/composables/useCan';
|
import { useCan } from '@/composables/useCan';
|
||||||
import type { ProductListItem } from '@/types/product';
|
|
||||||
import { edit, destroy } from '@/routes/admin/master/products';
|
import { edit, destroy } from '@/routes/admin/master/products';
|
||||||
|
import type { ProductListItem } from '@/types/product';
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
product: ProductListItem;
|
product: ProductListItem;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
@ -13,20 +14,17 @@ const { can } = useCan();
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center justify-end gap-1">
|
<div class="flex items-center justify-end gap-1">
|
||||||
<RowEditAction
|
<OwnerVerificationRowActions v-if="product.has_pending_request && product.pending_request_id" type="request"
|
||||||
v-if="can('products.update')"
|
:id="product.pending_request_id" :title="product.name" subject-label="Produk"
|
||||||
:href="edit.url(product.id)"
|
:action-label="product.pending_request_action_label" />
|
||||||
|
|
||||||
|
<RowEditAction v-if="can('products.update')" :href="edit.url(product.id)"
|
||||||
:disabled="product.has_pending_request"
|
:disabled="product.has_pending_request"
|
||||||
:tooltip="product.has_pending_request ? 'Menunggu verifikasi owner' : 'Ubah'"
|
:tooltip="product.has_pending_request ? 'Menunggu verifikasi owner' : 'Ubah'" />
|
||||||
/>
|
<RowDeleteAction v-if="can('products.delete')" :action-url="destroy.url(product.id)"
|
||||||
<RowDeleteAction
|
|
||||||
v-if="can('products.delete')"
|
|
||||||
:action-url="destroy.url(product.id)"
|
|
||||||
:disabled="product.has_pending_request"
|
:disabled="product.has_pending_request"
|
||||||
:tooltip="product.has_pending_request ? 'Menunggu verifikasi owner' : 'Hapus'"
|
:tooltip="product.has_pending_request ? 'Menunggu verifikasi owner' : 'Hapus'" title="Hapus produk?"
|
||||||
title="Hapus produk?"
|
|
||||||
:description="`Pengajuan hapus produk ${product.name} akan dikirim ke owner untuk verifikasi.`"
|
:description="`Pengajuan hapus produk ${product.name} akan dikirim ke owner untuk verifikasi.`"
|
||||||
error-message="Gagal mengajukan penghapusan produk."
|
error-message="Gagal mengajukan penghapusan produk." />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
import { RowDeleteAction, RowEditAction } from '@/components/button';
|
||||||
|
import OwnerVerificationRowActions from '@/components/owner-verification/OwnerVerificationRowActions.vue';
|
||||||
import { useCan } from '@/composables/useCan';
|
import { useCan } from '@/composables/useCan';
|
||||||
import type { RawMaterialListItem } from '@/types/raw-material';
|
import type { RawMaterialListItem } from '@/types/raw-material';
|
||||||
import { edit, destroy } from '@/routes/admin/master/raw_materials';
|
import { edit, destroy } from '@/routes/admin/master/raw_materials';
|
||||||
@ -13,6 +14,15 @@ const { can } = useCan();
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center justify-end gap-1">
|
<div class="flex items-center justify-end gap-1">
|
||||||
|
<OwnerVerificationRowActions
|
||||||
|
v-if="material.has_pending_request && material.pending_request_id"
|
||||||
|
type="request"
|
||||||
|
:id="material.pending_request_id"
|
||||||
|
:title="material.name"
|
||||||
|
subject-label="Bahan Baku"
|
||||||
|
:action-label="material.pending_request_action_label"
|
||||||
|
/>
|
||||||
|
|
||||||
<RowEditAction
|
<RowEditAction
|
||||||
v-if="can('raw_materials.update')"
|
v-if="can('raw_materials.update')"
|
||||||
:href="edit.url(material.id)"
|
:href="edit.url(material.id)"
|
||||||
|
|||||||
@ -64,6 +64,7 @@ export interface Product {
|
|||||||
|
|
||||||
export interface ProductListItem extends Product {
|
export interface ProductListItem extends Product {
|
||||||
has_pending_request?: boolean;
|
has_pending_request?: boolean;
|
||||||
|
pending_request_id?: number;
|
||||||
pending_request_action?: string;
|
pending_request_action?: string;
|
||||||
pending_request_action_label?: string;
|
pending_request_action_label?: string;
|
||||||
display_is_active?: boolean;
|
display_is_active?: boolean;
|
||||||
|
|||||||
@ -39,6 +39,7 @@ export type PurchaseListItem = {
|
|||||||
photos?: MediaItem | null;
|
photos?: MediaItem | null;
|
||||||
items: any[];
|
items: any[];
|
||||||
has_pending_request?: boolean;
|
has_pending_request?: boolean;
|
||||||
|
pending_request_id?: number;
|
||||||
pending_request_action?: string;
|
pending_request_action?: string;
|
||||||
pending_request_action_label?: string;
|
pending_request_action_label?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -28,6 +28,7 @@ export type RawMaterialListItem = {
|
|||||||
is_active: boolean;
|
is_active: boolean;
|
||||||
prices: RawMaterialPrice[];
|
prices: RawMaterialPrice[];
|
||||||
has_pending_request?: boolean;
|
has_pending_request?: boolean;
|
||||||
|
pending_request_id?: number;
|
||||||
pending_request_action?: string;
|
pending_request_action?: string;
|
||||||
pending_request_action_label?: string;
|
pending_request_action_label?: string;
|
||||||
display_is_active?: boolean;
|
display_is_active?: boolean;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user