diff --git a/docs/DEALERS_CSV_IMPORT_FIX.sql b/docs/DEALERS_CSV_IMPORT_FIX.sql index 4da9eb6..e8dda46 100644 --- a/docs/DEALERS_CSV_IMPORT_FIX.sql +++ b/docs/DEALERS_CSV_IMPORT_FIX.sql @@ -9,58 +9,7 @@ -- ============================================================ -- Use this COPY command if your CSV has exactly 44 columns (without the auto-generated ones) -\copy public.dealers( - sales_code, - service_code, - gear_code, - gma_code, - region, - dealership, - state, - district, - city, - location, - city_category_pst, - layout_format, - tier_city_category, - on_boarding_charges, - date, - single_format_month_year, - domain_id, - replacement, - termination_resignation_status, - date_of_termination_resignation, - last_date_of_operations, - old_codes, - branch_details, - dealer_principal_name, - dealer_principal_email_id, - dp_contact_number, - dp_contacts, - showroom_address, - showroom_pincode, - workshop_address, - workshop_pincode, - location_district, - state_workshop, - no_of_studios, - website_update, - gst, - pan, - firm_type, - prop_managing_partners_directors, - total_prop_partners_directors, - docs_folder_link, - workshop_gma_codes, - existing_new, - dlrcode -) -FROM 'C:/Users/COMP/Downloads/DEALERS_CLEAN.csv' -WITH ( - FORMAT csv, - HEADER true, - ENCODING 'UTF8' -); +\copy public.dealers (sales_code,service_code,gear_code,gma_code,region,dealership,state,district,city,location,city_category_pst,layout_format,tier_city_category,on_boarding_charges,"date",single_format_month_year,domain_id,replacement,termination_resignation_status,date_of_termination_resignation,last_date_of_operations,old_codes,branch_details,dealer_principal_name,dealer_principal_email_id,dp_contact_number,dp_contacts,showroom_address,showroom_pincode,workshop_address,workshop_pincode,location_district,state_workshop,no_of_studios,website_update,gst,pan,firm_type,prop_managing_partners_directors,total_prop_partners_directors,docs_folder_link,workshop_gma_codes,existing_new,dlrcode) FROM 'C:/Users/BACKPACKERS/Downloads/Dealer_Master.csv' CSV HEADER ENCODING 'WIN1252'; -- ============================================================ diff --git a/src/services/dmsWebhook.service.ts b/src/services/dmsWebhook.service.ts index 5126ed1..e01975f 100644 --- a/src/services/dmsWebhook.service.ts +++ b/src/services/dmsWebhook.service.ts @@ -3,9 +3,13 @@ import { ClaimInvoice } from '../models/ClaimInvoice'; import { ClaimCreditNote } from '../models/ClaimCreditNote'; import { WorkflowRequest } from '../models/WorkflowRequest'; import { ApprovalLevel } from '../models/ApprovalLevel'; +import { DealerClaimDetails } from '../models/DealerClaimDetails'; +import { User } from '../models/User'; import { ApprovalService } from './approval.service'; import logger from '../utils/logger'; import crypto from 'crypto'; +import { activityService } from './activity.service'; +import { notificationService } from './notification.service'; /** * DMS Webhook Service @@ -233,6 +237,14 @@ export class DMSWebhookService { creditNoteNumber: payload.document_no, hasInvoice: !!invoice, }); + + // Log activity and notify initiator + await this.logCreditNoteCreationActivity( + request.requestId, + payload.request_number, + payload.document_no, + creditNote.creditNoteAmount || payload.total_amount || payload.credit_amount + ); } else { // Update existing credit note with DMS response data await creditNote.update({ @@ -255,6 +267,14 @@ export class DMSWebhookService { irnNo: payload.irn_no, hasInvoice: !!invoice, }); + + // Log activity and notify initiator for updated credit note + await this.logCreditNoteCreationActivity( + request.requestId, + payload.request_number, + payload.document_no, + creditNote.creditNoteAmount || payload.total_amount || payload.credit_amount + ); } return { @@ -321,6 +341,149 @@ export class DMSWebhookService { return parts.length > 0 ? parts.join(' | ') : ''; } + /** + * Log Credit Note Creation as activity and notify initiator + * This is called after credit note is created/updated from DMS webhook + */ + private async logCreditNoteCreationActivity( + requestId: string, + requestNumber: string, + creditNoteNumber: string, + creditNoteAmount: number + ): Promise { + try { + // Check if this is a claim management workflow + const request = await WorkflowRequest.findByPk(requestId); + if (!request) { + logger.warn('[DMSWebhook] Request not found for credit note activity logging', { requestId }); + return; + } + + const workflowType = (request as any).workflowType; + if (workflowType !== 'CLAIM_MANAGEMENT') { + logger.info('[DMSWebhook] Not a claim management workflow, skipping credit note activity logging', { + requestId, + workflowType, + }); + return; + } + + const initiatorId = (request as any).initiatorId; + if (!initiatorId) { + logger.warn('[DMSWebhook] Initiator ID not found for credit note notification', { requestId }); + return; + } + + // Log activity + await activityService.log({ + requestId, + type: 'status_change', + user: undefined, // System event (no user means it's a system event) + timestamp: new Date().toISOString(), + action: 'Credit Note Generated', + details: `Credit note generated from DMS. Credit Note Number: ${creditNoteNumber}. Credit Note Amount: ₹${creditNoteAmount || 0}. Request: ${requestNumber}`, + category: 'credit_note', + severity: 'INFO', + }); + + logger.info('[DMSWebhook] Credit note activity logged successfully', { + requestId, + requestNumber, + creditNoteNumber, + }); + + // Get dealer information from claim details + const claimDetails = await DealerClaimDetails.findOne({ + where: { requestId } + }); + + let dealerUserId: string | null = null; + if (claimDetails?.dealerEmail) { + const dealerUser = await User.findOne({ + where: { email: claimDetails.dealerEmail.toLowerCase() }, + attributes: ['userId'], + }); + dealerUserId = dealerUser?.userId || null; + + if (dealerUserId) { + logger.info('[DMSWebhook] Found dealer user for notification', { + requestId, + dealerEmail: claimDetails.dealerEmail, + dealerUserId, + }); + } else { + logger.warn('[DMSWebhook] Dealer email found but user not found in system', { + requestId, + dealerEmail: claimDetails.dealerEmail, + }); + } + } else { + logger.info('[DMSWebhook] No dealer email found in claim details', { requestId }); + } + + // Send notification to initiator + await notificationService.sendToUsers([initiatorId], { + title: 'Credit Note Generated', + body: `Credit note ${creditNoteNumber} has been generated for request ${requestNumber}. Amount: ₹${creditNoteAmount || 0}`, + requestId, + requestNumber, + url: `/request/${requestNumber}`, + type: 'status_change', + priority: 'MEDIUM', + actionRequired: false, + metadata: { + creditNoteNumber, + creditNoteAmount, + source: 'dms_webhook', + }, + }); + + logger.info('[DMSWebhook] Credit note notification sent to initiator', { + requestId, + requestNumber, + initiatorId, + creditNoteNumber, + }); + + // Send notification to dealer if dealer user exists + if (dealerUserId) { + await notificationService.sendToUsers([dealerUserId], { + title: 'Credit Note Generated', + body: `Credit note ${creditNoteNumber} has been generated for your claim request ${requestNumber}. Amount: ₹${creditNoteAmount || 0}`, + requestId, + requestNumber, + url: `/request/${requestNumber}`, + type: 'status_change', + priority: 'MEDIUM', + actionRequired: false, + metadata: { + creditNoteNumber, + creditNoteAmount, + source: 'dms_webhook', + recipient: 'dealer', + }, + }); + + logger.info('[DMSWebhook] Credit note notification sent to dealer', { + requestId, + requestNumber, + dealerUserId, + dealerEmail: claimDetails?.dealerEmail, + creditNoteNumber, + }); + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + logger.error('[DMSWebhook] Error logging credit note activity:', { + requestId, + requestNumber, + error: errorMessage, + }); + // Don't throw error - webhook processing should continue even if activity/notification fails + // The credit note is already created/updated, which is the primary goal + } + } + /** * Log E-Invoice Generation as activity (no longer an approval step) * This is called after invoice is created/updated from DMS webhook