multi iteration flow added and the external dealer api aded
This commit is contained in:
parent
5be1e319b0
commit
7488ae3bee
@ -1 +1 @@
|
|||||||
import{a as s}from"./index-BCZm9H2Q.js";import"./radix-vendor-CYvDqP9X.js";import"./charts-vendor-BVfwAPj-.js";import"./utils-vendor-BTBPSQfW.js";import"./ui-vendor-CX5oLBI_.js";import"./socket-vendor-TjCxX7sJ.js";import"./redux-vendor-tbZCm13o.js";import"./router-vendor-B_rK4TXr.js";async function m(n){return(await s.post(`/conclusions/${n}/generate`)).data.data}async function f(n,t){return(await s.post(`/conclusions/${n}/finalize`,{finalRemark:t})).data.data}async function d(n){var t;try{return(await s.get(`/conclusions/${n}`)).data.data}catch(o){if(((t=o.response)==null?void 0:t.status)===404)return null;throw o}}export{f as finalizeConclusion,m as generateConclusion,d as getConclusion};
|
import{a as s}from"./index-yOqi1S1C.js";import"./radix-vendor-CYvDqP9X.js";import"./charts-vendor-BVfwAPj-.js";import"./utils-vendor-BTBPSQfW.js";import"./ui-vendor-CX5oLBI_.js";import"./socket-vendor-TjCxX7sJ.js";import"./redux-vendor-tbZCm13o.js";import"./router-vendor-B_rK4TXr.js";async function m(n){return(await s.post(`/conclusions/${n}/generate`)).data.data}async function f(n,t){return(await s.post(`/conclusions/${n}/finalize`,{finalRemark:t})).data.data}async function d(n){var t;try{return(await s.get(`/conclusions/${n}`)).data.data}catch(o){if(((t=o.response)==null?void 0:t.status)===404)return null;throw o}}export{f as finalizeConclusion,m as generateConclusion,d as getConclusion};
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
build/assets/index-XBJXaMj2.css
Normal file
1
build/assets/index-XBJXaMj2.css
Normal file
File diff suppressed because one or more lines are too long
64
build/assets/index-yOqi1S1C.js
Normal file
64
build/assets/index-yOqi1S1C.js
Normal file
File diff suppressed because one or more lines are too long
@ -13,7 +13,7 @@
|
|||||||
<!-- Preload essential fonts and icons -->
|
<!-- Preload essential fonts and icons -->
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<script type="module" crossorigin src="/assets/index-BCZm9H2Q.js"></script>
|
<script type="module" crossorigin src="/assets/index-yOqi1S1C.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="/assets/charts-vendor-BVfwAPj-.js">
|
<link rel="modulepreload" crossorigin href="/assets/charts-vendor-BVfwAPj-.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/radix-vendor-CYvDqP9X.js">
|
<link rel="modulepreload" crossorigin href="/assets/radix-vendor-CYvDqP9X.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/utils-vendor-BTBPSQfW.js">
|
<link rel="modulepreload" crossorigin href="/assets/utils-vendor-BTBPSQfW.js">
|
||||||
@ -21,7 +21,7 @@
|
|||||||
<link rel="modulepreload" crossorigin href="/assets/socket-vendor-TjCxX7sJ.js">
|
<link rel="modulepreload" crossorigin href="/assets/socket-vendor-TjCxX7sJ.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/redux-vendor-tbZCm13o.js">
|
<link rel="modulepreload" crossorigin href="/assets/redux-vendor-tbZCm13o.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/router-vendor-B_rK4TXr.js">
|
<link rel="modulepreload" crossorigin href="/assets/router-vendor-B_rK4TXr.js">
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-DjE6S9VF.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-XBJXaMj2.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@ -1183,10 +1183,18 @@ export class DealerClaimService {
|
|||||||
hsnCode: item.hsnCode || '',
|
hsnCode: item.hsnCode || '',
|
||||||
gstRate: Number(item.gstRate) || 0,
|
gstRate: Number(item.gstRate) || 0,
|
||||||
gstAmt: Number(item.gstAmt) || 0,
|
gstAmt: Number(item.gstAmt) || 0,
|
||||||
|
cgstRate: Number(item.cgstRate) || 0,
|
||||||
cgstAmt: Number(item.cgstAmt) || 0,
|
cgstAmt: Number(item.cgstAmt) || 0,
|
||||||
|
sgstRate: Number(item.sgstRate) || 0,
|
||||||
sgstAmt: Number(item.sgstAmt) || 0,
|
sgstAmt: Number(item.sgstAmt) || 0,
|
||||||
|
igstRate: Number(item.igstRate) || 0,
|
||||||
igstAmt: Number(item.igstAmt) || 0,
|
igstAmt: Number(item.igstAmt) || 0,
|
||||||
totalAmt: Number(item.totalAmt) || 0
|
utgstRate: Number(item.utgstRate) || 0,
|
||||||
|
utgstAmt: Number(item.utgstAmt) || 0,
|
||||||
|
cessRate: Number(item.cessRate) || 0,
|
||||||
|
cessAmt: Number(item.cessAmt) || 0,
|
||||||
|
totalAmt: Number(item.totalAmt) || 0,
|
||||||
|
isService: !!item.isService
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
// Note: costBreakup JSONB field has been removed - only using separate table now
|
// Note: costBreakup JSONB field has been removed - only using separate table now
|
||||||
@ -1268,6 +1276,7 @@ export class DealerClaimService {
|
|||||||
proposalDetails: transformedProposalDetails,
|
proposalDetails: transformedProposalDetails,
|
||||||
completionDetails: serializedCompletionDetails,
|
completionDetails: serializedCompletionDetails,
|
||||||
internalOrder: serializedInternalOrder,
|
internalOrder: serializedInternalOrder,
|
||||||
|
internalOrders: serializedInternalOrders, // Return full list for UI
|
||||||
// New normalized tables
|
// New normalized tables
|
||||||
budgetTracking: serializedBudgetTracking,
|
budgetTracking: serializedBudgetTracking,
|
||||||
invoice: serializedInvoice,
|
invoice: serializedInvoice,
|
||||||
@ -1766,11 +1775,35 @@ export class DealerClaimService {
|
|||||||
// If blocking amount is 0 but ioNumber is provided, just save the IO details without blocking
|
// If blocking amount is 0 but ioNumber is provided, just save the IO details without blocking
|
||||||
if (blockedAmount <= 0) {
|
if (blockedAmount <= 0) {
|
||||||
// Allow saving IO details (ioNumber only) even without blocking amount
|
// Allow saving IO details (ioNumber only) even without blocking amount
|
||||||
// This is useful when Requestor Evaluation is in progress but amount hasn't been blocked yet
|
// This is useful when Step 3/Requestor Evaluation is in progress but amount hasn't been blocked yet or for linking IO
|
||||||
if (ioData.ioNumber) {
|
if (ioData.ioNumber) {
|
||||||
const organizedBy = organizedByUserId || null;
|
const organizedBy = organizedByUserId || null;
|
||||||
|
|
||||||
// Always create a new Internal Order record for each block/provision (supporting multiple IOs)
|
// Check if an IO record already exists for this request and IO number
|
||||||
|
// This prevents duplicate 0-amount "provisioned" records when re-saving IO details
|
||||||
|
const existingIO = await InternalOrder.findOne({
|
||||||
|
where: {
|
||||||
|
requestId,
|
||||||
|
ioNumber: ioData.ioNumber
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingIO) {
|
||||||
|
// Update existing record with latest remark and organizer info if provided
|
||||||
|
await existingIO.update({
|
||||||
|
ioRemark: ioData.ioRemark || existingIO.ioRemark || '',
|
||||||
|
organizedBy: organizedBy || existingIO.organizedBy || undefined,
|
||||||
|
organizedAt: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`[DealerClaimService] Existing IO record updated for request: ${requestId}`, {
|
||||||
|
ioNumber: ioData.ioNumber,
|
||||||
|
status: existingIO.status
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new Internal Order record if none exists for this IO and request
|
||||||
await InternalOrder.create({
|
await InternalOrder.create({
|
||||||
requestId,
|
requestId,
|
||||||
ioNumber: ioData.ioNumber,
|
ioNumber: ioData.ioNumber,
|
||||||
@ -1915,15 +1948,6 @@ export class DealerClaimService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update budget tracking with blocked amount FIRST
|
|
||||||
await ClaimBudgetTracking.upsert({
|
|
||||||
requestId,
|
|
||||||
ioBlockedAmount: finalBlockedAmount,
|
|
||||||
ioBlockedAt: new Date(),
|
|
||||||
budgetStatus: BudgetStatus.BLOCKED,
|
|
||||||
currency: 'INR',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save IO history AFTER budget tracking update succeeds (only if ioLevel exists)
|
// Save IO history AFTER budget tracking update succeeds (only if ioLevel exists)
|
||||||
if (ioLevel && ioHistoryUserId) {
|
if (ioLevel && ioHistoryUserId) {
|
||||||
try {
|
try {
|
||||||
@ -2576,6 +2600,22 @@ export class DealerClaimService {
|
|||||||
costItems: costItems.map(i => ({
|
costItems: costItems.map(i => ({
|
||||||
description: i.itemDescription,
|
description: i.itemDescription,
|
||||||
amount: Number(i.amount || 0),
|
amount: Number(i.amount || 0),
|
||||||
|
quantity: Number(i.quantity || 1),
|
||||||
|
hsnCode: i.hsnCode || '',
|
||||||
|
gstRate: Number(i.gstRate || 0),
|
||||||
|
gstAmt: Number(i.gstAmt || 0),
|
||||||
|
cgstRate: Number(i.cgstRate || 0),
|
||||||
|
cgstAmt: Number(i.cgstAmt || 0),
|
||||||
|
sgstRate: Number(i.sgstRate || 0),
|
||||||
|
sgstAmt: Number(i.sgstAmt || 0),
|
||||||
|
igstRate: Number(i.igstRate || 0),
|
||||||
|
igstAmt: Number(i.igstAmt || 0),
|
||||||
|
utgstRate: Number(i.utgstRate || 0),
|
||||||
|
utgstAmt: Number(i.utgstAmt || 0),
|
||||||
|
cessRate: Number(i.cessRate || 0),
|
||||||
|
cessAmt: Number(i.cessAmt || 0),
|
||||||
|
totalAmt: Number(i.totalAmt || 0),
|
||||||
|
isService: !!i.isService,
|
||||||
order: i.itemOrder
|
order: i.itemOrder
|
||||||
})),
|
})),
|
||||||
otherDocuments: supportingDocs.map(doc => ({
|
otherDocuments: supportingDocs.map(doc => ({
|
||||||
|
|||||||
@ -284,84 +284,84 @@ export class DealerClaimApprovalService {
|
|||||||
// Fallback: proceed to Step 4 normally if history check fails
|
// Fallback: proceed to Step 4 normally if history check fails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
logger.info(`[DealerClaimApproval] No next level found after level ${currentLevelNumber} - this may be the final approval`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextLevel) {
|
// Important: Update nextLevelNumber in case nextLevel was shifted (e.g. Step 4 skip)
|
||||||
// Check if next level is paused - if so, don't activate it
|
// This ensures WorkflowRequest.currentLevel is updated to the correct active level
|
||||||
if ((nextLevel as any).isPaused || (nextLevel as any).status === 'PAUSED') {
|
const finalNextLevelNumber = nextLevel ? (nextLevel.levelNumber || 0) : null;
|
||||||
logger.warn(`[DealerClaimApproval] Cannot activate next level ${nextLevelNumber} - level is paused`);
|
|
||||||
throw new Error('Cannot activate next level - the next approval level is currently paused. Please resume it first.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Activate next level
|
if (nextLevel) {
|
||||||
await nextLevel.update({
|
// Check if next level is paused - if so, don't activate it
|
||||||
status: ApprovalStatus.IN_PROGRESS,
|
if ((nextLevel as any).isPaused || (nextLevel as any).status === 'PAUSED') {
|
||||||
levelStartTime: now,
|
logger.warn(`[DealerClaimApproval] Cannot activate next level ${finalNextLevelNumber} - level is paused`);
|
||||||
tatStartTime: now
|
throw new Error('Cannot activate next level - the next approval level is currently paused. Please resume it first.');
|
||||||
});
|
|
||||||
|
|
||||||
// Schedule TAT jobs for the next level
|
|
||||||
try {
|
|
||||||
const workflowPriority = (wf as any)?.priority || 'STANDARD';
|
|
||||||
|
|
||||||
await tatSchedulerService.scheduleTatJobs(
|
|
||||||
level.requestId,
|
|
||||||
(nextLevel as any).levelId,
|
|
||||||
(nextLevel as any).approverId,
|
|
||||||
Number((nextLevel as any).tatHours),
|
|
||||||
now,
|
|
||||||
workflowPriority
|
|
||||||
);
|
|
||||||
logger.info(`[DealerClaimApproval] TAT jobs scheduled for next level ${nextLevelNumber} (Priority: ${workflowPriority})`);
|
|
||||||
} catch (tatError) {
|
|
||||||
logger.error(`[DealerClaimApproval] Failed to schedule TAT jobs for next level:`, tatError);
|
|
||||||
// Don't fail the approval if TAT scheduling fails
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update workflow current level
|
|
||||||
if (nextLevelNumber !== null) {
|
|
||||||
await WorkflowRequest.update(
|
|
||||||
{ currentLevel: nextLevelNumber },
|
|
||||||
{ where: { requestId: level.requestId } }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update the APPROVE snapshot's changeReason to include movement information
|
|
||||||
// This ensures the approval snapshot shows both the approval and the movement
|
|
||||||
// We don't create a separate WORKFLOW snapshot for approvals - only APPROVE snapshot
|
|
||||||
try {
|
|
||||||
const { DealerClaimHistory } = await import('@models/DealerClaimHistory');
|
|
||||||
const { SnapshotType } = await import('@models/DealerClaimHistory');
|
|
||||||
|
|
||||||
const approvalHistory = await DealerClaimHistory.findOne({
|
|
||||||
where: {
|
|
||||||
requestId: level.requestId,
|
|
||||||
approvalLevelId: level.levelId,
|
|
||||||
snapshotType: SnapshotType.APPROVE
|
|
||||||
},
|
|
||||||
order: [['createdAt', 'DESC']]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (approvalHistory) {
|
|
||||||
// Use the robust approvalComment from outer scope
|
|
||||||
const updatedChangeReason = approvalComment
|
|
||||||
? `Approved by ${level.approverName || level.approverEmail}, moved to next level (${nextLevelNumber}). Comment: ${approvalComment}`
|
|
||||||
: `Approved by ${level.approverName || level.approverEmail}, moved to next level (${nextLevelNumber})`;
|
|
||||||
|
|
||||||
await approvalHistory.update({
|
|
||||||
changeReason: updatedChangeReason
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (updateError) {
|
|
||||||
// Log error but don't fail - this is just updating the changeReason for better display
|
|
||||||
logger.warn(`[DealerClaimApproval] Failed to update approval history changeReason (non-critical):`, updateError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`[DealerClaimApproval] Approved level ${level.levelNumber}. Activated next level ${nextLevelNumber} for workflow ${level.requestId}`);
|
// Activate next level
|
||||||
}
|
await nextLevel.update({
|
||||||
|
status: ApprovalStatus.IN_PROGRESS,
|
||||||
|
levelStartTime: now,
|
||||||
|
tatStartTime: now
|
||||||
|
});
|
||||||
|
|
||||||
// Handle dealer claim-specific step processing
|
// Schedule TAT jobs for the next level
|
||||||
|
try {
|
||||||
|
const workflowPriority = (wf as any)?.priority || 'STANDARD';
|
||||||
|
|
||||||
|
await tatSchedulerService.scheduleTatJobs(
|
||||||
|
level.requestId,
|
||||||
|
(nextLevel as any).levelId,
|
||||||
|
(nextLevel as any).approverId,
|
||||||
|
Number((nextLevel as any).tatHours),
|
||||||
|
now,
|
||||||
|
workflowPriority
|
||||||
|
);
|
||||||
|
logger.info(`[DealerClaimApproval] TAT jobs scheduled for next level ${finalNextLevelNumber} (Priority: ${workflowPriority})`);
|
||||||
|
} catch (tatError) {
|
||||||
|
logger.error(`[DealerClaimApproval] Failed to schedule TAT jobs for next level:`, tatError);
|
||||||
|
// Don't fail the approval if TAT scheduling fails
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update workflow current level
|
||||||
|
if (finalNextLevelNumber !== null) {
|
||||||
|
await WorkflowRequest.update(
|
||||||
|
{ currentLevel: finalNextLevelNumber },
|
||||||
|
{ where: { requestId: level.requestId } }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the APPROVE snapshot's changeReason to include movement information
|
||||||
|
// This ensures the approval snapshot shows both the approval and the movement
|
||||||
|
// We don't create a separate WORKFLOW snapshot for approvals - only APPROVE snapshot
|
||||||
|
try {
|
||||||
|
const { DealerClaimHistory } = await import('@models/DealerClaimHistory');
|
||||||
|
const { SnapshotType } = await import('@models/DealerClaimHistory');
|
||||||
|
|
||||||
|
const approvalHistory = await DealerClaimHistory.findOne({
|
||||||
|
where: {
|
||||||
|
requestId: level.requestId,
|
||||||
|
approvalLevelId: level.levelId,
|
||||||
|
snapshotType: SnapshotType.APPROVE
|
||||||
|
},
|
||||||
|
order: [['createdAt', 'DESC']]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (approvalHistory) {
|
||||||
|
// Use the robust approvalComment from outer scope
|
||||||
|
const updatedChangeReason = approvalComment
|
||||||
|
? `Approved by ${level.approverName || level.approverEmail}, moved to next level (${finalNextLevelNumber}). Comment: ${approvalComment}`
|
||||||
|
: `Approved by ${level.approverName || level.approverEmail}, moved to next level (${finalNextLevelNumber})`;
|
||||||
|
|
||||||
|
await approvalHistory.update({
|
||||||
|
changeReason: updatedChangeReason
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (updateError) {
|
||||||
|
// Log error but don't fail - this is just updating the changeReason for better display
|
||||||
|
logger.warn(`[DealerClaimApproval] Failed to update approval history changeReason (non-critical):`, updateError);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`[DealerClaimApproval] Approved level ${level.levelNumber}. Activated next level ${finalNextLevelNumber} for workflow ${level.requestId}`);
|
||||||
|
}
|
||||||
|
} // Handle dealer claim-specific step processing
|
||||||
const currentLevelName = (level.levelName || '').toLowerCase();
|
const currentLevelName = (level.levelName || '').toLowerCase();
|
||||||
// Check by levelName first, use levelNumber only as fallback if levelName is missing
|
// Check by levelName first, use levelNumber only as fallback if levelName is missing
|
||||||
// This handles cases where additional approvers shift step numbers
|
// This handles cases where additional approvers shift step numbers
|
||||||
|
|||||||
@ -114,12 +114,10 @@ export class PWCIntegrationService {
|
|||||||
// Extract State Code from Dealer GSTIN
|
// Extract State Code from Dealer GSTIN
|
||||||
let dealerGst = dealer?.gstin;
|
let dealerGst = dealer?.gstin;
|
||||||
|
|
||||||
const uatGst = '24AAAPI3182M002';
|
|
||||||
const isDevOrUat = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'uat';
|
const isDevOrUat = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'uat';
|
||||||
|
|
||||||
if (isDevOrUat) {
|
if (isDevOrUat) {
|
||||||
logger.info(`[PWC] Using Dev/UAT authorized GSTIN replacement: ${uatGst} (Original: ${dealerGst || 'empty'})`);
|
logger.info(`[PWC] Running in ${process.env.NODE_ENV} mode. Original Dealer GST: ${dealerGst || 'empty'}`);
|
||||||
dealerGst = uatGst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`[PWC] Final GSTIN being used for authentication and seller: ${dealerGst}`);
|
logger.info(`[PWC] Final GSTIN being used for authentication and seller: ${dealerGst}`);
|
||||||
@ -434,7 +432,7 @@ export class PWCIntegrationService {
|
|||||||
TrdNm: dealer?.dealerName || 'Dealer',
|
TrdNm: dealer?.dealerName || 'Dealer',
|
||||||
Addr1: dealer?.city || "Address Line 1",
|
Addr1: dealer?.city || "Address Line 1",
|
||||||
Loc: dealer?.city || "Location",
|
Loc: dealer?.city || "Location",
|
||||||
Pin: Number(dealer?.pincode || (dealerGst === uatGst ? 380001 : 600001)),
|
Pin: Number(dealer?.pincode || 600001),
|
||||||
Stcd: dealerStateCode,
|
Stcd: dealerStateCode,
|
||||||
Ph: dealer?.phone || "9998887776",
|
Ph: dealer?.phone || "9998887776",
|
||||||
Em: dealer?.email || "Supplier@inv.com"
|
Em: dealer?.email || "Supplier@inv.com"
|
||||||
|
|||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user