feat(FE-62,65): add inventory movement management with API and form validation

This commit is contained in:
rstubryan
2025-10-08 15:26:45 +07:00
parent 1968761b5d
commit 7ceb25ea71
4 changed files with 262 additions and 109 deletions
@@ -0,0 +1,67 @@
import * as Yup from 'yup';
export const MovementFormSchema = Yup.object({
alasan_transfer: Yup.string()
.required('Alasan Transfer wajib diisi!'),
tanggal_transfer: Yup.date()
.required('Tanggal Transfer wajib diisi!')
.typeError('Tanggal Transfer tidak valid!'),
warehouse_asal: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
warehouse_asal_id: Yup.number()
.required('Gudang Asal wajib diisi!'),
warehouse_tujuan: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
warehouse_tujuan_id: Yup.number()
.required('Gudang Tujuan wajib diisi!'),
alasan: Yup.string()
.required('Alasan wajib diisi!'),
product: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
product_id: Yup.array()
.of(Yup.number()).min(1, 'Pilih minimal 1 produk')
.required('Produk wajib diisi!'),
qty_product: Yup.array()
.of(Yup.number().min(1, 'Kuantitas minimal 1'))
.min(1, 'Pilih minimal 1 produk')
.required('Kuantitas wajib diisi!'),
ekspedisi: Yup.array().of(
Yup.object({
product: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
product_id: Yup.number()
.required('Produk wajib diisi!'),
qty: Yup.number().min(1, 'Kuantitas minimal 1')
.required('Kuantitas wajib diisi!'),
supplier: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
supplier_id: Yup.number()
.required('Supplier wajib diisi!'),
plat_nomor: Yup.string()
.required('Plat Nomor wajib diisi!'),
no_surat_jalan: Yup.string()
.required('No Surat Jalan wajib diisi!'),
dokumen: Yup.mixed()
.required('Dokumen wajib diisi!'),
biaya_ekspedisi: Yup.number()
.min(0, 'Biaya Ekspedisi minimal 0')
.required('Biaya Ekspedisi wajib diisi!'),
nama_sopir: Yup.string()
.required('Nama Sopir wajib diisi!'),
})
).min(1, 'Pilih minimal 1 ekspedisi').required('Ekspedisi wajib diisi!'),
});
export const UpdateMovementFormSchema = MovementFormSchema;
export type MovementFormValues = Yup.InferType<typeof MovementFormSchema>;
+32 -9
View File
@@ -5,6 +5,29 @@ export const MAIN_DRAWER_LINKS = [
icon: 'gg:chart', icon: 'gg:chart',
}, },
{
title: 'Persediaan',
link: '/inventory',
icon: 'mdi:warehouse',
submenu: [
{
title: 'Product',
link: '/inventory/product',
icon: 'mdi:package-variant-closed',
},
{
title: 'Penyesuaian Stok',
link: '/inventory/adjustment',
icon: 'mdi:database-edit',
},
{
title: 'Transfer Stok',
link: '/inventory/movement',
icon: 'mdi:swap-horizontal',
},
],
},
{ {
title: 'Master Data', title: 'Master Data',
link: '/master-data', link: '/master-data',
@@ -109,14 +132,14 @@ export const WAREHOUSE_TYPE_OPTIONS = [
]; ];
export const PRODUCT_FLAG_OPTIONS = [ export const PRODUCT_FLAG_OPTIONS = [
{ label: 'DOC', value: 'DOC' }, {label: 'DOC', value: 'DOC'},
{ label: 'PAKAN', value: 'PAKAN' }, {label: 'PAKAN', value: 'PAKAN'},
{ label: 'PRE-STARTER', value: 'PRE-STARTER' }, {label: 'PRE-STARTER', value: 'PRE-STARTER'},
{ label: 'STARTER', value: 'STARTER' }, {label: 'STARTER', value: 'STARTER'},
{ label: 'FINISHER', value: 'FINISHER' }, {label: 'FINISHER', value: 'FINISHER'},
{ label: 'OVK', value: 'OVK' }, {label: 'OVK', value: 'OVK'},
{ label: 'OBAT', value: 'OBAT' }, {label: 'OBAT', value: 'OBAT'},
{ label: 'VITAMIN', value: 'VITAMIN' }, {label: 'VITAMIN', value: 'VITAMIN'},
{ label: 'KIMIA', value: 'KIMIA' }, {label: 'KIMIA', value: 'KIMIA'},
]; ];
+12
View File
@@ -0,0 +1,12 @@
import {
CreateMovementPayload,
Movement,
UpdateMovementPayload,
} from "@/types/api/inventory/movement";
import {BaseApiService} from "@/services/api/base";
export const MovementApi = new BaseApiService<
Movement,
CreateMovementPayload,
UpdateMovementPayload
>('/inventory/movements');
+51
View File
@@ -0,0 +1,51 @@
import {BaseMetadata} from '@/types/api/api-general';
import {Product} from "@/types/api/master-data/product";
import {Supplier} from "@/types/api/master-data/supplier";
import {Warehouse} from "@/types/api/master-data/warehouse";
export type BaseMovement = {
id: number;
alasan_transfer: string;
tanggal_transfer: string;
warehouse_asal: Warehouse;
warehouse_tujuan: Warehouse;
product: Array<{
product: Product;
qty_product: number;
}>;
ekspedisi: Array<{
product_id: number;
qty: number;
supplier: Supplier;
plat_nomor: string;
no_surat_jalan: string;
dokumen: string;
biaya_ekspedisi: number;
nama_sopir: string;
}>;
name: string;
};
export type Movement = BaseMetadata & BaseMovement;
export type CreateMovementPayload = {
alasan: string;
warehouse_asal_id: number;
warehouse_tujuan_id: number;
product: Array<{
product_id: number;
qty_product: number;
}>;
ekspedisi: Array<{
product_id: number;
qty: number;
supplier_id: number;
plat_nomor: string;
no_surat_jalan: string;
dokumen: string;
biaya_ekspedisi: number;
nama_sopir: string;
}>;
}
export type UpdateMovementPayload = CreateMovementPayload;