From 43dcbf73eea84dbe410b3b863da937e400ab123f Mon Sep 17 00:00:00 2001 From: randy-ar Date: Thu, 5 Feb 2026 05:38:02 +0700 Subject: [PATCH] feat(FE): adding 4 input scenario marketing type --- .../pages/marketing/SalesOrderFormModal.tsx | 1 + .../marketing/form/MarketingForm.schema.ts | 26 +++++--- .../sales-order/SalesOrderProduct.schema.ts | 30 +++++++++ .../sales-order/SalesOrderProductForm.tsx | 36 +++++++---- .../table-view/SalesOrderProductTable.tsx | 64 +++++++++++-------- src/lib/marketing-calculation.ts | 18 +++--- src/types/api/marketing/marketing.d.ts | 13 +--- 7 files changed, 123 insertions(+), 65 deletions(-) diff --git a/src/components/pages/marketing/SalesOrderFormModal.tsx b/src/components/pages/marketing/SalesOrderFormModal.tsx index 6fca2b2f..cba86c6f 100644 --- a/src/components/pages/marketing/SalesOrderFormModal.tsx +++ b/src/components/pages/marketing/SalesOrderFormModal.tsx @@ -208,6 +208,7 @@ const SalesOrderFormModal = ({ convertion_unit: normalizedConvertionUnit, weight_per_convertion: product.weight_per_convertion ?? undefined, + week: product.week?.value ?? undefined, } as CreateSalesOrderProductPayload; }), } as CreateSalesOrderPayload) diff --git a/src/components/pages/marketing/form/MarketingForm.schema.ts b/src/components/pages/marketing/form/MarketingForm.schema.ts index 15bffaec..4f97bfa6 100644 --- a/src/components/pages/marketing/form/MarketingForm.schema.ts +++ b/src/components/pages/marketing/form/MarketingForm.schema.ts @@ -115,14 +115,24 @@ export const SalesProductToFieldValues = ( qty: product.qty, avg_weight: product.avg_weight, total_price: product.total_price, - marketing_type: { - value: product.marketing_type, - label: formatTitleCase(product.marketing_type), - }, - convertion_unit: { - value: product.convertion_unit, - label: formatTitleCase(product.convertion_unit), - }, + marketing_type: product.marketing_type + ? { + value: product.marketing_type, + label: formatTitleCase(product.marketing_type), + } + : null, + convertion_unit: product.convertion_unit + ? { + value: product.convertion_unit, + label: formatTitleCase(product.convertion_unit), + } + : null, + week: product.week + ? { + value: product.week, + label: `Week ${product.week}`, + } + : null, total_peti: product.total_peti, weight_per_convertion: product.weight_per_convertion, }; diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema.ts b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema.ts index 752fdd0c..d58fb48c 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema.ts +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema.ts @@ -34,6 +34,14 @@ type SalesOrderProductSchemaType = { price_sisa_berat?: number | null | undefined; /** Harga per butir telur untuk TELUR + QTY */ price_per_qty?: number | null | undefined; + /** Week untuk ayam pullet */ + week?: + | { + value?: number; + label?: string; + } + | null + | undefined; }; export const SalesOrderProductSchema: Yup.ObjectSchema = @@ -88,6 +96,28 @@ export const SalesOrderProductSchema: Yup.ObjectSchema + marketingType?.value?.toLowerCase() === 'ayam_pullet', + then: (schema) => + schema + .shape({ + value: Yup.number().required( + 'Week wajib diisi untuk Ayam Pullet!' + ), + label: Yup.string().required( + 'Week wajib diisi untuk Ayam Pullet!' + ), + }) + .required('Week wajib diisi untuk Ayam Pullet!'), + otherwise: (schema) => schema.optional().notRequired(), + }), }); export type SalesOrderProductFormValues = Yup.InferType< diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx index c6bb309e..63a88c04 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx @@ -70,8 +70,10 @@ const SalesOrderProductForm = ({ : 0; const initialPriceSisaBerat = - Number(initialValues?.total_price) - - initialPricePerConvertion * Number(initialValues?.total_peti); + initialValues?.total_price && initialValues?.total_peti + ? Number(initialValues.total_price) - + initialPricePerConvertion * Number(initialValues.total_peti) + : 0; const [hasSisaBerat, setHasSisaBerat] = useState( initialSisaBerat > 0 @@ -103,6 +105,7 @@ const SalesOrderProductForm = ({ price_per_qty: initialValues?.price_per_qty ?? null, sisa_berat: initialSisaBerat, price_sisa_berat: initialPriceSisaBerat, + week: initialValues?.week ?? null, }, validationSchema: SalesOrderProductSchema, onSubmit: async (values) => { @@ -122,11 +125,11 @@ const SalesOrderProductForm = ({ loadMore: loadMoreKandang, } = useSelect(WarehouseApi.basePath, 'id', 'name'); - // Options Weeks dari minggu 1 - 22 - const optionsWeeks = useMemo(() => { + // Options Week dari minggu 1 - 22 + const optionsWeek = useMemo(() => { return Array.from({ length: 22 }, (_, i) => ({ value: i + 1, - label: `Weeks ${i + 1}`, + label: `Week ${i + 1}`, })); }, []); @@ -205,6 +208,7 @@ const SalesOrderProductForm = ({ weight_per_convertion: null, price_per_convertion: null, uom: '', + week: null, }, }); }; @@ -256,6 +260,10 @@ const SalesOrderProductForm = ({ } ); + useEffect(() => { + handleBlurField('week'); + }, [formik.values.week]); + return ( <>
)} - {/* Konversi Satuan Weeks Pullet */} - {/* {formik.values.marketing_type?.value.toLowerCase() === + {/* Konversi Satuan Week Pullet */} + {formik.values.marketing_type?.value.toLowerCase() === 'ayam_pullet' && ( { - formik.setFieldValue('weeks', val); + formik.setFieldValue('week', val); }} - placeholder='Pilih Weeks' + placeholder='Pilih Week' /> - )} */} + )} {/* Total Peti */} {formik.values.convertion_unit?.value.toLowerCase() === 'peti' && ( diff --git a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx index 64d8f35f..6f667f76 100644 --- a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx @@ -222,12 +222,21 @@ const SalesOrderProductTable = ({ {item.product_warehouse?.label} - - Tipe Konversi - - {item.convertion_unit?.label} - - + {item.marketing_type?.value.toLowerCase() === 'telur' && ( + + Tipe Konversi + + {item.convertion_unit?.label} + + + )} + {item.marketing_type?.value.toLowerCase() === + 'ayam_pullet' && ( + + Tipe Konversi + {item.week?.label} + + )} {item.convertion_unit?.value.toLowerCase() === 'peti' && ( Total Peti @@ -236,25 +245,30 @@ const SalesOrderProductTable = ({ )} - - Total Bobot - - {item.total_weight - ? formatNumber( - parseFloat(item.total_weight as string) - ) + ' Kg' - : '-'} - - - - Avg Bobot - - {item.avg_weight - ? formatNumber(parseFloat(item.avg_weight as string)) + - ' Kg' - : '-'} - - + {item.marketing_type?.value.toLowerCase() !== 'trading' && ( + <> + + Total Bobot + + {item.total_weight + ? formatNumber( + parseFloat(item.total_weight as string) + ) + ' Kg' + : '0 Kg'} + + + + Avg Bobot + + {item.avg_weight + ? formatNumber( + parseFloat(item.avg_weight as string) + ) + ' Kg' + : '0 Kg'} + + + + )} {item.marketing_type?.value === 'telur' diff --git a/src/lib/marketing-calculation.ts b/src/lib/marketing-calculation.ts index 931551f0..5715ec88 100644 --- a/src/lib/marketing-calculation.ts +++ b/src/lib/marketing-calculation.ts @@ -15,7 +15,7 @@ export type MarketingFormValues = { total_price?: string | number; marketing_type?: { value: string; label: string } | null; convertion_unit?: { value: string; label: string } | null; - weeks?: { value: number; label: string } | null; + week?: { value?: number; label?: string } | null; weight_per_convertion?: number | null; price_per_convertion?: number | null; total_peti?: number | null; @@ -100,7 +100,7 @@ export const calculateAyamPullet = ( ): void => { const { values, setFieldValue } = ctx; const unitPrice = Number(values.unit_price || 0); - const weeks = Number(values.weeks?.value || 0); + const week = Number(values.week?.value || 0); const qty = Number(values.qty || 0); const avgWeight = Number(values.avg_weight || 0); const totalWeight = Number(values.total_weight || 0); @@ -108,11 +108,11 @@ export const calculateAyamPullet = ( switch (field) { case 'unit_price': - case 'weeks': + case 'week': case 'qty': { - // total_price = unit_price × weeks × qty - if (unitPrice > 0 && weeks > 0 && qty > 0) { - setFieldValue('total_price', roundPrice(unitPrice * weeks * qty)); + // total_price = unit_price × week × qty + if (unitPrice > 0 && week > 0 && qty > 0) { + setFieldValue('total_price', roundPrice(unitPrice * week * qty)); } // total_weight = avg_weight × qty if (avgWeight > 0 && qty > 0) { @@ -133,9 +133,9 @@ export const calculateAyamPullet = ( break; } case 'total_price': { - // Reverse: unit_price = total_price / (weeks × qty) - if (totalPrice > 0 && weeks > 0 && qty > 0) { - setFieldValue('unit_price', roundPrice(totalPrice / (weeks * qty))); + // Reverse: unit_price = total_price / (week × qty) + if (totalPrice > 0 && week > 0 && qty > 0) { + setFieldValue('unit_price', roundPrice(totalPrice / (week * qty))); } break; } diff --git a/src/types/api/marketing/marketing.d.ts b/src/types/api/marketing/marketing.d.ts index b063058d..80a0b90b 100644 --- a/src/types/api/marketing/marketing.d.ts +++ b/src/types/api/marketing/marketing.d.ts @@ -40,6 +40,8 @@ export type BaseSalesOrder = { convertion_unit: string; total_peti: number; weight_per_convertion: number; + /** Umur minggu untuk AYAM_PULLET */ + week?: number; }; export type BaseDeliveryOrder = { @@ -115,17 +117,6 @@ export type BaseCreateMarketingProductPayload = { avg_weight: string | number | undefined; total_price: string | number | undefined; marketing_type: string; - /** - * Tipe konversi untuk TELUR - * - "PETI": Penjualan telur dalam satuan peti - * - "KG": Penjualan telur dalam satuan kilogram - * - * Note: Untuk mode "QTY" di FE, tetap kirim "KG" ke BE dengan unit_price yang dinormalisasi - * karena BE tidak support convertion_unit "QTY". Workaround: - * - FE hitung: total_price = qty × price_per_qty - * - FE normalisasi: unit_price = total_price / total_weight - * - BE akan hitung: total_price = total_weight × unit_price (hasil sama) - */ convertion_unit?: 'PETI' | 'KG'; /** Berat per peti (kg), hanya untuk TELUR + PETI */ weight_per_convertion?: number;