From cb22fd1037ed29b467516bb5e46bbf894c2ca0eb Mon Sep 17 00:00:00 2001 From: randy-ar Date: Thu, 5 Feb 2026 04:41:46 +0700 Subject: [PATCH] feat(FE): calculation penjualan telur + peti --- .../pages/marketing/SalesOrderFormModal.tsx | 3 - .../marketing/form/MarketingForm.schema.ts | 14 ++- .../sales-order/SalesOrderProduct.schema.ts | 11 -- .../sales-order/SalesOrderProductForm.tsx | 87 ++++++++++++--- .../table-view/SalesOrderProductTable.tsx | 2 +- src/lib/marketing-calculation.ts | 100 ++++++++++++++---- src/types/api/marketing/marketing.d.ts | 2 + 7 files changed, 166 insertions(+), 53 deletions(-) diff --git a/src/components/pages/marketing/SalesOrderFormModal.tsx b/src/components/pages/marketing/SalesOrderFormModal.tsx index 5c08810e..6fca2b2f 100644 --- a/src/components/pages/marketing/SalesOrderFormModal.tsx +++ b/src/components/pages/marketing/SalesOrderFormModal.tsx @@ -14,8 +14,6 @@ import { DeliveryProductToFieldValues, mergeSOwithDO, SalesProductToFieldValues, -} from '@/components/pages/marketing/form/MarketingForm'; -import { DeliveryOrderFormValues, DeliveryOrderSchema, getFilledMarketingFormInitialValues, @@ -210,7 +208,6 @@ const SalesOrderFormModal = ({ convertion_unit: normalizedConvertionUnit, weight_per_convertion: product.weight_per_convertion ?? undefined, - week: product.weeks?.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 188fbf20..15bffaec 100644 --- a/src/components/pages/marketing/form/MarketingForm.schema.ts +++ b/src/components/pages/marketing/form/MarketingForm.schema.ts @@ -94,7 +94,7 @@ export type SalesOrderFormValues = Yup.InferType; export type DeliveryOrderFormValues = Yup.InferType; // ================ Helper Function ================ -const SalesProductToFieldValues = ( +export const SalesProductToFieldValues = ( product: BaseSalesOrder ): SalesOrderProductFormValues => { return { @@ -123,9 +123,11 @@ const SalesProductToFieldValues = ( value: product.convertion_unit, label: formatTitleCase(product.convertion_unit), }, + total_peti: product.total_peti, + weight_per_convertion: product.weight_per_convertion, }; }; -const DeliveryProductToFieldValues = ( +export const DeliveryProductToFieldValues = ( salesOrders: BaseSalesOrder[], delivery: BaseDeliveryOrder ): DeliveryOrderProductFormValues[] => { @@ -221,3 +223,11 @@ export const getFilledMarketingFormInitialValues = ( ), }; }; + +export const getPricePerConvertion = ( + totalPrice: number, + weightPerConvertion: number, + totalPeti: number +) => { + return totalPrice / (weightPerConvertion * totalPeti); +}; 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 33028e69..752fdd0c 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,10 +34,6 @@ type SalesOrderProductSchemaType = { price_sisa_berat?: number | null | undefined; /** Harga per butir telur untuk TELUR + QTY */ price_per_qty?: number | null | undefined; - weeks?: { - value: number; - label: string; - } | null; }; export const SalesOrderProductSchema: Yup.ObjectSchema = @@ -92,13 +88,6 @@ export const SalesOrderProductSchema: Yup.ObjectSchema(''); const [selectedProductWarehouse, setSelectedProductWarehouse] = useState(null); - const [hasSisaBerat, setHasSisaBerat] = useState(false); + + // Check jika ada sisa berat = total_weight - (weight_per_convertion * total_peti) + const initialSisaBerat = + initialValues?.total_weight && + initialValues?.weight_per_convertion && + initialValues?.total_peti + ? Number(initialValues.total_weight) - + Number(initialValues.weight_per_convertion) * + Number(initialValues.total_peti) + : 0; + + const initialPricePerConvertion = + initialValues?.total_price && + initialValues?.total_peti && + Number(initialValues.total_peti) !== 0 + ? (Number(initialValues.total_price) - + initialSisaBerat * Number(initialValues.unit_price || 0)) / + Number(initialValues.total_peti) + : 0; + + const initialPriceSisaBerat = + Number(initialValues?.total_price) - + initialPricePerConvertion * Number(initialValues?.total_peti); + + const [hasSisaBerat, setHasSisaBerat] = useState( + initialSisaBerat > 0 + ); // ============ Formik ============ const formik = useFormik({ @@ -70,11 +96,13 @@ const SalesOrderProductForm = ({ initialValues?.weight_per_convertion != null ? Number(initialValues.weight_per_convertion) : null, + price_per_convertion: initialPricePerConvertion, convertion_unit: initialValues?.convertion_unit || null, marketing_type: initialValues?.marketing_type || null, total_peti: initialValues?.total_peti ?? null, - weeks: initialValues?.weeks || null, price_per_qty: initialValues?.price_per_qty ?? null, + sisa_berat: initialSisaBerat, + price_sisa_berat: initialPriceSisaBerat, }, validationSchema: SalesOrderProductSchema, onSubmit: async (values) => { @@ -168,6 +196,15 @@ const SalesOrderProductForm = ({ qty: '', avg_weight: '', total_price: '', + total_peti: null, + price_per_qty: null, + price_sisa_berat: null, + sisa_berat: null, + convertion_unit: null, + marketing_type: null, + weight_per_convertion: null, + price_per_convertion: null, + uom: '', }, }); }; @@ -182,6 +219,28 @@ const SalesOrderProductForm = ({ }); }; + // Handler khusus untuk toggle sisa berat - langsung pakai nilai baru + const handleSisaBeratToggle = (newHasSisaBerat: boolean) => { + setHasSisaBerat(newHasSisaBerat); + + if (!newHasSisaBerat) { + // Ketika OFF - set nilai ke 0 dan recalculate tanpa sisa + formik.setFieldValue('sisa_berat', 0); + formik.setFieldValue('price_sisa_berat', 0); + } + + // Langsung trigger recalculation dengan hasSisaBerat yang baru + handleMarketingCalculation('total_peti', { + values: { + ...formik.values, + sisa_berat: newHasSisaBerat ? formik.values.sisa_berat : 0, + price_sisa_berat: newHasSisaBerat ? formik.values.price_sisa_berat : 0, + }, + setFieldValue: formik.setFieldValue, + hasSisaBerat: newHasSisaBerat, + }); + }; + // ===== Formik Error List ===== const { formErrorList, close, handleFormSubmit } = useFormikErrorList( formik, @@ -314,7 +373,7 @@ const SalesOrderProductForm = ({ /> )} {formik.values.convertion_unit && - formik.values.convertion_unit.value === 'peti' && ( + formik.values.convertion_unit.value.toLowerCase() === 'peti' && (
)} {/* Konversi Satuan Weeks Pullet */} - {formik.values.marketing_type?.value.toLowerCase() === + {/* {formik.values.marketing_type?.value.toLowerCase() === 'ayam_pullet' && ( { formik.setFieldValue('weeks', val); }} placeholder='Pilih Weeks' /> - )} + )} */} {/* Total Peti */} - {formik.values.convertion_unit?.value === 'peti' && ( + {formik.values.convertion_unit?.value.toLowerCase() === 'peti' && ( { formik.handleChange(e); @@ -429,7 +489,7 @@ const SalesOrderProductForm = ({ Kg } - bottomLabel={`1 ${formik.values.convertion_unit?.value} = ${formik.values.weight_per_convertion ?? 0} Kg`} + bottomLabel={`1 ${formik.values.convertion_unit?.value.toLowerCase()} = ${formik.values.weight_per_convertion ?? 0} Kg`} /> )} @@ -586,12 +646,9 @@ const SalesOrderProductForm = ({
{ - setHasSisaBerat(!hasSisaBerat); - }} - onBlur={() => handleBlurField('sisa_berat')} + onChange={() => handleSisaBeratToggle(!hasSisaBerat)} className='toggle toggle-primary rounded-full before:rounded-full before:bg-base-content/50 border-base-content/50 checked:border-primary checked:bg-primary checked:before:bg-base-100' />