mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-177): Integrate API sales order and fixing sales order initial state
This commit is contained in:
@@ -215,7 +215,7 @@ const SalesOrderTable = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'name',
|
accessorKey: 'so_number',
|
||||||
header: 'No. Order',
|
header: 'No. Order',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -226,7 +226,7 @@ const SalesOrderTable = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'approval.step_name',
|
accessorKey: 'latest_approval.step_name',
|
||||||
header: 'Status',
|
header: 'Status',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ import ApprovalSteps, {
|
|||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import { MARKETING_APPROVAL_LINE } from '@/config/approval-line';
|
import { MARKETING_APPROVAL_LINE } from '@/config/approval-line';
|
||||||
import { cn, formatCurrency, formatDate, formatNumber } from '@/lib/helper';
|
import { cn, formatCurrency, formatDate, formatNumber } from '@/lib/helper';
|
||||||
import { MarketingApi } from '@/services/api/marketing/marketing';
|
import {
|
||||||
|
MarketingApi,
|
||||||
|
SalesOrderApi,
|
||||||
|
} from '@/services/api/marketing/marketing';
|
||||||
import { BaseSalesOrder, Marketing } from '@/types/api/marketing/marketing';
|
import { BaseSalesOrder, Marketing } from '@/types/api/marketing/marketing';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -77,7 +80,7 @@ const SalesOrderDetail = ({
|
|||||||
|
|
||||||
const confirmationModalApproveClickHandler = async () => {
|
const confirmationModalApproveClickHandler = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const res = await MarketingApi.singleApproval(
|
const res = await SalesOrderApi.singleApproval(
|
||||||
initialValues?.id as number,
|
initialValues?.id as number,
|
||||||
approvalAction
|
approvalAction
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { CustomerApi } from '@/services/api/master-data';
|
|||||||
import { useFormik } from 'formik';
|
import { useFormik } from 'formik';
|
||||||
import { SalesOrderFormValues, SalesOrderSchema } from './MarketingForm.schema';
|
import { SalesOrderFormValues, SalesOrderSchema } from './MarketingForm.schema';
|
||||||
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
import { MarketingApi } from '@/services/api/marketing/marketing';
|
import { SalesOrderApi } from '@/services/api/marketing/marketing';
|
||||||
import { SalesOrderProductFormValues } from './repeater/sales-order/SalesOrderProduct.schema';
|
import { SalesOrderProductFormValues } from './repeater/sales-order/SalesOrderProduct.schema';
|
||||||
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
@@ -36,6 +36,8 @@ const MarketingProductToFieldValues = (
|
|||||||
product: BaseSalesOrder
|
product: BaseSalesOrder
|
||||||
): SalesOrderProductFormValues => {
|
): SalesOrderProductFormValues => {
|
||||||
return {
|
return {
|
||||||
|
id: product.id,
|
||||||
|
vehicle_number: product.vehicle_number,
|
||||||
kandang_id: product.product_warehouse.warehouse.id,
|
kandang_id: product.product_warehouse.warehouse.id,
|
||||||
kandang: {
|
kandang: {
|
||||||
value: product.product_warehouse.warehouse.id,
|
value: product.product_warehouse.warehouse.id,
|
||||||
@@ -70,87 +72,89 @@ const SalesForm = ({
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [selectedMarketingProduct, setSelectedMarketingProduct] =
|
const [selectedMarketingProduct, setSelectedMarketingProduct] =
|
||||||
useState<SalesOrderProductFormValues | null>(null);
|
useState<SalesOrderProductFormValues | null>(null);
|
||||||
const [rawMarketingProducts, setRawMarketingProducts] = useState<
|
|
||||||
SalesOrderProductFormValues[]
|
|
||||||
>(
|
|
||||||
initialValues?.sales_order.map((item) =>
|
|
||||||
MarketingProductToFieldValues(item)
|
|
||||||
) || []
|
|
||||||
);
|
|
||||||
const [selectedCustomer, setSelectedCustomer] = useState<OptionType | null>(
|
|
||||||
initialValues?.customer
|
|
||||||
? { value: initialValues.customer.id, label: initialValues.customer.name }
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
|
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
|
||||||
const selectedRowIds = Object.keys(rowSelection).map((item) =>
|
const selectedRowIds = Object.keys(rowSelection).map((item) =>
|
||||||
parseInt(item)
|
parseInt(item)
|
||||||
);
|
);
|
||||||
const [grandTotal, setGrandTotal] = useState<number>(
|
|
||||||
initialValues?.sales_order
|
|
||||||
?.map((item) => item.total_price)
|
|
||||||
.reduce((a, b) => a + b, 0) ?? 0
|
|
||||||
);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
options: customerOptions,
|
options: customerOptions,
|
||||||
isLoadingOptions: isLoadingCustomerOptions,
|
isLoadingOptions: isLoadingCustomerOptions,
|
||||||
} = useSelect<Customer>(CustomerApi.basePath, 'id', 'name');
|
} = useSelect<Customer>(CustomerApi.basePath, 'id', 'name');
|
||||||
|
|
||||||
const handleDeleteProduct = useCallback(
|
const formikInitialValues = useMemo(() => {
|
||||||
(product_warehouse_id: number, kandang_id: number) => {
|
return {
|
||||||
setRawMarketingProducts((prev) =>
|
so_date: initialValues?.so_date || undefined,
|
||||||
prev.filter(
|
notes: initialValues?.notes || undefined,
|
||||||
(p) =>
|
customer_id: initialValues?.customer?.id || undefined,
|
||||||
p.product_warehouse_id !== product_warehouse_id &&
|
sales_person_id: initialValues?.sales_person?.id || 1,
|
||||||
p.kandang_id !== kandang_id
|
customer: initialValues?.customer
|
||||||
)
|
? {
|
||||||
);
|
value: initialValues.customer.id,
|
||||||
},
|
label: initialValues.customer.name,
|
||||||
[]
|
}
|
||||||
);
|
: null,
|
||||||
const handleBulkDeleteProduct = () => {
|
sales_order:
|
||||||
setRawMarketingProducts((prev) =>
|
initialValues?.sales_order?.map((product) =>
|
||||||
prev.filter(
|
MarketingProductToFieldValues(product)
|
||||||
(product) =>
|
) ?? [],
|
||||||
!selectedRowIds.includes(
|
};
|
||||||
parseInt(`${product.product_warehouse_id}${product.kandang_id}`)
|
}, [initialValues]);
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const handleDelete = () => {
|
|
||||||
deleteModal.openModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAddProductClick = useCallback(() => {
|
const formik = useFormik<SalesOrderFormValues>({
|
||||||
setSelectedMarketingProduct(null); // Pastikan form tambah
|
enableReinitialize: true,
|
||||||
addProductModal.openModal();
|
initialValues: formikInitialValues,
|
||||||
}, [addProductModal]);
|
validationSchema: SalesOrderSchema,
|
||||||
const handleAddSubmitProduct = useCallback(
|
validateOnMount: true,
|
||||||
async (values: SalesOrderProductFormValues) => {
|
onSubmit: async (values) => {
|
||||||
setRawMarketingProducts((prev) => [...prev, values]);
|
console.log('VALUES');
|
||||||
formik.setValues({
|
console.log(values);
|
||||||
...formik.values,
|
const payload = {
|
||||||
sales_order: [...formik.values.sales_order, values],
|
customer_id: values.customer_id as number,
|
||||||
});
|
sales_person_id: values.sales_person_id as number,
|
||||||
setGrandTotal((prev) => prev + (values.total_price as number));
|
date: formatDate(values.so_date as string, 'yyyy-MM-DD'),
|
||||||
addProductModal.closeModal();
|
notes: values.notes as string,
|
||||||
|
marketing_products: values.sales_order.map((product) => {
|
||||||
|
return {
|
||||||
|
vehicle_number: product.vehicle_number as string,
|
||||||
|
kandang_id: product.kandang_id as number,
|
||||||
|
product_warehouse_id: product.product_warehouse_id as number,
|
||||||
|
unit_price: parseFloat(product.unit_price as string),
|
||||||
|
total_weight: parseFloat(product.total_weight as string),
|
||||||
|
qty: parseFloat(product.qty as string),
|
||||||
|
avg_weight: parseFloat(product.avg_weight as string),
|
||||||
|
total_price: parseFloat(product.total_price as string),
|
||||||
|
} as CreateSalesOrderProductPayload;
|
||||||
|
}),
|
||||||
|
} as CreateSalesOrderPayload;
|
||||||
|
console.log('PAYLOAD');
|
||||||
|
console.log(payload);
|
||||||
|
switch (formType) {
|
||||||
|
case 'add':
|
||||||
|
await createMarketingHandler(payload);
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
await updateMarketingHandler(payload);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
afterSubmit?.();
|
||||||
},
|
},
|
||||||
[rawMarketingProducts.length, addProductModal]
|
});
|
||||||
);
|
|
||||||
const handleChangeCustomer = useCallback(
|
const grandTotal = useMemo(() => {
|
||||||
(val: OptionType | OptionType[] | null) => {
|
return formik.values.sales_order.reduce(
|
||||||
setSelectedCustomer(val as OptionType);
|
(total, product) =>
|
||||||
formik.setFieldValue('customer_id', (val as OptionType)?.value);
|
total + parseFloat((product.total_price as string) || '0'),
|
||||||
formik.setFieldValue('customer', val as OptionType);
|
0
|
||||||
},
|
);
|
||||||
[selectedCustomer, setSelectedCustomer]
|
}, [formik.values.sales_order]);
|
||||||
);
|
|
||||||
|
|
||||||
const createMarketingHandler = async (values: CreateSalesOrderPayload) => {
|
const createMarketingHandler = async (values: CreateSalesOrderPayload) => {
|
||||||
console.log(values);
|
console.log(values);
|
||||||
const createMarketingRes = await MarketingApi.create(values);
|
const createMarketingRes = await SalesOrderApi.create(values);
|
||||||
if (isResponseSuccess(createMarketingRes)) {
|
if (isResponseSuccess(createMarketingRes)) {
|
||||||
toast.success(createMarketingRes?.message as string);
|
toast.success(createMarketingRes?.message as string);
|
||||||
router.push('/marketing/sales-orders');
|
router.push('/marketing/sales-orders');
|
||||||
@@ -161,7 +165,7 @@ const SalesForm = ({
|
|||||||
};
|
};
|
||||||
const updateMarketingHandler = async (values: CreateSalesOrderPayload) => {
|
const updateMarketingHandler = async (values: CreateSalesOrderPayload) => {
|
||||||
console.log(values);
|
console.log(values);
|
||||||
const updateMarketingRes = await MarketingApi.update(
|
const updateMarketingRes = await SalesOrderApi.update(
|
||||||
initialValues?.id as number,
|
initialValues?.id as number,
|
||||||
values
|
values
|
||||||
);
|
);
|
||||||
@@ -176,7 +180,7 @@ const SalesForm = ({
|
|||||||
const deleteMarketingHandler = async () => {
|
const deleteMarketingHandler = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
console.log(initialValues?.id);
|
console.log(initialValues?.id);
|
||||||
const deleteMarketingRes = await MarketingApi.delete(
|
const deleteMarketingRes = await SalesOrderApi.delete(
|
||||||
initialValues?.id as number
|
initialValues?.id as number
|
||||||
);
|
);
|
||||||
if (isResponseSuccess(deleteMarketingRes)) {
|
if (isResponseSuccess(deleteMarketingRes)) {
|
||||||
@@ -191,84 +195,59 @@ const SalesForm = ({
|
|||||||
router.push('/marketing/sales-orders');
|
router.push('/marketing/sales-orders');
|
||||||
};
|
};
|
||||||
|
|
||||||
const formikInitialValues = useMemo(() => {
|
const handleDeleteProduct = useCallback(
|
||||||
return {
|
(id: number) => {
|
||||||
so_date: initialValues?.so_date || undefined,
|
const currentProducts = formik.values.sales_order;
|
||||||
notes: initialValues?.notes || undefined,
|
formik.setFieldValue(
|
||||||
customer_id: initialValues?.customer?.id || undefined,
|
'sales_order',
|
||||||
sales_person_id: initialValues?.sales_person?.id || 1,
|
currentProducts.filter((p) => p.id != id)
|
||||||
customer: {
|
);
|
||||||
value: initialValues?.customer?.id as number,
|
|
||||||
label: initialValues?.customer?.name as string,
|
|
||||||
},
|
|
||||||
sales_order:
|
|
||||||
initialValues?.sales_order?.map((product) =>
|
|
||||||
MarketingProductToFieldValues(product)
|
|
||||||
) ?? [],
|
|
||||||
};
|
|
||||||
}, [initialValues]);
|
|
||||||
|
|
||||||
const formik = useFormik<SalesOrderFormValues>({
|
|
||||||
enableReinitialize: true,
|
|
||||||
initialValues: formikInitialValues,
|
|
||||||
validationSchema: SalesOrderSchema,
|
|
||||||
validateOnMount: true,
|
|
||||||
onSubmit: async (values) => {
|
|
||||||
const payload = {
|
|
||||||
customer_id: values.customer_id as number,
|
|
||||||
sales_person_id: values.sales_person_id as number,
|
|
||||||
date: formatDate(values.so_date as string, 'yyyy-MM-DD'),
|
|
||||||
notes: values.notes as string,
|
|
||||||
marketing_products: values.sales_order.map((product) => {
|
|
||||||
return {
|
|
||||||
vehicle_number: 'D 1234 XXXX',
|
|
||||||
kandang_id: product.kandang_id as number,
|
|
||||||
product_warehouse_id: product.product_warehouse_id as number,
|
|
||||||
unit_price: parseFloat(product.unit_price as string),
|
|
||||||
total_weight: parseFloat(product.total_weight as string),
|
|
||||||
qty: parseFloat(product.qty as string),
|
|
||||||
avg_weight: parseFloat(product.avg_weight as string),
|
|
||||||
total_price: parseFloat(product.total_price as string),
|
|
||||||
} as CreateSalesOrderProductPayload;
|
|
||||||
}),
|
|
||||||
} as CreateSalesOrderPayload;
|
|
||||||
switch (formType) {
|
|
||||||
case 'add':
|
|
||||||
createMarketingHandler(payload);
|
|
||||||
break;
|
|
||||||
case 'edit':
|
|
||||||
updateMarketingHandler(payload);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
afterSubmit?.();
|
|
||||||
},
|
},
|
||||||
});
|
[formik]
|
||||||
|
);
|
||||||
|
|
||||||
const { setValues: formikSetValues } = formik;
|
const handleBulkDeleteProduct = useCallback(() => {
|
||||||
|
const currentProducts = formik.values.sales_order;
|
||||||
useEffect(() => {
|
formik.setFieldValue(
|
||||||
formikSetValues(formik.initialValues);
|
'sales_order',
|
||||||
}, [formikSetValues, formik.initialValues]);
|
currentProducts.filter(
|
||||||
|
(product) => !selectedRowIds.includes(product.id ?? -1)
|
||||||
useEffect(() => {
|
)
|
||||||
// Hitung Grand Total baru
|
|
||||||
const newGrandTotal = rawMarketingProducts.reduce(
|
|
||||||
(total, product) => total + parseFloat(product.total_price as string),
|
|
||||||
0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Perbarui nilai formik.values.marketing_products
|
|
||||||
formik.setFieldValue('marketing_products', rawMarketingProducts, false);
|
|
||||||
// Parameter ketiga (false) untuk menghindari validasi secara langsung
|
|
||||||
|
|
||||||
// Perbarui state grandTotal
|
|
||||||
setGrandTotal(newGrandTotal);
|
|
||||||
|
|
||||||
// Reset row selection setiap kali daftar produk berubah (opsional, tapi disarankan)
|
|
||||||
setRowSelection({});
|
setRowSelection({});
|
||||||
}, [rawMarketingProducts]);
|
}, [formik, selectedRowIds]);
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
deleteModal.openModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddProductClick = useCallback(() => {
|
||||||
|
setSelectedMarketingProduct(null);
|
||||||
|
addProductModal.openModal();
|
||||||
|
}, [addProductModal]);
|
||||||
|
|
||||||
|
const handleAddSubmitProduct = useCallback(
|
||||||
|
async (values: SalesOrderProductFormValues) => {
|
||||||
|
const currentProducts = formik.values.sales_order;
|
||||||
|
const newValues = {
|
||||||
|
...values,
|
||||||
|
id: values.id ?? Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
formik.setFieldValue('sales_order', [...currentProducts, newValues]);
|
||||||
|
|
||||||
|
addProductModal.closeModal();
|
||||||
|
},
|
||||||
|
[formik, addProductModal]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleChangeCustomer = useCallback(
|
||||||
|
(val: OptionType | OptionType[] | null) => {
|
||||||
|
formik.setFieldValue('customer_id', (val as OptionType)?.value);
|
||||||
|
formik.setFieldValue('customer', val as OptionType);
|
||||||
|
},
|
||||||
|
[formik]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -292,7 +271,7 @@ const SalesForm = ({
|
|||||||
label='Pelanggan'
|
label='Pelanggan'
|
||||||
options={customerOptions}
|
options={customerOptions}
|
||||||
isLoading={isLoadingCustomerOptions}
|
isLoading={isLoadingCustomerOptions}
|
||||||
value={selectedCustomer}
|
value={formik.values.customer}
|
||||||
onChange={handleChangeCustomer}
|
onChange={handleChangeCustomer}
|
||||||
isError={
|
isError={
|
||||||
formik.touched.customer_id && Boolean(formik.errors.customer_id)
|
formik.touched.customer_id && Boolean(formik.errors.customer_id)
|
||||||
@@ -318,13 +297,14 @@ const SalesForm = ({
|
|||||||
wrapper: 'bg-white w-full',
|
wrapper: 'bg-white w-full',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{JSON.stringify(formik.values.sales_order)}
|
{/* <div className='text-blue-500'>{JSON.stringify(initialValues)}</div>
|
||||||
<div className='text-green-500'>
|
<div className='text-green-500'>{JSON.stringify(formik.values)}</div>
|
||||||
{JSON.stringify(formik.values.sales_order)}
|
<div className='text-red-500'>{JSON.stringify(formik.errors)}</div> */}
|
||||||
</div>
|
|
||||||
<span className='text-red-500'>{JSON.stringify(formik.errors)}</span>
|
|
||||||
<SalesOrderProductTable
|
<SalesOrderProductTable
|
||||||
data={rawMarketingProducts}
|
data={formik.values.sales_order}
|
||||||
|
rowSelection={rowSelection}
|
||||||
|
setRowSelection={setRowSelection}
|
||||||
|
selectedRowIds={selectedRowIds}
|
||||||
onDelete={handleDeleteProduct}
|
onDelete={handleDeleteProduct}
|
||||||
onBulkDelete={handleBulkDeleteProduct}
|
onBulkDelete={handleBulkDeleteProduct}
|
||||||
onAddProductClick={handleAddProductClick}
|
onAddProductClick={handleAddProductClick}
|
||||||
@@ -345,7 +325,7 @@ const SalesForm = ({
|
|||||||
<div className='flex flex-col h-full justify-between items-end py-6'>
|
<div className='flex flex-col h-full justify-between items-end py-6'>
|
||||||
<span>Total Penjualan</span>
|
<span>Total Penjualan</span>
|
||||||
<span className='text-lg font-semibold'>
|
<span className='text-lg font-semibold'>
|
||||||
{formatCurrency(grandTotal)}
|
{formatCurrency(grandTotal)}{' '}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -356,6 +336,7 @@ const SalesForm = ({
|
|||||||
<Button
|
<Button
|
||||||
type='submit'
|
type='submit'
|
||||||
disabled={!formik.isValid || formik.isSubmitting}
|
disabled={!formik.isValid || formik.isSubmitting}
|
||||||
|
isLoading={formik.isSubmitting}
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
@@ -363,7 +344,12 @@ const SalesForm = ({
|
|||||||
</form>
|
</form>
|
||||||
{formType == 'edit' && (
|
{formType == 'edit' && (
|
||||||
<div className='flex flex-row justify-start'>
|
<div className='flex flex-row justify-start'>
|
||||||
<Button type='button' color='error' onClick={handleDelete}>
|
<Button
|
||||||
|
type='button'
|
||||||
|
color='error'
|
||||||
|
onClick={handleDelete}
|
||||||
|
isLoading={isLoading}
|
||||||
|
>
|
||||||
<Icon icon='mdi:trash' width={24} height={24} />
|
<Icon icon='mdi:trash' width={24} height={24} />
|
||||||
Hapus
|
Hapus
|
||||||
</Button>
|
</Button>
|
||||||
@@ -403,6 +389,7 @@ const SalesForm = ({
|
|||||||
text={`Apakah anda yakin ingin menghapus data penjualan ini?`}
|
text={`Apakah anda yakin ingin menghapus data penjualan ini?`}
|
||||||
secondaryButton={{
|
secondaryButton={{
|
||||||
text: 'Tidak',
|
text: 'Tidak',
|
||||||
|
onClick: deleteModal.closeModal,
|
||||||
}}
|
}}
|
||||||
primaryButton={{
|
primaryButton={{
|
||||||
text: 'Ya',
|
text: 'Ya',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
|
||||||
type SalesOrderProductSchemaType = {
|
type SalesOrderProductSchemaType = {
|
||||||
|
id?: number | undefined;
|
||||||
kandang_id?: number;
|
kandang_id?: number;
|
||||||
kandang?: {
|
kandang?: {
|
||||||
value: number;
|
value: number;
|
||||||
@@ -16,10 +17,13 @@ type SalesOrderProductSchemaType = {
|
|||||||
qty: string | number | undefined;
|
qty: string | number | undefined;
|
||||||
avg_weight: string | number | undefined;
|
avg_weight: string | number | undefined;
|
||||||
total_price: string | number | undefined;
|
total_price: string | number | undefined;
|
||||||
|
vehicle_number?: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SalesOrderProductSchema: Yup.ObjectSchema<SalesOrderProductSchemaType> =
|
export const SalesOrderProductSchema: Yup.ObjectSchema<SalesOrderProductSchemaType> =
|
||||||
Yup.object({
|
Yup.object({
|
||||||
|
id: Yup.number(),
|
||||||
|
vehicle_number: Yup.string().required('Nomor Kendaraan wajib diisi!'),
|
||||||
kandang: Yup.object({
|
kandang: Yup.object({
|
||||||
value: Yup.number().min(1).required(),
|
value: Yup.number().min(1).required(),
|
||||||
label: Yup.string().required(),
|
label: Yup.string().required(),
|
||||||
|
|||||||
+65
-86
@@ -4,8 +4,8 @@ import { useFormik } from 'formik';
|
|||||||
import {
|
import {
|
||||||
SalesOrderProductFormValues,
|
SalesOrderProductFormValues,
|
||||||
SalesOrderProductSchema,
|
SalesOrderProductSchema,
|
||||||
} from './SalesOrderProduct.schema';
|
} from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema';
|
||||||
import { RefObject, useEffect, useState } from 'react';
|
import { RefObject, useState } from 'react';
|
||||||
import SelectInput, {
|
import SelectInput, {
|
||||||
OptionType,
|
OptionType,
|
||||||
useSelect,
|
useSelect,
|
||||||
@@ -17,75 +17,24 @@ import { ProductWarehouseApi } from '@/services/api/inventory';
|
|||||||
import NumberInput from '@/components/input/NumberInput';
|
import NumberInput from '@/components/input/NumberInput';
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import { isResponseSuccess } from '@/lib/api-helper';
|
import { isResponseSuccess } from '@/lib/api-helper';
|
||||||
|
import { formatVechicleNumber } from '@/lib/helper';
|
||||||
|
import PatternInput from '@/components/input/PatternInput';
|
||||||
|
import Alert from '@/components/Alert';
|
||||||
|
|
||||||
const SalesOrderProductForm = ({
|
const SalesOrderProductForm = ({
|
||||||
initialValues,
|
initialValues,
|
||||||
modalRef,
|
|
||||||
onSubmitForm,
|
onSubmitForm,
|
||||||
}: {
|
}: {
|
||||||
initialValues?: SalesOrderProductFormValues;
|
initialValues?: SalesOrderProductFormValues;
|
||||||
modalRef?: RefObject<HTMLDialogElement | null>;
|
modalRef?: RefObject<HTMLDialogElement | null>;
|
||||||
onSubmitForm?: (value: SalesOrderProductFormValues) => Promise<void>;
|
onSubmitForm?: (value: SalesOrderProductFormValues) => Promise<void>;
|
||||||
}) => {
|
}) => {
|
||||||
// State
|
|
||||||
const [selectedOptionsKandang, setSelectedOptionsKandang] =
|
|
||||||
useState<OptionType | null>(null);
|
|
||||||
const [selectedOptionsWarehouse, setSelectedOptionsWarehouse] = useState<
|
|
||||||
OptionType | null | undefined
|
|
||||||
>(undefined);
|
|
||||||
const [formErrorMessage, setFormErrorMessage] = useState('');
|
const [formErrorMessage, setFormErrorMessage] = useState('');
|
||||||
|
|
||||||
// Options Data
|
|
||||||
const {
|
|
||||||
options: kandangSourceOptions,
|
|
||||||
rawData: kandangSourceRawData,
|
|
||||||
isLoadingOptions: isLoadingKandangSourceOptions,
|
|
||||||
} = useSelect<Kandang>(KandangApi.basePath, 'id', 'name');
|
|
||||||
const {
|
|
||||||
options: warehouseSourceOptions,
|
|
||||||
rawData: warehouseSourceRawData,
|
|
||||||
isLoadingOptions: isLoadingWarehouseSourceOptions,
|
|
||||||
} = useSelect<ProductWarehouse>(
|
|
||||||
ProductWarehouseApi.basePath,
|
|
||||||
'id',
|
|
||||||
'product.name',
|
|
||||||
'search',
|
|
||||||
{
|
|
||||||
warehouse_id: selectedOptionsKandang?.value?.toString() ?? '',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handler
|
|
||||||
const kandangChangeHandler = (val: OptionType | OptionType[] | null) => {
|
|
||||||
setSelectedOptionsKandang(val as OptionType);
|
|
||||||
formik.setFieldValue('kandang', val as OptionType);
|
|
||||||
formik.setFieldValue('kandang_id', (val as OptionType)?.value);
|
|
||||||
formik.setFieldValue('product_warehouse_id', null);
|
|
||||||
formik.setFieldValue('qty', null);
|
|
||||||
warehouseChangeHandler(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const warehouseChangeHandler = (val: OptionType | OptionType[] | null) => {
|
|
||||||
setSelectedOptionsWarehouse(val as OptionType);
|
|
||||||
formik.setFieldValue('product_warehouse', val as OptionType);
|
|
||||||
formik.setFieldValue('product_warehouse_id', (val as OptionType)?.value);
|
|
||||||
if (isResponseSuccess(warehouseSourceRawData)) {
|
|
||||||
const productWarehouse = warehouseSourceRawData?.data.find(
|
|
||||||
(item: ProductWarehouse) => item.id === (val as OptionType)?.value
|
|
||||||
);
|
|
||||||
if (selectedOptionsWarehouse?.value !== null) {
|
|
||||||
formik.setFieldValue('qty', productWarehouse?.quantity);
|
|
||||||
handleBlurField('qty');
|
|
||||||
} else {
|
|
||||||
formik.setFieldValue('qty', null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Formik
|
|
||||||
const formik = useFormik<SalesOrderProductFormValues>({
|
const formik = useFormik<SalesOrderProductFormValues>({
|
||||||
enableReinitialize: true,
|
enableReinitialize: true,
|
||||||
initialValues: {
|
initialValues: {
|
||||||
|
vehicle_number: initialValues?.vehicle_number || undefined,
|
||||||
kandang_id: initialValues?.kandang_id || undefined,
|
kandang_id: initialValues?.kandang_id || undefined,
|
||||||
kandang: initialValues?.kandang || undefined,
|
kandang: initialValues?.kandang || undefined,
|
||||||
product_warehouse: initialValues?.product_warehouse || undefined,
|
product_warehouse: initialValues?.product_warehouse || undefined,
|
||||||
@@ -99,34 +48,59 @@ const SalesOrderProductForm = ({
|
|||||||
validationSchema: SalesOrderProductSchema,
|
validationSchema: SalesOrderProductSchema,
|
||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
setFormErrorMessage('');
|
setFormErrorMessage('');
|
||||||
if (
|
onSubmitForm?.(values);
|
||||||
isResponseSuccess(kandangSourceRawData) &&
|
handleResetForm();
|
||||||
isResponseSuccess(warehouseSourceRawData)
|
|
||||||
) {
|
|
||||||
const productWarehouse = warehouseSourceRawData?.data.find(
|
|
||||||
(item: ProductWarehouse) => item.id === values.product_warehouse_id
|
|
||||||
);
|
|
||||||
const kandang = kandangSourceRawData?.data.find(
|
|
||||||
(item: Kandang) => item.id === values.kandang_id
|
|
||||||
);
|
|
||||||
|
|
||||||
onSubmitForm?.(values);
|
|
||||||
handleResetForm();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { setValues: formikSetValues } = formik;
|
|
||||||
|
|
||||||
useEffect(() => {
|
const {
|
||||||
formikSetValues(formik.initialValues);
|
options: kandangSourceOptions,
|
||||||
}, [formikSetValues, formik.initialValues]);
|
isLoadingOptions: isLoadingKandangSourceOptions,
|
||||||
|
} = useSelect<Kandang>(KandangApi.basePath, 'id', 'name');
|
||||||
|
|
||||||
|
const {
|
||||||
|
options: warehouseSourceOptions,
|
||||||
|
rawData: warehouseSourceRawData,
|
||||||
|
isLoadingOptions: isLoadingWarehouseSourceOptions,
|
||||||
|
} = useSelect<ProductWarehouse>(
|
||||||
|
ProductWarehouseApi.basePath,
|
||||||
|
'id',
|
||||||
|
'product.name',
|
||||||
|
'search',
|
||||||
|
{
|
||||||
|
warehouse_id: formik.values.kandang_id?.toString() ?? '',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const kandangChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
|
formik.setFieldValue('kandang', val as OptionType);
|
||||||
|
formik.setFieldValue('kandang_id', (val as OptionType)?.value);
|
||||||
|
formik.setFieldValue('product_warehouse_id', null);
|
||||||
|
formik.setFieldValue('product_warehouse', null);
|
||||||
|
formik.setFieldValue('qty', null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const warehouseChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
|
formik.setFieldValue('product_warehouse', val as OptionType);
|
||||||
|
const newId = (val as OptionType)?.value;
|
||||||
|
formik.setFieldValue('product_warehouse_id', newId);
|
||||||
|
|
||||||
|
if (isResponseSuccess(warehouseSourceRawData) && newId) {
|
||||||
|
const productWarehouse = warehouseSourceRawData?.data.find(
|
||||||
|
(item: ProductWarehouse) => item.id === newId
|
||||||
|
);
|
||||||
|
formik.setFieldValue('qty', productWarehouse?.quantity);
|
||||||
|
handleBlurField('qty');
|
||||||
|
} else {
|
||||||
|
formik.setFieldValue('qty', null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleResetForm = () => {
|
const handleResetForm = () => {
|
||||||
setSelectedOptionsKandang(null);
|
|
||||||
setSelectedOptionsWarehouse(null);
|
|
||||||
setFormErrorMessage('');
|
setFormErrorMessage('');
|
||||||
formik.resetForm({
|
formik.resetForm({
|
||||||
values: {
|
values: {
|
||||||
|
vehicle_number: '',
|
||||||
kandang_id: undefined,
|
kandang_id: undefined,
|
||||||
kandang: null,
|
kandang: null,
|
||||||
product_warehouse: null,
|
product_warehouse: null,
|
||||||
@@ -145,7 +119,7 @@ const SalesOrderProductForm = ({
|
|||||||
formik.values;
|
formik.values;
|
||||||
|
|
||||||
if (field === 'unit_price' || field === 'total_price' || field === 'qty') {
|
if (field === 'unit_price' || field === 'total_price' || field === 'qty') {
|
||||||
if (qty && unit_price && field === 'unit_price') {
|
if (qty && unit_price && (field === 'unit_price' || field === 'qty')) {
|
||||||
formik.setFieldValue(
|
formik.setFieldValue(
|
||||||
'total_price',
|
'total_price',
|
||||||
(qty as number) * (unit_price as number)
|
(qty as number) * (unit_price as number)
|
||||||
@@ -159,7 +133,7 @@ const SalesOrderProductForm = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (field === 'avg_weight' || field === 'total_weight' || field === 'qty') {
|
if (field === 'avg_weight' || field === 'total_weight' || field === 'qty') {
|
||||||
if (qty && avg_weight && field === 'avg_weight') {
|
if (qty && avg_weight && (field === 'avg_weight' || field === 'qty')) {
|
||||||
formik.setFieldValue(
|
formik.setFieldValue(
|
||||||
'total_weight',
|
'total_weight',
|
||||||
(qty as number) * (avg_weight as number)
|
(qty as number) * (avg_weight as number)
|
||||||
@@ -180,8 +154,15 @@ const SalesOrderProductForm = ({
|
|||||||
onSubmit={formik.handleSubmit}
|
onSubmit={formik.handleSubmit}
|
||||||
onReset={handleResetForm}
|
onReset={handleResetForm}
|
||||||
>
|
>
|
||||||
|
{formErrorMessage && (
|
||||||
|
<div onClick={() => setFormErrorMessage('')} className='my-3 w-full'>
|
||||||
|
<Alert color='error'>
|
||||||
|
{formErrorMessage ? formErrorMessage : ''}
|
||||||
|
</Alert>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className='grid grid-cols-2 gap-4 z-200'>
|
<div className='grid grid-cols-2 gap-4 z-200'>
|
||||||
{/* <PatternInput
|
<PatternInput
|
||||||
name='vehicle_number'
|
name='vehicle_number'
|
||||||
label='No. Polisi'
|
label='No. Polisi'
|
||||||
format='AA #### AAA'
|
format='AA #### AAA'
|
||||||
@@ -198,16 +179,15 @@ const SalesOrderProductForm = ({
|
|||||||
Boolean(formik.errors.vehicle_number)
|
Boolean(formik.errors.vehicle_number)
|
||||||
}
|
}
|
||||||
errorMessage={formik.errors.vehicle_number}
|
errorMessage={formik.errors.vehicle_number}
|
||||||
/> */}
|
/>
|
||||||
<SelectInput
|
<SelectInput
|
||||||
required
|
required
|
||||||
label='Kandang'
|
label='Kandang'
|
||||||
options={kandangSourceOptions}
|
options={kandangSourceOptions}
|
||||||
isLoading={isLoadingKandangSourceOptions}
|
isLoading={isLoadingKandangSourceOptions}
|
||||||
value={selectedOptionsKandang}
|
value={formik.values.kandang}
|
||||||
onChange={kandangChangeHandler}
|
onChange={kandangChangeHandler}
|
||||||
isClearable
|
isClearable
|
||||||
menuPortalTarget={modalRef?.current}
|
|
||||||
isError={
|
isError={
|
||||||
formik.touched.kandang_id && Boolean(formik.errors.kandang_id)
|
formik.touched.kandang_id && Boolean(formik.errors.kandang_id)
|
||||||
}
|
}
|
||||||
@@ -219,12 +199,11 @@ const SalesOrderProductForm = ({
|
|||||||
label='Produk'
|
label='Produk'
|
||||||
options={warehouseSourceOptions}
|
options={warehouseSourceOptions}
|
||||||
isLoading={isLoadingWarehouseSourceOptions}
|
isLoading={isLoadingWarehouseSourceOptions}
|
||||||
value={selectedOptionsWarehouse}
|
value={formik.values.product_warehouse}
|
||||||
onChange={warehouseChangeHandler}
|
onChange={warehouseChangeHandler}
|
||||||
isClearable
|
isClearable
|
||||||
menuPortalTarget={modalRef?.current}
|
|
||||||
placeholder='Pilih Kandang Terlebih Dahulu'
|
placeholder='Pilih Kandang Terlebih Dahulu'
|
||||||
isDisabled={!selectedOptionsKandang?.value}
|
isDisabled={!formik.values.kandang_id}
|
||||||
isError={
|
isError={
|
||||||
formik.touched.product_warehouse_id &&
|
formik.touched.product_warehouse_id &&
|
||||||
Boolean(formik.errors.product_warehouse_id)
|
Boolean(formik.errors.product_warehouse_id)
|
||||||
|
|||||||
@@ -3,39 +3,38 @@
|
|||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import { SalesOrderProductFormValues } from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema';
|
import { SalesOrderProductFormValues } from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema';
|
||||||
import { cn, formatCurrency, formatNumber } from '@/lib/helper';
|
import {
|
||||||
|
cn,
|
||||||
|
formatCurrency,
|
||||||
|
formatNumber,
|
||||||
|
formatVechicleNumber,
|
||||||
|
} from '@/lib/helper';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import * as TanStack from '@tanstack/react-table';
|
import * as TanStack from '@tanstack/react-table';
|
||||||
import CheckboxInput from '@/components/input/CheckboxInput';
|
import CheckboxInput from '@/components/input/CheckboxInput';
|
||||||
|
|
||||||
// Hapus import Modal, useModal, dan MarketingProductForm
|
|
||||||
|
|
||||||
// Tentukan Tipe Props baru yang diterima dari SalesForm
|
|
||||||
type SalesOrderProductTableProps = {
|
type SalesOrderProductTableProps = {
|
||||||
data: SalesOrderProductFormValues[];
|
data: SalesOrderProductFormValues[];
|
||||||
onDelete: (product_warehouse_id: number, kandang_id: number) => void;
|
rowSelection: Record<string, boolean>;
|
||||||
onBulkDelete: (selectedIds: number[]) => void;
|
setRowSelection: React.Dispatch<
|
||||||
onAddProductClick: () => void; // Prop baru untuk memanggil modal di parent
|
React.SetStateAction<Record<string, boolean>>
|
||||||
|
>;
|
||||||
|
selectedRowIds: number[];
|
||||||
|
onDelete: (id: number) => void;
|
||||||
|
onBulkDelete: () => void;
|
||||||
|
onAddProductClick: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SalesOrderProductTable = ({
|
const SalesOrderProductTable = ({
|
||||||
data,
|
data,
|
||||||
|
rowSelection,
|
||||||
|
setRowSelection,
|
||||||
|
selectedRowIds,
|
||||||
onDelete,
|
onDelete,
|
||||||
onBulkDelete,
|
onBulkDelete,
|
||||||
onAddProductClick,
|
onAddProductClick,
|
||||||
}: SalesOrderProductTableProps) => {
|
}: SalesOrderProductTableProps) => {
|
||||||
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
|
|
||||||
|
|
||||||
const selectedRowIds = Object.keys(rowSelection).map((item) =>
|
|
||||||
parseInt(item)
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleBulkDeleteClick = () => {
|
|
||||||
onBulkDelete(selectedRowIds);
|
|
||||||
setRowSelection({});
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
@@ -67,6 +66,11 @@ const SalesOrderProductTable = ({
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessorFn: (row: SalesOrderProductFormValues) =>
|
||||||
|
formatVechicleNumber(row.vehicle_number as string),
|
||||||
|
header: 'No. Polisi',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (row: SalesOrderProductFormValues) => row.kandang?.label,
|
accessorFn: (row: SalesOrderProductFormValues) => row.kandang?.label,
|
||||||
header: 'Kandang',
|
header: 'Kandang',
|
||||||
@@ -110,22 +114,10 @@ const SalesOrderProductTable = ({
|
|||||||
<Button
|
<Button
|
||||||
color='error'
|
color='error'
|
||||||
className='p-1'
|
className='p-1'
|
||||||
disabled={
|
|
||||||
!props.row.original.product_warehouse_id ||
|
|
||||||
!props.row.original.kandang_id
|
|
||||||
}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// PANGGIL CALLBACK PARENT (onDelete)
|
onDelete(props.row.original.id as number);
|
||||||
if (
|
|
||||||
props.row.original.product_warehouse_id &&
|
|
||||||
props.row.original.kandang_id
|
|
||||||
) {
|
|
||||||
onDelete(
|
|
||||||
props.row.original.product_warehouse_id,
|
|
||||||
props.row.original.kandang_id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
|
type='button'
|
||||||
>
|
>
|
||||||
<Icon icon='mdi:trash' width={16} height={16} />
|
<Icon icon='mdi:trash' width={16} height={16} />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -180,7 +172,7 @@ const SalesOrderProductTable = ({
|
|||||||
variant='outline'
|
variant='outline'
|
||||||
color='error'
|
color='error'
|
||||||
className='justify-start w-fit py-1 text-sm'
|
className='justify-start w-fit py-1 text-sm'
|
||||||
onClick={handleBulkDeleteClick}
|
onClick={onBulkDelete}
|
||||||
>
|
>
|
||||||
<Icon icon='mdi:trash' width={16} height={16} />
|
<Icon icon='mdi:trash' width={16} height={16} />
|
||||||
Hapus
|
Hapus
|
||||||
@@ -191,8 +183,6 @@ const SalesOrderProductTable = ({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Modal dan Form dihapus dari sini */}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ export const dummyProductWarehouses: ProductWarehouse[] = [
|
|||||||
|
|
||||||
// Helper untuk Sales Order (SO) Item
|
// Helper untuk Sales Order (SO) Item
|
||||||
const soItem1: BaseSalesOrder = {
|
const soItem1: BaseSalesOrder = {
|
||||||
|
vehicle_number: 'B 1234 ABC',
|
||||||
id: 101,
|
id: 101,
|
||||||
marketing_id: 1,
|
marketing_id: 1,
|
||||||
product_warehouse_id: 1,
|
product_warehouse_id: 1,
|
||||||
@@ -222,6 +223,7 @@ const soItem1: BaseSalesOrder = {
|
|||||||
product_warehouse: dummyProductWarehouses[0] as ProductWarehouse,
|
product_warehouse: dummyProductWarehouses[0] as ProductWarehouse,
|
||||||
};
|
};
|
||||||
const soItem2: BaseSalesOrder = {
|
const soItem2: BaseSalesOrder = {
|
||||||
|
vehicle_number: 'D 5678 EFG',
|
||||||
id: 102,
|
id: 102,
|
||||||
marketing_id: 2,
|
marketing_id: 2,
|
||||||
product_warehouse_id: 2,
|
product_warehouse_id: 2,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const createDummyResponse = <T>(data: T): BaseApiResponse<T> => ({
|
|||||||
data: data,
|
data: data,
|
||||||
});
|
});
|
||||||
|
|
||||||
export class MarketingService extends BaseApiService<
|
export class SalesOrderService extends BaseApiService<
|
||||||
Marketing,
|
Marketing,
|
||||||
CreateSalesOrderPayload,
|
CreateSalesOrderPayload,
|
||||||
UpdateSalesOrderPayload
|
UpdateSalesOrderPayload
|
||||||
@@ -29,40 +29,40 @@ export class MarketingService extends BaseApiService<
|
|||||||
super(basePath);
|
super(basePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Override: Mengambil semua data Marketing dari dummyMarketings
|
// * Override: Mengambil semua data Marketing dari dummyMarketings
|
||||||
*/
|
// */
|
||||||
async getAllFetcher(endpoint: string): Promise<BaseApiResponse<Marketing[]>> {
|
// async getAllFetcher(endpoint: string): Promise<BaseApiResponse<Marketing[]>> {
|
||||||
// Simulasi delay jaringan
|
// // Simulasi delay jaringan
|
||||||
await sleep(500);
|
// await sleep(500);
|
||||||
|
|
||||||
// Filter data marketing yang valid (jika menggunakan BaseMarketing[])
|
// // Filter data marketing yang valid (jika menggunakan BaseMarketing[])
|
||||||
const data = dummyMarketings as Marketing[];
|
// const data = dummyMarketings as Marketing[];
|
||||||
|
|
||||||
return createDummyResponse<Marketing[]>(data);
|
// return createDummyResponse<Marketing[]>(data);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Override: Mengambil satu data Marketing berdasarkan ID dari dummyMarketings
|
// * Override: Mengambil satu data Marketing berdasarkan ID dari dummyMarketings
|
||||||
*/
|
// */
|
||||||
async getSingle(id: number): Promise<BaseApiResponse<Marketing> | undefined> {
|
// async getSingle(id: number): Promise<BaseApiResponse<Marketing> | undefined> {
|
||||||
// Simulasi delay jaringan
|
// // Simulasi delay jaringan
|
||||||
await sleep(300);
|
// await sleep(300);
|
||||||
|
|
||||||
const foundData = dummyMarketings.find((m) => m.id == id);
|
// const foundData = dummyMarketings.find((m) => m.id == id);
|
||||||
|
|
||||||
if (foundData) {
|
// if (foundData) {
|
||||||
// Data ditemukan, kembalikan respons sukses
|
// // Data ditemukan, kembalikan respons sukses
|
||||||
return createDummyResponse<Marketing>(foundData as Marketing);
|
// return createDummyResponse<Marketing>(foundData as Marketing);
|
||||||
} else {
|
// } else {
|
||||||
// Data tidak ditemukan, simulasi respons error
|
// // Data tidak ditemukan, simulasi respons error
|
||||||
return {
|
// return {
|
||||||
code: 404,
|
// code: 404,
|
||||||
status: 'error',
|
// status: 'error',
|
||||||
message: 'Marketing data not found (MOCK)',
|
// message: 'Marketing data not found (MOCK)',
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Approve single marketing data
|
* Approve single marketing data
|
||||||
@@ -111,4 +111,7 @@ export class MarketingService extends BaseApiService<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MarketingApi = new MarketingService('/marketing/sales-orders');
|
export const SalesOrderApi = new SalesOrderService('/marketing/sales-orders');
|
||||||
|
export const MarketingApi = new BaseApiService<Marketing, unknown, unknown>(
|
||||||
|
'/marketing'
|
||||||
|
);
|
||||||
|
|||||||
+1
@@ -35,6 +35,7 @@ export type BaseSalesOrder = {
|
|||||||
total_weight: number;
|
total_weight: number;
|
||||||
total_price: number;
|
total_price: number;
|
||||||
product_warehouse: ProductWarehouse;
|
product_warehouse: ProductWarehouse;
|
||||||
|
vehicle_number: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BaseDeliveryOrder = {
|
export type BaseDeliveryOrder = {
|
||||||
|
|||||||
Reference in New Issue
Block a user