- Introduced StockMutation model and service to handle stock changes. - Created migration for stock_mutations table. - Implemented stock mutation recording in various services (CuttingService, OrderService, PurchaseService, RestockService, RetailStockService). - Added StockHistoryController to manage stock history views. - Developed frontend components for displaying stock history and actions. - Updated routes to include stock history access with appropriate permissions. - Enhanced ProductVariant and RawMaterialPrice models to support stock mutations. - Added RowHistoryAction button for accessing stock history in product and raw material tables.
130 lines
4.3 KiB
Vue
130 lines
4.3 KiB
Vue
<script setup lang="ts">
|
|
import { Head } from '@inertiajs/vue3';
|
|
import type { ColumnDef } from '@tanstack/vue-table';
|
|
import { h } from 'vue';
|
|
import BackButton from '@/components/button/BackButton.vue';
|
|
import DataTable from '@/components/data-table/DataTable.vue';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Card, CardContent } from '@/components/ui/card';
|
|
import AdminLayout from '@/layouts/AdminLayout.vue';
|
|
import { index as productsIndex } from '@/routes/admin/master/products';
|
|
import { index as rawMaterialsIndex } from '@/routes/admin/master/raw_materials';
|
|
import type { PaginatedStockMutations, StockMutation } from '@/types/stock-mutation';
|
|
|
|
const props = defineProps<{
|
|
title: string;
|
|
stockableType: string;
|
|
stockableId: number;
|
|
mutations: PaginatedStockMutations;
|
|
}>();
|
|
|
|
const backUrl = props.stockableType === 'product-variant'
|
|
? productsIndex.url()
|
|
: rawMaterialsIndex.url();
|
|
|
|
const pagination = {
|
|
currentPage: props.mutations.current_page,
|
|
perPage: props.mutations.per_page,
|
|
lastPage: props.mutations.last_page,
|
|
total: props.mutations.total,
|
|
};
|
|
|
|
const typeBadgeVariant = (type: string): string => {
|
|
const map: Record<string, string> = {
|
|
in: 'success',
|
|
out: 'destructive',
|
|
transfer: 'info',
|
|
adjustment: 'warning',
|
|
};
|
|
return map[type] ?? 'secondary';
|
|
};
|
|
|
|
const columns: ColumnDef<StockMutation>[] = [
|
|
{
|
|
accessorKey: 'created_at_formatted',
|
|
header: 'Tanggal',
|
|
cell: ({ row }) => row.original.created_at_formatted ?? '-',
|
|
},
|
|
{
|
|
accessorKey: 'type_label',
|
|
header: 'Tipe',
|
|
cell: ({ row }) => h(Badge, {
|
|
variant: typeBadgeVariant(row.original.type),
|
|
}, () => row.original.type_label),
|
|
},
|
|
{
|
|
accessorKey: 'description',
|
|
header: 'Keterangan',
|
|
cell: ({ row }) => {
|
|
const mutation = row.original;
|
|
const parts = [mutation.description ?? '-'];
|
|
if (mutation.stock_quality) {
|
|
const qualityLabels: Record<string, string> = {
|
|
good: 'Stok Bagus',
|
|
reject: 'Stok Reject',
|
|
retail: 'Stok Ecer',
|
|
};
|
|
parts.push(qualityLabels[mutation.stock_quality] ?? mutation.stock_quality);
|
|
}
|
|
return parts.join(' — ');
|
|
},
|
|
},
|
|
{
|
|
accessorKey: 'quantity',
|
|
header: 'Qty',
|
|
cell: ({ row }) => {
|
|
const qty = Number(row.original.quantity);
|
|
const prefix = qty >= 0 ? '+' : '';
|
|
const cls = qty > 0 ? 'text-green-600 font-medium tabular-nums'
|
|
: qty < 0 ? 'text-red-600 font-medium tabular-nums'
|
|
: 'tabular-nums';
|
|
return h('span', { class: cls }, `${prefix}${qty.toLocaleString('id-ID')}`);
|
|
},
|
|
},
|
|
{
|
|
accessorKey: 'stock_before',
|
|
header: 'Stok Sebelum',
|
|
cell: ({ row }) => h('span', { class: 'tabular-nums' }, Number(row.original.stock_before).toLocaleString('id-ID')),
|
|
},
|
|
{
|
|
accessorKey: 'stock_after',
|
|
header: 'Stok Sesudah',
|
|
cell: ({ row }) => h('span', { class: 'tabular-nums' }, Number(row.original.stock_after).toLocaleString('id-ID')),
|
|
},
|
|
{
|
|
accessorKey: 'user.profile.full_name',
|
|
id: 'user',
|
|
header: 'User',
|
|
cell: ({ row }) => row.original.user?.profile?.full_name ?? 'Sistem',
|
|
},
|
|
];
|
|
</script>
|
|
|
|
<template>
|
|
<Head :title="`Riwayat Stok - ${title}`" />
|
|
|
|
<AdminLayout>
|
|
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
<div class="space-y-1">
|
|
<h2 class="text-2xl font-bold tracking-tight">Riwayat Stok</h2>
|
|
<p class="text-sm text-muted-foreground">{{ title }}</p>
|
|
</div>
|
|
|
|
<BackButton :href="backUrl" />
|
|
</div>
|
|
|
|
<Card class="min-w-0">
|
|
<CardContent class="min-w-0">
|
|
<DataTable
|
|
:columns="columns"
|
|
:data="mutations.data"
|
|
:pagination="pagination"
|
|
:pagination-links="mutations.links"
|
|
:show-row-number="true"
|
|
pagination-item-label="mutasi"
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
</AdminLayout>
|
|
</template>
|