From ea6cd5151b32b81bba31cdf782e0a22214c39817 Mon Sep 17 00:00:00 2001 From: laxmanhalaki Date: Tue, 16 Dec 2025 19:48:54 +0530 Subject: [PATCH] sap implementsion for internal order and budget block --- .../components/request-detail/WorkflowTab.tsx | 10 +- .../request-detail/modals/DMSPushModal.tsx | 2 +- .../modals/DealerCompletionDocumentsModal.tsx | 220 ++++++++++++++---- .../modals/DealerProposalSubmissionModal.tsx | 89 +++++-- .../modals/DeptLeadIOApprovalModal.tsx | 91 +++++--- src/hooks/useRequestDetails.ts | 9 - src/services/dealerClaimApi.ts | 18 +- 7 files changed, 316 insertions(+), 123 deletions(-) diff --git a/src/dealer-claim/components/request-detail/WorkflowTab.tsx b/src/dealer-claim/components/request-detail/WorkflowTab.tsx index 2c3b21f..fe8c713 100644 --- a/src/dealer-claim/components/request-detail/WorkflowTab.tsx +++ b/src/dealer-claim/components/request-detail/WorkflowTab.tsx @@ -546,14 +546,12 @@ export function DealerClaimWorkflowTab({ const levelId = step3Level.levelId || step3Level.level_id; // First, update IO details using dealer claim API - // Note: We need to get IO balance from SAP integration, but for now we'll use placeholder values - // The backend should handle SAP integration + // Only pass ioNumber and ioRemark - don't override existing balance values + // Balance values should already be stored when amount was blocked earlier await updateIODetails(requestId, { ioNumber: data.ioNumber, ioRemark: data.ioRemark, - ioAvailableBalance: 0, // Should come from SAP integration - ioBlockedAmount: 0, // Should come from SAP integration - ioRemainingBalance: 0, // Should come from SAP integration + // Don't pass balance fields - let backend preserve existing values }); // Approve Step 3 using real API @@ -1002,7 +1000,6 @@ export function DealerClaimWorkflowTab({ ))} @@ -413,7 +442,13 @@ export function DealerCompletionDocumentsModal({

Upload photos from the completed activity (event photos, installations, etc.)

-
+
0 + ? 'border-green-500 bg-green-50 hover:border-green-600' + : 'border-gray-300 hover:border-blue-500 bg-white' + }`} + > - - - Click to upload photos (JPG, PNG - multiple files allowed) - + {activityPhotos.length > 0 ? ( + <> + +
+ + {activityPhotos.length} photo{activityPhotos.length !== 1 ? 's' : ''} selected + + + Click to add more photos + +
+ + ) : ( + <> + + + Click to upload photos (JPG, PNG - multiple files allowed) + + + )}
{activityPhotos.length > 0 && ( -
+
+

+ Selected Photos ({activityPhotos.length}): +

{activityPhotos.map((file, index) => (
- {file.name} +
+ + {file.name} +
))} @@ -473,7 +531,13 @@ export function DealerCompletionDocumentsModal({

Upload invoices and receipts for expenses incurred

-
+
0 + ? 'border-blue-500 bg-blue-50 hover:border-blue-600' + : 'border-gray-300 hover:border-blue-500 bg-white' + }`} + > - - - Click to upload invoices/receipts (PDF, JPG, PNG) - + {invoicesReceipts.length > 0 ? ( + <> + +
+ + {invoicesReceipts.length} document{invoicesReceipts.length !== 1 ? 's' : ''} selected + + + Click to add more documents + +
+ + ) : ( + <> + + + Click to upload invoices/receipts (PDF, JPG, PNG) + + + )}
{invoicesReceipts.length > 0 && ( -
+
+

+ Selected Documents ({invoicesReceipts.length}): +

{invoicesReceipts.map((file, index) => (
- {file.name} +
+ + {file.name} +
))} @@ -524,7 +611,13 @@ export function DealerCompletionDocumentsModal({

Upload attendance records or participant lists (if applicable)

-
+
- - - Click to upload attendance sheet (Excel, PDF, CSV) - + {attendanceSheet ? ( + <> + +
+ + {attendanceSheet.name} + + + Document selected + +
+ + ) : ( + <> + + + Click to upload attendance sheet (Excel, PDF, CSV) + + + )}
{attendanceSheet && ( -
- {attendanceSheet.name} - +
+

+ Selected Document: +

+
+
+ + {attendanceSheet.name} +
+ +
)}
diff --git a/src/dealer-claim/components/request-detail/modals/DealerProposalSubmissionModal.tsx b/src/dealer-claim/components/request-detail/modals/DealerProposalSubmissionModal.tsx index 8065301..2a4b03f 100644 --- a/src/dealer-claim/components/request-detail/modals/DealerProposalSubmissionModal.tsx +++ b/src/dealer-claim/components/request-detail/modals/DealerProposalSubmissionModal.tsx @@ -18,7 +18,7 @@ import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Badge } from '@/components/ui/badge'; -import { Upload, Plus, X, Calendar, DollarSign, CircleAlert } from 'lucide-react'; +import { Upload, Plus, X, Calendar, DollarSign, CircleAlert, CheckCircle2, FileText } from 'lucide-react'; import { toast } from 'sonner'; interface CostItem { @@ -187,7 +187,7 @@ export function DealerProposalSubmissionModal({ return ( - + @@ -223,7 +223,13 @@ export function DealerProposalSubmissionModal({

Detailed proposal with activity details and requested information

-
+
- - - {proposalDocument - ? proposalDocument.name - : 'Click to upload proposal (PDF, DOC, DOCX)'} - + {proposalDocument ? ( + <> + +
+ + {proposalDocument.name} + + + Document selected + +
+ + ) : ( + <> + + + Click to upload proposal (PDF, DOC, DOCX) + + + )}
@@ -390,7 +410,13 @@ export function DealerProposalSubmissionModal({

Any other supporting documents (invoices, receipts, photos, etc.)

-
+
0 + ? 'border-blue-500 bg-blue-50 hover:border-blue-600' + : 'border-gray-300 hover:border-blue-500 bg-white' + }`} + > - - - Click to upload additional documents (multiple files allowed) - + {otherDocuments.length > 0 ? ( + <> + +
+ + {otherDocuments.length} document{otherDocuments.length !== 1 ? 's' : ''} selected + + + Click to add more documents + +
+ + ) : ( + <> + + + Click to upload additional documents (multiple files allowed) + + + )}
{otherDocuments.length > 0 && ( -
+
+

+ Selected Documents ({otherDocuments.length}): +

{otherDocuments.map((file, index) => (
- {file.name} +
+ + + {file.name} + +
))} diff --git a/src/dealer-claim/components/request-detail/modals/DeptLeadIOApprovalModal.tsx b/src/dealer-claim/components/request-detail/modals/DeptLeadIOApprovalModal.tsx index 1fe6159..0a63d3e 100644 --- a/src/dealer-claim/components/request-detail/modals/DeptLeadIOApprovalModal.tsx +++ b/src/dealer-claim/components/request-detail/modals/DeptLeadIOApprovalModal.tsx @@ -33,9 +33,10 @@ interface DeptLeadIOApprovalModalProps { onReject: (comments: string) => Promise; requestTitle?: string; requestId?: string; - // Pre-filled IO data from IO tab + // Pre-filled IO data from IO table preFilledIONumber?: string; preFilledBlockedAmount?: number; + preFilledRemainingBalance?: number; } export function DeptLeadIOApprovalModal({ @@ -47,19 +48,25 @@ export function DeptLeadIOApprovalModal({ requestId: _requestId, preFilledIONumber, preFilledBlockedAmount, + preFilledRemainingBalance, }: DeptLeadIOApprovalModalProps) { const [actionType, setActionType] = useState<'approve' | 'reject'>('approve'); - const [ioNumber, setIoNumber] = useState(preFilledIONumber || ''); const [ioRemark, setIoRemark] = useState(''); const [comments, setComments] = useState(''); const [submitting, setSubmitting] = useState(false); - // Update ioNumber when preFilledIONumber changes (when modal opens with new data) + // Get IO number from props (read-only, from IO table) + const ioNumber = preFilledIONumber || ''; + + // Reset form when modal opens/closes React.useEffect(() => { - if (isOpen && preFilledIONumber) { - setIoNumber(preFilledIONumber); + if (isOpen) { + // Reset form when modal opens + setIoRemark(''); + setComments(''); + setActionType('approve'); } - }, [isOpen, preFilledIONumber]); + }, [isOpen]); const ioRemarkChars = ioRemark.length; const commentsChars = comments.length; @@ -71,9 +78,9 @@ export function DeptLeadIOApprovalModal({ if (actionType === 'reject') { return comments.trim().length > 0; } - // For approve, need IO number, IO remark, and comments + // For approve, need IO number (from table), IO remark, and comments return ( - ioNumber.trim().length > 0 && + ioNumber.trim().length > 0 && // IO number must exist from IO table ioRemark.trim().length > 0 && comments.trim().length > 0 ); @@ -83,7 +90,7 @@ export function DeptLeadIOApprovalModal({ if (!isFormValid) { if (actionType === 'approve') { if (!ioNumber.trim()) { - toast.error('Please enter IO number'); + toast.error('IO number is required. Please block amount from IO tab first.'); return; } if (!ioRemark.trim()) { @@ -123,7 +130,6 @@ export function DeptLeadIOApprovalModal({ const handleReset = () => { setActionType('approve'); - setIoNumber(preFilledIONumber || ''); setIoRemark(''); setComments(''); }; @@ -148,7 +154,7 @@ export function DeptLeadIOApprovalModal({ Approve and Organise IO - Enter blocked IO details and provide your approval comments + Review IO details and provide your approval comments
@@ -206,52 +212,71 @@ export function DeptLeadIOApprovalModal({ {/* IO Organisation Details - Only shown when approving */} {actionType === 'approve' && ( -
+

IO Organisation Details

- {/* IO Number */} + {/* IO Number - Read-only from IO table */}
setIoNumber(e.target.value)} - className="bg-white h-8" + value={ioNumber || '—'} + disabled + readOnly + className="bg-gray-100 h-8 cursor-not-allowed" /> - {preFilledIONumber && ( + {!ioNumber && ( +

+ ⚠️ IO number not found. Please block amount from IO tab first. +

+ )} + {ioNumber && (

- Pre-filled from IO tab + ✓ Loaded from IO table

)}
- {/* Blocked Amount Display (if available) */} - {preFilledBlockedAmount !== undefined && preFilledBlockedAmount > 0 && ( -
-
- Blocked Amount: - - ₹{preFilledBlockedAmount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} - + {/* IO Balance Information - Read-only */} +
+ {/* Blocked Amount Display */} + {preFilledBlockedAmount !== undefined && preFilledBlockedAmount > 0 && ( +
+
+ Blocked Amount: + + ₹{preFilledBlockedAmount.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} + +
-

Amount already blocked in SAP from IO tab

-
- )} + )} - {/* IO Remark */} + {/* Remaining Balance Display */} + {preFilledRemainingBalance !== undefined && preFilledRemainingBalance !== null && ( +
+
+ Remaining Balance: + + ₹{preFilledRemainingBalance.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} + +
+
+ )} +
+ + {/* IO Remark - Only editable field */}