SAP team asked to map credit posting on based on the item group Vehicle/Spares have been implemented also points like delare code pading and nomenclature changes added

This commit is contained in:
laxmanhalaki 2026-03-17 17:19:06 +05:30
parent ef95d4af09
commit 85ddb72143
4 changed files with 128 additions and 18 deletions

View File

@ -48,7 +48,8 @@ export function ActivityTypeManager() {
title: '',
itemCode: '',
taxationType: '',
sapRefNo: ''
sapRefNo: '',
creditPostingOn: ''
});
useEffect(() => {
@ -75,7 +76,8 @@ export function ActivityTypeManager() {
title: '',
itemCode: '',
taxationType: '',
sapRefNo: ''
sapRefNo: '',
creditPostingOn: ''
});
setEditingActivityType(null);
setShowAddDialog(true);
@ -86,7 +88,8 @@ export function ActivityTypeManager() {
title: activityType.title,
itemCode: activityType.itemCode || '',
taxationType: activityType.taxationType || '',
sapRefNo: activityType.sapRefNo || ''
sapRefNo: activityType.sapRefNo || '',
creditPostingOn: activityType.creditPostingOn || ''
});
setEditingActivityType(activityType);
setShowAddDialog(true);
@ -96,8 +99,8 @@ export function ActivityTypeManager() {
try {
setError(null);
if (!formData.title.trim() || !formData.taxationType.trim() || !formData.sapRefNo.trim()) {
setError('Title, Taxation Type, and Claim Document Type (SAP Ref) are required');
if (!formData.title.trim() || !formData.taxationType.trim() || !formData.sapRefNo.trim() || !formData.creditPostingOn.trim()) {
setError('Title, Taxation Type, Credit Posting On, and Claim Document Type (SAP Ref) are required');
toast.error('Please fill in all mandatory fields');
return;
}
@ -106,7 +109,8 @@ export function ActivityTypeManager() {
title: formData.title.trim(),
itemCode: formData.itemCode.trim() || null,
taxationType: formData.taxationType.trim(),
sapRefNo: formData.sapRefNo.trim()
sapRefNo: formData.sapRefNo.trim(),
creditPostingOn: formData.creditPostingOn.trim()
};
if (editingActivityType) {
@ -270,7 +274,10 @@ export function ActivityTypeManager() {
{activityType.sapRefNo && (
<span className="font-medium">SAP Ref: <span className="text-slate-900">{activityType.sapRefNo}</span></span>
)}
{!activityType.itemCode && !activityType.taxationType && !activityType.sapRefNo && (
{activityType.creditPostingOn && (
<span className="font-medium">Credit Posting On: <Badge variant="secondary" className="ml-1 bg-slate-200 text-slate-800">{activityType.creditPostingOn}</Badge></span>
)}
{!activityType.itemCode && !activityType.taxationType && !activityType.sapRefNo && !activityType.creditPostingOn && (
<span className="text-slate-500 italic">No additional details</span>
)}
</div>
@ -433,6 +440,28 @@ export function ActivityTypeManager() {
/>
<p className="text-xs text-slate-500">Required SAP reference number for CSV generation</p>
</div>
{/* Credit Posting On Field */}
<div className="space-y-2">
<Label htmlFor="creditPostingOn" className="text-sm font-semibold text-slate-900 flex items-center gap-1">
Credit Posting On <span className="text-red-500">*</span>
</Label>
<Select
value={formData.creditPostingOn}
onValueChange={(value) => setFormData({ ...formData, creditPostingOn: value })}
>
<SelectTrigger id="creditPostingOn" className="h-11 border-slate-300 focus:border-re-green focus:ring-2 focus:ring-re-green/20 rounded-lg transition-all shadow-sm">
<SelectValue placeholder="Select Credit Posting Group" />
</SelectTrigger>
<SelectContent className="rounded-lg">
<SelectItem value="Vehicle" className="p-3">Vehicle</SelectItem>
<SelectItem value="Spares" className="p-3">Spares</SelectItem>
<SelectItem value="GMA" className="p-3">GMA</SelectItem>
<SelectItem value="Apparel" className="p-3">Apparel</SelectItem>
</SelectContent>
</Select>
<p className="text-xs text-slate-500">Categorize for dealer validation (Vehicle, Spares, GMA, or Apparel)</p>
</div>
</div>
<DialogFooter className="gap-3 pt-4 border-t border-slate-100 px-6 pb-6 flex-shrink-0">
@ -445,7 +474,7 @@ export function ActivityTypeManager() {
</Button>
<Button
onClick={handleSave}
disabled={!formData.title.trim() || !formData.taxationType || !formData.sapRefNo.trim()}
disabled={!formData.title.trim() || !formData.taxationType || !formData.sapRefNo.trim() || !formData.creditPostingOn}
className="h-11 bg-re-green hover:bg-re-green/90 text-white shadow-md hover:shadow-lg transition-all disabled:opacity-50 disabled:cursor-not-allowed"
>
<FileText className="w-4 h-4 mr-2" />

View File

@ -149,6 +149,7 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar
dealerEmail: '',
dealerPhone: '',
dealerAddress: '',
dealerItemGroup: '', // For validation
activityDate: undefined as Date | undefined,
location: '',
requestDescription: '',
@ -227,25 +228,57 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar
// Validate period dates
if (field === 'periodStartDate') {
// If start date is selected and end date exists, validate end date
if (value && updated.periodEndDate && value > updated.periodEndDate) {
// Clear end date if it's before the new start date
updated.periodEndDate = undefined;
toast.error('End date must be on or after the start date. End date has been cleared.');
}
} else if (field === 'periodEndDate') {
// If end date is selected and start date exists, validate end date
if (value && updated.periodStartDate && value < updated.periodStartDate) {
toast.error('End date must be on or after the start date.');
// Don't update the end date if it's invalid
return prev;
}
}
// 1b. Validate Activity Type change against already selected Dealer
if (field === 'activityType' && updated.dealerCode) {
const selectedActivity = activityTypes.find(t => t.title === value);
if (selectedActivity) {
if (selectedActivity.creditPostingOn) {
const activityCategory = selectedActivity.creditPostingOn.toLowerCase();
const dealerGroup = (updated.dealerItemGroup || '').toLowerCase();
// If we have a dealer group, validate it
if (dealerGroup) {
let isMatch = false;
if (activityCategory === 'vehicle' && dealerGroup === 'vehicle') isMatch = true;
else if (activityCategory === 'spares' && dealerGroup === 'spares') isMatch = true;
else if (activityCategory === 'gma' && dealerGroup === 'gma') isMatch = true;
else if (activityCategory === 'apparel' && dealerGroup === 'apparel') isMatch = true;
else if (activityCategory === dealerGroup) isMatch = true;
if (!isMatch) {
toast.error(`incorrect Delercode for selected service group`, {
description: `Activity requires ${selectedActivity.creditPostingOn}, but already selected dealer is ${updated.dealerItemGroup}`,
duration: 6000
});
return prev;
}
}
} else {
console.warn(`[ClaimWizard] Activity type "${value}" is missing creditPostingOn configuration.`);
}
}
}
return updated;
});
};
// Helper to update multiple fields at once
const updateMultipleFormData = (updates: Record<string, any>) => {
setFormData(prev => ({ ...prev, ...updates }));
};
const isStepValid = () => {
switch (currentStep) {
case 1:
@ -331,12 +364,58 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar
return;
}
// Dealer is logged in, update form data
updateFormData('dealerCode', verifiedDealer.dealerCode);
updateFormData('dealerName', verifiedDealer.dealerName || verifiedDealer.displayName);
updateFormData('dealerEmail', verifiedDealer.email || '');
updateFormData('dealerPhone', verifiedDealer.phone || '');
updateFormData('dealerAddress', ''); // Address not available in API response
// 1a. Validate Category Match (Frontend UX)
if (formData.activityType) {
const selectedActivity = activityTypes.find(t => t.title === formData.activityType);
if (selectedActivity && selectedActivity.creditPostingOn) {
const activityCategory = selectedActivity.creditPostingOn.toLowerCase();
const dealerGroup = (verifiedDealer.itemGroup || '').toLowerCase();
let isMatch = false;
// Vehicle matches Vehicle
if (activityCategory === 'vehicle' && dealerGroup === 'vehicle') {
isMatch = true;
}
// Spares matches Spares (Strict)
else if (activityCategory === 'spares' && dealerGroup === 'spares') {
isMatch = true;
}
// GMA matches GMA (Strict)
else if (activityCategory === 'gma' && dealerGroup === 'gma') {
isMatch = true;
}
// Apparel matches Apparel (Strict)
else if (activityCategory === 'apparel' && dealerGroup === 'apparel') {
isMatch = true;
}
// Direct match fallback
else if (activityCategory === dealerGroup) {
isMatch = true;
}
if (!isMatch) {
toast.error(`incorrect Delercode for selected service group`, {
description: `Activity requires ${selectedActivity.creditPostingOn}, but dealer is ${verifiedDealer.itemGroup || 'N/A'}`,
duration: 6000
});
// Clear the selection
setDealerSearchInput('');
setDealerSearchResults([]);
setVerifyingDealer(false);
return;
}
}
}
// Dealer is logged in, update form data in one batch
updateMultipleFormData({
dealerCode: verifiedDealer.dealerCode,
dealerName: verifiedDealer.dealerName || verifiedDealer.displayName,
dealerEmail: verifiedDealer.email || '',
dealerPhone: verifiedDealer.phone || '',
dealerAddress: '',
dealerItemGroup: verifiedDealer.itemGroup || ''
});
// Clear search input and results
setDealerSearchInput(verifiedDealer.dealerName || verifiedDealer.displayName);

View File

@ -44,6 +44,7 @@ export interface ActivityType {
itemCode?: string | null;
taxationType?: string | null;
sapRefNo?: string | null;
creditPostingOn?: string | null;
isActive?: boolean;
}

View File

@ -26,6 +26,7 @@ export interface DealerInfo {
city?: string | null;
dealerPrincipalName?: string | null;
dealerPrincipalEmailId?: string | null;
itemGroup?: string | null;
}
/**