Compare commits
3 Commits
5be1e319b0
...
f679317d4a
| Author | SHA1 | Date | |
|---|---|---|---|
| f679317d4a | |||
| 7488ae3bee | |||
| 2fee63dc44 |
@ -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 -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<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/radix-vendor-CYvDqP9X.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/redux-vendor-tbZCm13o.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>
|
||||
|
||||
<body>
|
||||
|
||||
@ -66,7 +66,7 @@ function deleteTempFile(tempPath: string): void {
|
||||
* Malware scan middleware for single file uploads (multer.single)
|
||||
* Works with memory storage — writes buffer to temp → scans → deletes temp
|
||||
*/
|
||||
export function malwareScanMiddleware(req: Request, res: Response, next: NextFunction): void {
|
||||
export async function malwareScanMiddleware(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
// Skip if no file uploaded
|
||||
const file = req.file;
|
||||
if (!file) {
|
||||
@ -79,14 +79,14 @@ export function malwareScanMiddleware(req: Request, res: Response, next: NextFun
|
||||
req.scanEventId = scanEventId;
|
||||
|
||||
// Handle the async scan
|
||||
performScan(file, scanEventId, req, res, next);
|
||||
await performScan(file, scanEventId, req, res, next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Malware scan middleware for multiple file uploads (multer.array / multer.fields)
|
||||
* Scans all files and blocks if ANY file is infected
|
||||
*/
|
||||
export function malwareScanMultipleMiddleware(req: Request, res: Response, next: NextFunction): void {
|
||||
export async function malwareScanMultipleMiddleware(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
// Handle multer.array()
|
||||
const files = req.files;
|
||||
if (!files || (Array.isArray(files) && files.length === 0)) {
|
||||
@ -100,7 +100,7 @@ export function malwareScanMultipleMiddleware(req: Request, res: Response, next:
|
||||
|
||||
// Handle array of files
|
||||
if (Array.isArray(files)) {
|
||||
performMultiScan(files, scanEventId, req, res, next);
|
||||
await performMultiScan(files, scanEventId, req, res, next);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ export function malwareScanMultipleMiddleware(req: Request, res: Response, next:
|
||||
return next();
|
||||
}
|
||||
|
||||
performMultiScan(allFiles, scanEventId, req, res, next);
|
||||
await performMultiScan(allFiles, scanEventId, req, res, next);
|
||||
}
|
||||
|
||||
// ── Core scan logic ──
|
||||
@ -132,7 +132,7 @@ async function performScan(
|
||||
try {
|
||||
// Step 0: Pre-scan file validation (extension, MIME, magic bytes, blocked patterns)
|
||||
const maxSizeMB = parseInt(process.env.MAX_FILE_SIZE_MB || '50', 10);
|
||||
const validation = validateFile(
|
||||
const validation = await validateFile(
|
||||
file.originalname,
|
||||
file.mimetype,
|
||||
file.buffer || null,
|
||||
@ -304,7 +304,7 @@ async function performMultiScan(
|
||||
|
||||
// Step 0: Pre-scan file validation
|
||||
const maxSizeMB = parseInt(process.env.MAX_FILE_SIZE_MB || '50', 10);
|
||||
const validation = validateFile(
|
||||
const validation = await validateFile(
|
||||
file.originalname,
|
||||
file.mimetype,
|
||||
file.buffer || null,
|
||||
|
||||
@ -63,7 +63,7 @@ router.get('/:requestId', authenticateToken, validateParams(requestIdParamsSchem
|
||||
* @desc Submit dealer proposal (Step 1)
|
||||
* @access Private
|
||||
*/
|
||||
router.post('/:requestId/proposal', authenticateToken, validateParams(requestIdParamsSchema), upload.single('proposalDocument'), malwareScanMiddleware, asyncHandler(dealerClaimController.submitProposal.bind(dealerClaimController)));
|
||||
router.post('/:requestId/proposal', authenticateToken, validateParams(requestIdParamsSchema), upload.single('proposalDocument'), asyncHandler(malwareScanMiddleware), asyncHandler(dealerClaimController.submitProposal.bind(dealerClaimController)));
|
||||
|
||||
/**
|
||||
* @route POST /api/v1/dealer-claims/:requestId/completion
|
||||
@ -75,7 +75,7 @@ router.post('/:requestId/completion', authenticateToken, uploadLimiter, validate
|
||||
{ name: 'activityPhotos', maxCount: 10 },
|
||||
{ name: 'invoicesReceipts', maxCount: 10 },
|
||||
{ name: 'attendanceSheet', maxCount: 1 },
|
||||
]), malwareScanMultipleMiddleware, asyncHandler(dealerClaimController.submitCompletion.bind(dealerClaimController)));
|
||||
]), asyncHandler(malwareScanMultipleMiddleware), asyncHandler(dealerClaimController.submitCompletion.bind(dealerClaimController)));
|
||||
|
||||
/**
|
||||
* @route GET /api/v1/dealer-claims/:requestId/io/validate
|
||||
@ -105,7 +105,7 @@ router.get('/:requestId/e-invoice/pdf', authenticateToken, validateParams(reques
|
||||
* @access Private
|
||||
*/
|
||||
router.get('/:requestId/e-invoice/csv', authenticateToken, validateParams(requestIdParamsSchema), asyncHandler(dealerClaimController.downloadInvoiceCsv.bind(dealerClaimController)));
|
||||
router.post('/:requestId/credit-note', authenticateToken, validateParams(requestIdParamsSchema), upload.single('creditNoteFile'), malwareScanMiddleware, asyncHandler(dealerClaimController.updateCreditNote.bind(dealerClaimController)));
|
||||
router.post('/:requestId/credit-note', authenticateToken, validateParams(requestIdParamsSchema), upload.single('creditNoteFile'), asyncHandler(malwareScanMiddleware), asyncHandler(dealerClaimController.updateCreditNote.bind(dealerClaimController)));
|
||||
|
||||
/**
|
||||
* @route POST /api/v1/dealer-claims/:requestId/credit-note/send
|
||||
|
||||
@ -22,6 +22,6 @@ const controller = new DocumentController();
|
||||
|
||||
// multipart/form-data: file, requestId, optional category
|
||||
// Middleware chain: auth → multer → malware scan → controller
|
||||
router.post('/', authenticateToken, upload.single('file'), malwareScanMiddleware, asyncHandler(controller.upload.bind(controller)));
|
||||
router.post('/', authenticateToken, upload.single('file'), asyncHandler(malwareScanMiddleware), asyncHandler(controller.upload.bind(controller)));
|
||||
|
||||
export default router;
|
||||
|
||||
@ -1183,10 +1183,18 @@ export class DealerClaimService {
|
||||
hsnCode: item.hsnCode || '',
|
||||
gstRate: Number(item.gstRate) || 0,
|
||||
gstAmt: Number(item.gstAmt) || 0,
|
||||
cgstRate: Number(item.cgstRate) || 0,
|
||||
cgstAmt: Number(item.cgstAmt) || 0,
|
||||
sgstRate: Number(item.sgstRate) || 0,
|
||||
sgstAmt: Number(item.sgstAmt) || 0,
|
||||
igstRate: Number(item.igstRate) || 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
|
||||
@ -1268,6 +1276,7 @@ export class DealerClaimService {
|
||||
proposalDetails: transformedProposalDetails,
|
||||
completionDetails: serializedCompletionDetails,
|
||||
internalOrder: serializedInternalOrder,
|
||||
internalOrders: serializedInternalOrders, // Return full list for UI
|
||||
// New normalized tables
|
||||
budgetTracking: serializedBudgetTracking,
|
||||
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 (blockedAmount <= 0) {
|
||||
// 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) {
|
||||
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({
|
||||
requestId,
|
||||
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)
|
||||
if (ioLevel && ioHistoryUserId) {
|
||||
try {
|
||||
@ -2576,6 +2600,22 @@ export class DealerClaimService {
|
||||
costItems: costItems.map(i => ({
|
||||
description: i.itemDescription,
|
||||
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
|
||||
})),
|
||||
otherDocuments: supportingDocs.map(doc => ({
|
||||
|
||||
@ -284,14 +284,15 @@ export class DealerClaimApprovalService {
|
||||
// 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`);
|
||||
}
|
||||
|
||||
// Important: Update nextLevelNumber in case nextLevel was shifted (e.g. Step 4 skip)
|
||||
// This ensures WorkflowRequest.currentLevel is updated to the correct active level
|
||||
const finalNextLevelNumber = nextLevel ? (nextLevel.levelNumber || 0) : null;
|
||||
|
||||
if (nextLevel) {
|
||||
// Check if next level is paused - if so, don't activate it
|
||||
if ((nextLevel as any).isPaused || (nextLevel as any).status === 'PAUSED') {
|
||||
logger.warn(`[DealerClaimApproval] Cannot activate next level ${nextLevelNumber} - level is paused`);
|
||||
logger.warn(`[DealerClaimApproval] Cannot activate next level ${finalNextLevelNumber} - level is paused`);
|
||||
throw new Error('Cannot activate next level - the next approval level is currently paused. Please resume it first.');
|
||||
}
|
||||
|
||||
@ -314,16 +315,16 @@ export class DealerClaimApprovalService {
|
||||
now,
|
||||
workflowPriority
|
||||
);
|
||||
logger.info(`[DealerClaimApproval] TAT jobs scheduled for next level ${nextLevelNumber} (Priority: ${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 (nextLevelNumber !== null) {
|
||||
if (finalNextLevelNumber !== null) {
|
||||
await WorkflowRequest.update(
|
||||
{ currentLevel: nextLevelNumber },
|
||||
{ currentLevel: finalNextLevelNumber },
|
||||
{ where: { requestId: level.requestId } }
|
||||
);
|
||||
|
||||
@ -346,8 +347,8 @@ export class DealerClaimApprovalService {
|
||||
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})`;
|
||||
? `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
|
||||
@ -358,10 +359,9 @@ export class DealerClaimApprovalService {
|
||||
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}`);
|
||||
logger.info(`[DealerClaimApproval] Approved level ${level.levelNumber}. Activated next level ${finalNextLevelNumber} for workflow ${level.requestId}`);
|
||||
}
|
||||
|
||||
// Handle dealer claim-specific step processing
|
||||
} // Handle dealer claim-specific step processing
|
||||
const currentLevelName = (level.levelName || '').toLowerCase();
|
||||
// Check by levelName first, use levelNumber only as fallback if levelName is missing
|
||||
// This handles cases where additional approvers shift step numbers
|
||||
|
||||
@ -7,8 +7,11 @@
|
||||
* - Path traversal blocking (e.g., ../../etc/passwd)
|
||||
* - Magic bytes / file signature validation
|
||||
* - Filename sanitization
|
||||
* - Configuration-driven allowed file types
|
||||
*/
|
||||
|
||||
import { getConfigValue } from '../configReader.service';
|
||||
|
||||
// ── Types ──
|
||||
|
||||
export interface FileValidationResult {
|
||||
@ -123,19 +126,29 @@ const BLOCKED_PATTERNS: Array<{ pattern: RegExp; reason: string }> = [
|
||||
* Validate an uploaded file for security concerns.
|
||||
* This runs BEFORE ClamAV and catches things ClamAV won't flag.
|
||||
*/
|
||||
export function validateFile(
|
||||
export async function validateFile(
|
||||
originalName: string,
|
||||
mimeType: string,
|
||||
fileBuffer: Buffer | null,
|
||||
fileSizeBytes: number,
|
||||
maxSizeMB: number = 50,
|
||||
): FileValidationResult {
|
||||
): Promise<FileValidationResult> {
|
||||
const errors: string[] = [];
|
||||
const warnings: string[] = [];
|
||||
|
||||
// 1. Extract and validate extension
|
||||
const ext = originalName.split('.').pop()?.toLowerCase() || '';
|
||||
const allowedExtensions = Object.keys(EXTENSION_MIME_MAP);
|
||||
|
||||
// Get allowed extensions from config, fallback to default EXTENSION_MIME_MAP keys
|
||||
const allowedTypesConfig = await getConfigValue('ALLOWED_FILE_TYPES', '');
|
||||
let allowedExtensions: string[];
|
||||
|
||||
if (allowedTypesConfig) {
|
||||
// e.g., "pdf, docx, jpg" -> ["pdf", "docx", "jpg"]
|
||||
allowedExtensions = allowedTypesConfig.split(',').map(e => e.trim().toLowerCase()).filter(e => e);
|
||||
} else {
|
||||
allowedExtensions = Object.keys(EXTENSION_MIME_MAP);
|
||||
}
|
||||
|
||||
if (!ext) {
|
||||
errors.push('File has no extension');
|
||||
@ -160,13 +173,14 @@ export function validateFile(
|
||||
errors.push('File is empty (0 bytes)');
|
||||
}
|
||||
|
||||
// 4. MIME type ↔ extension mismatch detection (warning only — browsers/multer can report wrong MIME)
|
||||
// 4. MIME type ↔ extension mismatch detection
|
||||
let mimeMatchesExtension = true;
|
||||
if (ext && EXTENSION_MIME_MAP[ext]) {
|
||||
const allowedMimes = EXTENSION_MIME_MAP[ext];
|
||||
if (!allowedMimes.includes(mimeType) && mimeType !== 'application/octet-stream') {
|
||||
mimeMatchesExtension = false;
|
||||
warnings.push(
|
||||
// Block if the uploaded file's claimed mimetype doesn't match its extension
|
||||
errors.push(
|
||||
`MIME type mismatch: file claims ".${ext}" but has MIME "${mimeType}". ` +
|
||||
`Expected: ${allowedMimes.join(' or ')}`
|
||||
);
|
||||
@ -186,15 +200,26 @@ export function validateFile(
|
||||
// Check if magic bytes match claimed extension
|
||||
if (ext) {
|
||||
const expectedSignatures = MAGIC_BYTES.filter(m => m.ext === ext);
|
||||
// If we know the expected signatures for this extension, enforce them
|
||||
if (expectedSignatures.length > 0) {
|
||||
const matchesAny = expectedSignatures.some(sig => matchesBytes(fileBuffer, sig.bytes, sig.offset));
|
||||
if (!matchesAny) {
|
||||
// Warning only — some legitimate files have variant headers
|
||||
// ClamAV will do the real malware check
|
||||
warnings.push(
|
||||
`File header does not match ".${ext}" signature — file may be corrupted or mislabeled`
|
||||
// Block uploads where the file's actual magic bytes do not match the expected ones
|
||||
errors.push(
|
||||
`File header does not match ".${ext}" signature — file may be a different type disguised as ".${ext}"`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// If we DON'T strictly know the signatures for this extension,
|
||||
// we should check if its bytes match a KNOWN DIFFERENT file type
|
||||
for (const { ext: knownExt, bytes: knownBytes, offset: knownOffset } of MAGIC_BYTES) {
|
||||
if (knownExt !== ext && matchesBytes(fileBuffer, knownBytes, knownOffset)) {
|
||||
errors.push(
|
||||
`File signature mismatch: claims to be ".${ext}" but header matches ".${knownExt}"`
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -114,12 +114,10 @@ export class PWCIntegrationService {
|
||||
// Extract State Code from Dealer GSTIN
|
||||
let dealerGst = dealer?.gstin;
|
||||
|
||||
const uatGst = '24AAAPI3182M002';
|
||||
const isDevOrUat = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'uat';
|
||||
|
||||
if (isDevOrUat) {
|
||||
logger.info(`[PWC] Using Dev/UAT authorized GSTIN replacement: ${uatGst} (Original: ${dealerGst || 'empty'})`);
|
||||
dealerGst = uatGst;
|
||||
logger.info(`[PWC] Running in ${process.env.NODE_ENV} mode. Original Dealer GST: ${dealerGst || 'empty'}`);
|
||||
}
|
||||
|
||||
logger.info(`[PWC] Final GSTIN being used for authentication and seller: ${dealerGst}`);
|
||||
@ -434,7 +432,7 @@ export class PWCIntegrationService {
|
||||
TrdNm: dealer?.dealerName || 'Dealer',
|
||||
Addr1: dealer?.city || "Address Line 1",
|
||||
Loc: dealer?.city || "Location",
|
||||
Pin: Number(dealer?.pincode || (dealerGst === uatGst ? 380001 : 600001)),
|
||||
Pin: Number(dealer?.pincode || 600001),
|
||||
Stcd: dealerStateCode,
|
||||
Ph: dealer?.phone || "9998887776",
|
||||
Em: dealer?.email || "Supplier@inv.com"
|
||||
|
||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user