CR Fixed for mand for varience
This commit is contained in:
parent
81f8ef2081
commit
11392873c3
@ -1170,6 +1170,53 @@ useEffect(() => {
|
||||
});
|
||||
};
|
||||
|
||||
// Calculate percentage variation between previous and current quarter costs
|
||||
const calculateVariationPercentage = (product) => {
|
||||
// Previous quarter costs (Q4): October, November, December
|
||||
const previousCosts = [
|
||||
parseFloat(product.octCost) || 0,
|
||||
parseFloat(product.novCost) || 0,
|
||||
parseFloat(product.decCost) || 0
|
||||
];
|
||||
|
||||
// Current quarter costs (Q1): January, February, March
|
||||
const currentCosts = [
|
||||
parseFloat(product.janCost) || 0,
|
||||
parseFloat(product.febCost) || 0,
|
||||
parseFloat(product.marCost) || 0
|
||||
];
|
||||
|
||||
const totalPreviousCost = previousCosts.reduce((sum, cost) => sum + cost, 0);
|
||||
const totalCurrentCost = currentCosts.reduce((sum, cost) => sum + cost, 0);
|
||||
|
||||
// If previous cost is 0, return 0 to avoid division by zero
|
||||
if (totalPreviousCost === 0) {
|
||||
console.log('🔍 Variation Calculation: Previous cost is 0, returning 0% variation');
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate percentage variation
|
||||
const variation = ((totalCurrentCost - totalPreviousCost) / totalPreviousCost) * 100;
|
||||
|
||||
console.log('🔍 Variation Calculation Details:', {
|
||||
productId: product.id || 'unknown',
|
||||
previousCosts,
|
||||
currentCosts,
|
||||
totalPreviousCost,
|
||||
totalCurrentCost,
|
||||
variation: variation.toFixed(2) + '%',
|
||||
isMandatory: Math.abs(variation) > 10
|
||||
});
|
||||
|
||||
return variation;
|
||||
};
|
||||
|
||||
// Check if variation reason should be mandatory based on variation percentage
|
||||
const isVariationReasonMandatory = (product) => {
|
||||
const variation = calculateVariationPercentage(product);
|
||||
return Math.abs(variation) > 10; // Greater than +10% or less than -10%
|
||||
};
|
||||
|
||||
// Simple validation function
|
||||
const validateField = (fieldName, value, productIndex) => {
|
||||
const errors = { ...formErrors };
|
||||
@ -1244,6 +1291,28 @@ useEffect(() => {
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Dynamic validation for variation reason based on cost variation
|
||||
const mandatoryVariationReason = isVariationReasonMandatory(product);
|
||||
if (mandatoryVariationReason) {
|
||||
// Check if variation reason is selected
|
||||
if (!product.variationReason || product.variationReason === '0' || product.variationReason === '') {
|
||||
errors[`variationReason_${index}`] = 'Reason for variation is required when cost variation exceeds ±10%';
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
// If "Other" is selected, validate the other variation reason field
|
||||
const selectedReason = variationReasons.find(r => r.value === product.variationReason);
|
||||
const isOtherSelected = selectedReason && (
|
||||
(selectedReason.name && selectedReason.name.toLowerCase().includes('other')) ||
|
||||
(selectedReason.label && selectedReason.label.toLowerCase().includes('other'))
|
||||
);
|
||||
|
||||
if (isOtherSelected && (!product.otherVariationReason || product.otherVariationReason.trim() === '')) {
|
||||
errors[`otherVariationReason_${index}`] = 'Please specify the reason for variation';
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setFormErrors(errors);
|
||||
@ -1636,6 +1705,102 @@ useEffect(() => {
|
||||
delete newErrors[errorKey];
|
||||
setFormErrors(newErrors);
|
||||
}
|
||||
|
||||
// Real-time validation for variation reason when cost fields change
|
||||
const costFields = ['octCost', 'novCost', 'decCost', 'janCost', 'febCost', 'marCost'];
|
||||
if (costFields.includes(field)) {
|
||||
const updatedProduct = updatedProducts.find(p => p.id === id);
|
||||
if (updatedProduct) {
|
||||
const mandatoryVariationReason = isVariationReasonMandatory(updatedProduct);
|
||||
const variationErrorKey = `variationReason_${productIndex}`;
|
||||
const otherVariationErrorKey = `otherVariationReason_${productIndex}`;
|
||||
|
||||
const newErrors = { ...formErrors };
|
||||
|
||||
if (mandatoryVariationReason) {
|
||||
// Check if variation reason is selected
|
||||
if (!updatedProduct.variationReason || updatedProduct.variationReason === '0' || updatedProduct.variationReason === '') {
|
||||
newErrors[variationErrorKey] = 'Reason for variation is required when cost variation exceeds ±10%';
|
||||
} else {
|
||||
delete newErrors[variationErrorKey];
|
||||
|
||||
// If "Other" is selected, validate the other variation reason field
|
||||
const selectedReason = variationReasons.find(r => r.value === updatedProduct.variationReason);
|
||||
const isOtherSelected = selectedReason && (
|
||||
(selectedReason.name && selectedReason.name.toLowerCase().includes('other')) ||
|
||||
(selectedReason.label && selectedReason.label.toLowerCase().includes('other'))
|
||||
);
|
||||
|
||||
if (isOtherSelected && (!updatedProduct.otherVariationReason || updatedProduct.otherVariationReason.trim() === '')) {
|
||||
newErrors[otherVariationErrorKey] = 'Please specify the reason for variation';
|
||||
} else {
|
||||
delete newErrors[otherVariationErrorKey];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Remove variation reason errors if variation is within ±10%
|
||||
delete newErrors[variationErrorKey];
|
||||
delete newErrors[otherVariationErrorKey];
|
||||
}
|
||||
|
||||
setFormErrors(newErrors);
|
||||
}
|
||||
}
|
||||
|
||||
// Real-time validation when variation reason field changes
|
||||
if (field === 'variationReason' || field === 'otherVariationReason') {
|
||||
const updatedProduct = updatedProducts.find(p => p.id === id);
|
||||
if (updatedProduct) {
|
||||
const mandatoryVariationReason = isVariationReasonMandatory(updatedProduct);
|
||||
const variationErrorKey = `variationReason_${productIndex}`;
|
||||
const otherVariationErrorKey = `otherVariationReason_${productIndex}`;
|
||||
|
||||
const newErrors = { ...formErrors };
|
||||
|
||||
if (mandatoryVariationReason) {
|
||||
if (field === 'variationReason') {
|
||||
// Check if variation reason is selected
|
||||
if (!updatedProduct.variationReason || updatedProduct.variationReason === '0' || updatedProduct.variationReason === '') {
|
||||
newErrors[variationErrorKey] = 'Reason for variation is required when cost variation exceeds ±10%';
|
||||
} else {
|
||||
delete newErrors[variationErrorKey];
|
||||
|
||||
// If "Other" is selected, validate the other variation reason field
|
||||
const selectedReason = variationReasons.find(r => r.value === updatedProduct.variationReason);
|
||||
const isOtherSelected = selectedReason && (
|
||||
(selectedReason.name && selectedReason.name.toLowerCase().includes('other')) ||
|
||||
(selectedReason.label && selectedReason.label.toLowerCase().includes('other'))
|
||||
);
|
||||
|
||||
if (isOtherSelected && (!updatedProduct.otherVariationReason || updatedProduct.otherVariationReason.trim() === '')) {
|
||||
newErrors[otherVariationErrorKey] = 'Please specify the reason for variation';
|
||||
} else {
|
||||
delete newErrors[otherVariationErrorKey];
|
||||
}
|
||||
}
|
||||
} else if (field === 'otherVariationReason') {
|
||||
// Validate other variation reason if "Other" is selected
|
||||
const selectedReason = variationReasons.find(r => r.value === updatedProduct.variationReason);
|
||||
const isOtherSelected = selectedReason && (
|
||||
(selectedReason.name && selectedReason.name.toLowerCase().includes('other')) ||
|
||||
(selectedReason.label && selectedReason.label.toLowerCase().includes('other'))
|
||||
);
|
||||
|
||||
if (isOtherSelected && (!updatedProduct.otherVariationReason || updatedProduct.otherVariationReason.trim() === '')) {
|
||||
newErrors[otherVariationErrorKey] = 'Please specify the reason for variation';
|
||||
} else {
|
||||
delete newErrors[otherVariationErrorKey];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Remove variation reason errors if variation is within ±10%
|
||||
delete newErrors[variationErrorKey];
|
||||
delete newErrors[otherVariationErrorKey];
|
||||
}
|
||||
|
||||
setFormErrors(newErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onProductsChange(updatedProducts);
|
||||
@ -2397,13 +2562,20 @@ useEffect(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Reason for Variation</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Reason for Variation
|
||||
{isVariationReasonMandatory(p) && <span className="text-red-600">*</span>}
|
||||
</label>
|
||||
<Select
|
||||
placeholder={isLoadingReasons ? 'Loading reasons...' : 'Select reason'}
|
||||
options={variationReasons}
|
||||
value={p.variationReason || ''}
|
||||
onChange={(e) => updateProductField(p.id, 'variationReason', e.target.value, variationReasons)}
|
||||
error={!!formErrors[`variationReason_${idx}`]}
|
||||
/>
|
||||
{formErrors[`variationReason_${idx}`] && (
|
||||
<p className="mt-1 text-xs text-red-600">{formErrors[`variationReason_${idx}`]}</p>
|
||||
)}
|
||||
{(showOtherVariationReason[p.id] || (p.variationReason && (p.variationReason.toString().toLowerCase().includes('other') || (variationReasons.find(r => r.value === p.variationReason)?.name?.toLowerCase().includes('other') || variationReasons.find(r => r.value === p.variationReason)?.label?.toLowerCase().includes('other'))))) && (
|
||||
<div className="mt-3 p-3 bg-gray-50 rounded-md border border-gray-200">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">Please specify the reason</label>
|
||||
@ -2412,7 +2584,11 @@ useEffect(() => {
|
||||
placeholder="Enter your reason here..."
|
||||
value={p.otherVariationReason || ''}
|
||||
onChange={(e) => updateProductField(p.id, 'otherVariationReason', e.target.value)}
|
||||
error={!!formErrors[`otherVariationReason_${idx}`]}
|
||||
/>
|
||||
{formErrors[`otherVariationReason_${idx}`] && (
|
||||
<p className="mt-1 text-xs text-red-600">{formErrors[`otherVariationReason_${idx}`]}</p>
|
||||
)}
|
||||
{/* <p className="mt-1 text-xs text-gray-500">Please provide details about the variation reason</p> */}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -4,7 +4,8 @@ import {
|
||||
IconButton,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent
|
||||
DialogContent,
|
||||
Tooltip
|
||||
} from '@mui/material';
|
||||
import { SelectField as BaseSelectField } from '@/components/common/FormControls';
|
||||
import Table from '@/components/common/Table';
|
||||
@ -513,7 +514,9 @@ const ManufacturingIndex = () => {
|
||||
Next scheduled run: {nextScheduledRun}
|
||||
</div>
|
||||
<div className="flex text-sm text-gray-600">
|
||||
<InfoOutlinedIcon className="text-gray-400 text-base mr-1 mt-0.5 flex-shrink-0" />
|
||||
<Tooltip title="Manufacturing index calculation method" arrow>
|
||||
<InfoOutlinedIcon className="text-gray-400 text-sm mr-1 align-middle flex-shrink-0 mt-[-0.2rem]" />
|
||||
</Tooltip>
|
||||
<span className="whitespace-nowrap">Formula: Manufacturing index<sub>t</sub> = Σ (sector weight<sub>i</sub> × group index<sub>i,t</sub>)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user