diff --git a/.husky/pre-commit b/.husky/pre-commit index ac8a41c7..f799d12f 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1,3 @@ npm run format npm run lint -npm run typecheck +npm run typecheck \ No newline at end of file diff --git a/src/components/pages/marketing/DeliveryOrderFormModal.tsx b/src/components/pages/marketing/DeliveryOrderFormModal.tsx index eb488285..d6ace126 100644 --- a/src/components/pages/marketing/DeliveryOrderFormModal.tsx +++ b/src/components/pages/marketing/DeliveryOrderFormModal.tsx @@ -199,6 +199,9 @@ const DeliveryOrderFormModal = ({}: { initialValues?: Marketing }) => { 'yyyy-MM-DD' ), vehicle_number: product.vehicle_number, + weight_per_convertion: parseFloat( + String(product.weight_per_convertion ?? 0) + ), }; } }) @@ -432,6 +435,9 @@ const DeliveryOrderFormModal = ({}: { initialValues?: Marketing }) => { 'yyyy-MM-DD' ), vehicle_number: product.vehicle_number, + weight_per_convertion: parseFloat( + String(product.weight_per_convertion ?? 0) + ), }; } }) diff --git a/src/components/pages/marketing/form/MarketingForm.schema.ts b/src/components/pages/marketing/form/MarketingForm.schema.ts index e34fab4e..f9a3c476 100644 --- a/src/components/pages/marketing/form/MarketingForm.schema.ts +++ b/src/components/pages/marketing/form/MarketingForm.schema.ts @@ -151,6 +151,25 @@ export const DeliveryProductToFieldValues = ( value: item.product_warehouse.warehouse.id, label: item.product_warehouse.warehouse.name, }; + + const initialSisaBerat = + item?.total_weight && + salesOrder?.weight_per_convertion && + salesOrder?.total_peti + ? Number(item.total_weight) - + Number(salesOrder.weight_per_convertion) * + Number(salesOrder.total_peti) + : 0; + + const initialPricePerConvertion = + item?.total_price && + salesOrder?.total_peti && + Number(salesOrder.total_peti) !== 0 + ? (Number(item.total_price) - + initialSisaBerat * Number(item.unit_price || 0)) / + Number(salesOrder.total_peti) + : Number(item?.unit_price || 0); + return { id: salesOrder?.id, unit_price: item.unit_price, @@ -193,6 +212,10 @@ export const DeliveryProductToFieldValues = ( avg_weight: item.avg_weight, total_price: item.total_price, }, + total_peti: salesOrder?.total_peti, + weight_per_convertion: + item?.weight_per_convertion ?? salesOrder?.weight_per_convertion ?? 0, + price_per_convertion: initialPricePerConvertion, } as DeliveryOrderProductFormValues; }); @@ -203,6 +226,8 @@ export const mergeSOwithDO = ( deliveryOrders: DeliveryOrderProductFormValues[], autofill?: boolean ): DeliveryOrderProductFormValues[] => { + const hasDeliveryOrders = deliveryOrders.length > 0; + return salesOrders.map((so) => { const delivery = deliveryOrders.find( (d) => d?.marketing_product_id === so.id @@ -227,30 +252,50 @@ export const mergeSOwithDO = ( delivery_date: delivery?.delivery_date || undefined, do_number: delivery?.do_number || undefined, vehicle_number: delivery?.vehicle_number || so.vehicle_number, - unit_price: autofill ? delivery?.unit_price : salesOrderUnitPrice, - total_weight: autofill ? delivery?.total_weight : so.total_weight, - qty: autofill ? delivery?.qty : so.qty, - avg_weight: autofill ? delivery?.avg_weight : so.avg_weight, - total_price: autofill ? delivery?.total_price : so.total_price, + unit_price: + autofill && hasDeliveryOrders + ? delivery?.unit_price + : salesOrderUnitPrice, + total_weight: + autofill && hasDeliveryOrders + ? delivery?.total_weight + : so.total_weight, + qty: autofill && hasDeliveryOrders ? delivery?.qty : so.qty, + avg_weight: + autofill && hasDeliveryOrders ? delivery?.avg_weight : so.avg_weight, + total_price: + autofill && hasDeliveryOrders ? delivery?.total_price : so.total_price, marketing_product: so, // jika ada, override - uom: autofill ? delivery?.uom : so.uom, - weight_per_convertion: autofill - ? delivery?.weight_per_convertion - : so.weight_per_convertion, - price_per_convertion: autofill - ? delivery?.price_per_convertion - : so.price_per_convertion, - convertion_unit: autofill - ? delivery?.convertion_unit - : so.convertion_unit, - marketing_type: autofill ? delivery?.marketing_type : so.marketing_type, - total_peti: autofill ? delivery?.total_peti : so.total_peti, - price_per_qty: autofill ? delivery?.price_per_qty : salesOrderPricePerQty, - sisa_berat: autofill ? delivery?.sisa_berat : so.sisa_berat, - price_sisa_berat: autofill - ? delivery?.price_sisa_berat - : so.price_sisa_berat, - week: autofill ? delivery?.week : so.week, + uom: autofill && hasDeliveryOrders ? delivery?.uom : so.uom, + weight_per_convertion: + autofill && hasDeliveryOrders + ? delivery?.weight_per_convertion + : so.weight_per_convertion, + price_per_convertion: + autofill && hasDeliveryOrders + ? delivery?.price_per_convertion + : so.price_per_convertion, + convertion_unit: + autofill && hasDeliveryOrders + ? delivery?.convertion_unit + : so.convertion_unit, + marketing_type: + autofill && hasDeliveryOrders + ? delivery?.marketing_type + : so.marketing_type, + total_peti: + autofill && hasDeliveryOrders ? delivery?.total_peti : so.total_peti, + price_per_qty: + autofill && hasDeliveryOrders + ? delivery?.price_per_qty + : salesOrderPricePerQty, + sisa_berat: + autofill && hasDeliveryOrders ? delivery?.sisa_berat : so.sisa_berat, + price_sisa_berat: + autofill && hasDeliveryOrders + ? delivery?.price_sisa_berat + : so.price_sisa_berat, + week: autofill && hasDeliveryOrders ? delivery?.week : so.week, } as DeliveryOrderProductFormValues; }); }; diff --git a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx index 781ebf26..6793018b 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -126,18 +126,14 @@ const DeliveryOrderProductForm = ({ 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 initialPricePerConvertion = initialValues?.unit_price - ? Number(initialValues?.unit_price) - : 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) + : Number(initialValues?.unit_price || 0); const initialPriceSisaBerat = initialValues?.total_price && initialValues?.total_peti @@ -728,7 +724,7 @@ const DeliveryOrderProductForm = ({ placeholder='Masukan Total Peti' endAdornment={
- Kg + Peti
} bottomLabel={`1 ${formik.values.convertion_unit?.value.toLowerCase()} = ${formik.values.weight_per_convertion ?? 0} Kg`} @@ -778,6 +774,9 @@ const DeliveryOrderProductForm = ({ } errorMessage={formik.errors.total_weight} placeholder='Masukan Total Bobot' + disabled={ + formik.values.convertion_unit?.value.toLowerCase() === 'peti' + } /> )} 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 a7f2c73e..5f0031f8 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx @@ -61,18 +61,14 @@ const SalesOrderProductForm = ({ 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 initialPricePerConvertion = initialValues?.unit_price - ? Number(initialValues?.unit_price) - : 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) + : Number(initialValues?.unit_price || 0); const isInitialTelurQty = initialValues?.marketing_type?.value?.toLowerCase() === 'telur' && @@ -624,7 +620,7 @@ const SalesOrderProductForm = ({ placeholder='Masukan Total Peti' endAdornment={
- Kg + Peti
} bottomLabel={`1 ${formik.values.convertion_unit?.value.toLowerCase()} = ${formik.values.weight_per_convertion ?? 0} Kg`} @@ -674,6 +670,9 @@ const SalesOrderProductForm = ({ } errorMessage={formik.errors.total_weight} placeholder='Masukan Total Bobot' + disabled={ + formik.values.convertion_unit?.value.toLowerCase() === 'peti' + } /> )} diff --git a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx index a1e0c9de..9c7337ec 100644 --- a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx @@ -85,7 +85,7 @@ const DeliveryOrderProductTable = ({
Value
- {formType !== 'success' && + {/* {formType !== 'success' && (formType === 'add_delivery' || formType === 'edit_delivery' || formType === 'detail') && ( @@ -102,7 +102,7 @@ const DeliveryOrderProductTable = ({
- )} + )} */} @@ -141,12 +141,15 @@ const DeliveryOrderProductTable = ({ Total Bobot - {formatNumber(Number(item.total_weight))} + {formatNumber(Number(item.total_weight))} Kg )} - Total Harga Satuan + + Total Harga Satuan + {item.convertion_unit?.label.toLowerCase() === 'peti' && ' (Kg)'} + {formatCurrency(parseFloat(item.unit_price as string))} diff --git a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx index f40f9151..d8e906cf 100644 --- a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx @@ -137,8 +137,22 @@ const SalesOrderProductTable = ({ {`${formatNumber(parseFloat(item.qty as string))} ${item.uom || ''}`} + {item.convertion_unit?.value.toLowerCase() === 'peti' && ( + + Harga Satuan Per Peti + + {formatCurrency( + parseFloat(item.unit_price as string) * + parseFloat(String(item.weight_per_convertion)) + )} + + + )} - Harga Satuan + + Harga Satuan + {item.convertion_unit?.value.toLowerCase() === 'peti' && ' (Kg)'} + {formatCurrency(parseFloat(item.unit_price as string))} diff --git a/src/components/pages/production/uniformity/form/UniformityForm.tsx b/src/components/pages/production/uniformity/form/UniformityForm.tsx index 8840c021..80668748 100644 --- a/src/components/pages/production/uniformity/form/UniformityForm.tsx +++ b/src/components/pages/production/uniformity/form/UniformityForm.tsx @@ -597,6 +597,7 @@ const UniformityForm = ({ onBlur={formik.handleBlur} isError={formik.touched.date && Boolean(formik.errors.date)} errorMessage={formik.errors.date as string} + disabled={isNextStep} /> { const filterModal = useModal(); // ===== OPTIONS ===== - const { options: areaOptions, isLoadingOptions: isLoadingAreas } = useSelect( - AreaApi.basePath, + const { + options: areaOptions, + isLoadingOptions: isLoadingAreas, + setInputValue: setAreaInputValue, + loadMore: loadMoreArea, + } = useSelect(AreaApi.basePath, 'id', 'name', 'search'); + + const { + options: locationOptions, + isLoadingOptions: isLoadingLocations, + setInputValue: setLocationInputValue, + loadMore: loadMoreLocation, + } = useSelect(LocationApi.basePath, 'id', 'name', 'search'); + + const { + options: kandangOptions, + isLoadingOptions: isLoadingKandangs, + setInputValue: setKandangInputValue, + loadMore: loadMoreKandang, + } = useSelect( + ProjectFlockKandangApi.basePath, 'id', - 'name', + 'name_with_period', 'search' ); - const { options: locationOptions, isLoadingOptions: isLoadingLocations } = - useSelect(LocationApi.basePath, 'id', 'name', 'search'); - - const { options: kandangOptions, isLoadingOptions: isLoadingKandangs } = - useSelect( - ProjectFlockKandangApi.basePath, - 'id', - 'name_with_period', - 'search' - ); - const showUnrecordedOptions = useMemo( () => [ { value: 'false', label: 'Sembunyikan' }, @@ -918,6 +926,8 @@ const HppPerKandangTab = ({ tabId }: HppPerKandangTabProps) => { isLoading={isLoadingAreas} isClearable className={{ wrapper: 'w-full' }} + onInputChange={setAreaInputValue} + onMenuScrollToBottom={loadMoreArea} /> {/* Location Filter */} @@ -937,6 +947,8 @@ const HppPerKandangTab = ({ tabId }: HppPerKandangTabProps) => { isLoading={isLoadingLocations} isClearable className={{ wrapper: 'w-full' }} + onInputChange={setLocationInputValue} + onMenuScrollToBottom={loadMoreLocation} /> {/* Kandang Filter */} @@ -956,6 +968,8 @@ const HppPerKandangTab = ({ tabId }: HppPerKandangTabProps) => { isLoading={isLoadingKandangs} isClearable className={{ wrapper: 'w-full' }} + onInputChange={setKandangInputValue} + onMenuScrollToBottom={loadMoreKandang} /> {/* Weight Range Filter */} diff --git a/src/lib/marketing-calculation.ts b/src/lib/marketing-calculation.ts index 3d4930c5..e957d64f 100644 --- a/src/lib/marketing-calculation.ts +++ b/src/lib/marketing-calculation.ts @@ -235,10 +235,8 @@ export const calculateTelurPeti = ( const totalPrice = pricePerConvertion * totalPeti + priceSisaBerat; setFieldValue('total_price', totalPrice); // Recalculate unit_price = total_price / total_weight - - // TODO: consider sisa berat later const totalWeight = weightPerConvertion * totalPeti + sisaBerat; - updateUnitPrice(totalPrice, totalPeti); + updateUnitPrice(totalPrice, totalWeight); } break; } @@ -257,8 +255,8 @@ export const calculateTelurPeti = ( if (pricePerConvertion > 0 && totalPeti > 0) { const totalPrice = pricePerConvertion * totalPeti + priceSisaBerat; setFieldValue('total_price', totalPrice); - // Recalculate unit_price = total_price / total_peti - updateUnitPrice(totalPrice, totalPeti); + // Recalculate unit_price = total_price / totalWeight + updateUnitPrice(totalPrice, totalWeight); } break; } @@ -317,6 +315,15 @@ export const calculateTelurPeti = ( updateUnitPrice(totalPrice, totalWeight); break; } + case 'qty': + // Recalculate avg_weight = total_weight / qty + if (qty > 0 && values.total_weight) { + setFieldValue( + 'avg_weight', + preciseWeight(Number(values.total_weight) / qty) + ); + } + break; } }; diff --git a/src/types/api/marketing/marketing.d.ts b/src/types/api/marketing/marketing.d.ts index 743493f7..15d34345 100644 --- a/src/types/api/marketing/marketing.d.ts +++ b/src/types/api/marketing/marketing.d.ts @@ -61,6 +61,7 @@ export type BaseDelivery = { avg_weight: number; total_price: number; vehicle_number: string; + weight_per_convertion: number; }; export type MarketingProduct = {