enhancd expens and cost items to support gst values addd pwc service file to integrate pwc
This commit is contained in:
parent
2282d29322
commit
17c62d2b45
119
src/migrations/20260209-add-gst-and-pwc-fields.ts
Normal file
119
src/migrations/20260209-add-gst-and-pwc-fields.ts
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import { QueryInterface, DataTypes } from 'sequelize';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to check if a column exists in a table
|
||||||
|
*/
|
||||||
|
async function columnExists(
|
||||||
|
queryInterface: QueryInterface,
|
||||||
|
tableName: string,
|
||||||
|
columnName: string
|
||||||
|
): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const tableDescription = await queryInterface.describeTable(tableName);
|
||||||
|
return columnName in tableDescription;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function up(queryInterface: QueryInterface): Promise<void> {
|
||||||
|
// 1. ActivityType
|
||||||
|
const activityCols = {
|
||||||
|
hsn_code: { type: DataTypes.STRING(20), allowNull: true },
|
||||||
|
sac_code: { type: DataTypes.STRING(20), allowNull: true },
|
||||||
|
gst_rate: { type: DataTypes.DECIMAL(5, 2), allowNull: true },
|
||||||
|
gl_code: { type: DataTypes.STRING(20), allowNull: true },
|
||||||
|
credit_nature: { type: DataTypes.STRING(50), allowNull: true }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [col, spec] of Object.entries(activityCols)) {
|
||||||
|
if (!(await columnExists(queryInterface, 'activity_types', col))) {
|
||||||
|
await queryInterface.addColumn('activity_types', col, spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. GST Fields mapping for Multiple Tables
|
||||||
|
const gstFields = {
|
||||||
|
gst_rate: { type: DataTypes.DECIMAL(5, 2), allowNull: true },
|
||||||
|
gst_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
cgst_rate: { type: DataTypes.DECIMAL(5, 2), allowNull: true },
|
||||||
|
cgst_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
sgst_rate: { type: DataTypes.DECIMAL(5, 2), allowNull: true },
|
||||||
|
sgst_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
igst_rate: { type: DataTypes.DECIMAL(5, 2), allowNull: true },
|
||||||
|
igst_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
utgst_rate: { type: DataTypes.DECIMAL(5, 2), allowNull: true },
|
||||||
|
utgst_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
cess_rate: { type: DataTypes.DECIMAL(5, 2), allowNull: true },
|
||||||
|
cess_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
total_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const tables = ['dealer_proposal_cost_items', 'dealer_completion_expenses', 'claim_credit_notes'];
|
||||||
|
|
||||||
|
for (const table of tables) {
|
||||||
|
for (const [col, spec] of Object.entries(gstFields)) {
|
||||||
|
if (!(await columnExists(queryInterface, table, col))) {
|
||||||
|
await queryInterface.addColumn(table, col, spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add missing expense_date to DealerCompletionExpense
|
||||||
|
if (!(await columnExists(queryInterface, 'dealer_completion_expenses', 'expense_date'))) {
|
||||||
|
await queryInterface.addColumn('dealer_completion_expenses', 'expense_date', { type: DataTypes.DATEONLY, allowNull: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. ClaimInvoice
|
||||||
|
const invoiceCols = {
|
||||||
|
irn: { type: DataTypes.STRING(500), allowNull: true },
|
||||||
|
ack_no: { type: DataTypes.STRING(255), allowNull: true },
|
||||||
|
ack_date: { type: DataTypes.DATE, allowNull: true },
|
||||||
|
signed_invoice: { type: DataTypes.TEXT, allowNull: true },
|
||||||
|
signed_invoice_url: { type: DataTypes.STRING(500), allowNull: true },
|
||||||
|
dealer_claim_number: { type: DataTypes.STRING(100), allowNull: true },
|
||||||
|
qr_code: { type: DataTypes.TEXT, allowNull: true },
|
||||||
|
qr_image: { type: DataTypes.TEXT, allowNull: true },
|
||||||
|
dealer_claim_date: { type: DataTypes.DATEONLY, allowNull: true },
|
||||||
|
billing_no: { type: DataTypes.STRING(100), allowNull: true },
|
||||||
|
billing_date: { type: DataTypes.DATEONLY, allowNull: true },
|
||||||
|
taxable_value: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
cgst_total: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
sgst_total: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
igst_total: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
utgst_total: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
cess_total: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
tcs_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
round_off_amt: { type: DataTypes.DECIMAL(15, 2), allowNull: true },
|
||||||
|
place_of_supply: { type: DataTypes.STRING(255), allowNull: true },
|
||||||
|
total_value_in_words: { type: DataTypes.STRING(500), allowNull: true },
|
||||||
|
tax_value_in_words: { type: DataTypes.STRING(500), allowNull: true },
|
||||||
|
credit_nature: { type: DataTypes.STRING(100), allowNull: true },
|
||||||
|
consignor_gsin: { type: DataTypes.STRING(255), allowNull: true },
|
||||||
|
gstin_date: { type: DataTypes.DATEONLY, allowNull: true }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [col, spec] of Object.entries(invoiceCols)) {
|
||||||
|
if (!(await columnExists(queryInterface, 'claim_invoices', col))) {
|
||||||
|
await queryInterface.addColumn('claim_invoices', col, spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure file_path exists as 'file_path'
|
||||||
|
try {
|
||||||
|
if (!(await columnExists(queryInterface, 'claim_invoices', 'file_path'))) {
|
||||||
|
if (await columnExists(queryInterface, 'claim_invoices', 'invoice_file_path')) {
|
||||||
|
await queryInterface.renameColumn('claim_invoices', 'invoice_file_path', 'file_path');
|
||||||
|
} else {
|
||||||
|
await queryInterface.addColumn('claim_invoices', 'file_path', { type: DataTypes.STRING(500), allowNull: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Silently continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(queryInterface: QueryInterface): Promise<void> {
|
||||||
|
// Note: Best effort rollback (usually not recommended to drop columns in shared dev unless necessary)
|
||||||
|
await queryInterface.removeColumn('dealer_completion_expenses', 'expense_date').catch(() => { });
|
||||||
|
}
|
||||||
@ -9,13 +9,18 @@ interface ActivityTypeAttributes {
|
|||||||
taxationType?: string;
|
taxationType?: string;
|
||||||
sapRefNo?: string;
|
sapRefNo?: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
hsnCode?: string | null;
|
||||||
|
sacCode?: string | null;
|
||||||
|
gstRate?: number | null;
|
||||||
|
glCode?: string | null;
|
||||||
|
creditNature?: 'Commercial' | 'GST' | null;
|
||||||
createdBy: string;
|
createdBy: string;
|
||||||
updatedBy?: string;
|
updatedBy?: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ActivityTypeCreationAttributes extends Optional<ActivityTypeAttributes, 'activityTypeId' | 'itemCode' | 'taxationType' | 'sapRefNo' | 'isActive' | 'updatedBy' | 'createdAt' | 'updatedAt'> {}
|
interface ActivityTypeCreationAttributes extends Optional<ActivityTypeAttributes, 'activityTypeId' | 'itemCode' | 'taxationType' | 'sapRefNo' | 'isActive' | 'updatedBy' | 'createdAt' | 'updatedAt'> { }
|
||||||
|
|
||||||
class ActivityType extends Model<ActivityTypeAttributes, ActivityTypeCreationAttributes> implements ActivityTypeAttributes {
|
class ActivityType extends Model<ActivityTypeAttributes, ActivityTypeCreationAttributes> implements ActivityTypeAttributes {
|
||||||
public activityTypeId!: string;
|
public activityTypeId!: string;
|
||||||
@ -24,6 +29,11 @@ class ActivityType extends Model<ActivityTypeAttributes, ActivityTypeCreationAtt
|
|||||||
public taxationType?: string;
|
public taxationType?: string;
|
||||||
public sapRefNo?: string;
|
public sapRefNo?: string;
|
||||||
public isActive!: boolean;
|
public isActive!: boolean;
|
||||||
|
public hsnCode?: string | null;
|
||||||
|
public sacCode?: string | null;
|
||||||
|
public gstRate?: number | null;
|
||||||
|
public glCode?: string | null;
|
||||||
|
public creditNature?: 'Commercial' | 'GST' | null;
|
||||||
public createdBy!: string;
|
public createdBy!: string;
|
||||||
public updatedBy?: string;
|
public updatedBy?: string;
|
||||||
public createdAt!: Date;
|
public createdAt!: Date;
|
||||||
@ -71,6 +81,31 @@ ActivityType.init(
|
|||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
field: 'is_active'
|
field: 'is_active'
|
||||||
},
|
},
|
||||||
|
hsnCode: {
|
||||||
|
type: DataTypes.STRING(20),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'hsn_code'
|
||||||
|
},
|
||||||
|
sacCode: {
|
||||||
|
type: DataTypes.STRING(20),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sac_code'
|
||||||
|
},
|
||||||
|
gstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'gst_rate'
|
||||||
|
},
|
||||||
|
glCode: {
|
||||||
|
type: DataTypes.STRING(50),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'gl_code'
|
||||||
|
},
|
||||||
|
creditNature: {
|
||||||
|
type: DataTypes.ENUM('Commercial', 'GST'),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'credit_nature'
|
||||||
|
},
|
||||||
createdBy: {
|
createdBy: {
|
||||||
type: DataTypes.UUID,
|
type: DataTypes.UUID,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
|||||||
@ -9,7 +9,20 @@ interface ClaimCreditNoteAttributes {
|
|||||||
invoiceId?: string;
|
invoiceId?: string;
|
||||||
creditNoteNumber?: string;
|
creditNoteNumber?: string;
|
||||||
creditNoteDate?: Date;
|
creditNoteDate?: Date;
|
||||||
creditNoteAmount?: number;
|
creditNoteAmount: number;
|
||||||
|
gstRate?: number;
|
||||||
|
gstAmt?: number;
|
||||||
|
cgstRate?: number;
|
||||||
|
cgstAmt?: number;
|
||||||
|
sgstRate?: number;
|
||||||
|
sgstAmt?: number;
|
||||||
|
igstRate?: number;
|
||||||
|
igstAmt?: number;
|
||||||
|
utgstRate?: number;
|
||||||
|
utgstAmt?: number;
|
||||||
|
cessRate?: number;
|
||||||
|
cessAmt?: number;
|
||||||
|
totalAmt?: number;
|
||||||
sapDocumentNumber?: string;
|
sapDocumentNumber?: string;
|
||||||
creditNoteFilePath?: string;
|
creditNoteFilePath?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
@ -22,7 +35,7 @@ interface ClaimCreditNoteAttributes {
|
|||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ClaimCreditNoteCreationAttributes extends Optional<ClaimCreditNoteAttributes, 'creditNoteId' | 'invoiceId' | 'creditNoteNumber' | 'creditNoteDate' | 'creditNoteAmount' | 'sapDocumentNumber' | 'creditNoteFilePath' | 'status' | 'errorMessage' | 'confirmedBy' | 'confirmedAt' | 'reason' | 'description' | 'createdAt' | 'updatedAt'> {}
|
interface ClaimCreditNoteCreationAttributes extends Optional<ClaimCreditNoteAttributes, 'creditNoteId' | 'invoiceId' | 'creditNoteNumber' | 'creditNoteDate' | 'gstRate' | 'gstAmt' | 'cgstRate' | 'cgstAmt' | 'sgstRate' | 'sgstAmt' | 'igstRate' | 'igstAmt' | 'utgstRate' | 'utgstAmt' | 'cessRate' | 'cessAmt' | 'totalAmt' | 'sapDocumentNumber' | 'creditNoteFilePath' | 'status' | 'errorMessage' | 'confirmedBy' | 'confirmedAt' | 'reason' | 'description' | 'createdAt' | 'updatedAt'> { }
|
||||||
|
|
||||||
class ClaimCreditNote extends Model<ClaimCreditNoteAttributes, ClaimCreditNoteCreationAttributes> implements ClaimCreditNoteAttributes {
|
class ClaimCreditNote extends Model<ClaimCreditNoteAttributes, ClaimCreditNoteCreationAttributes> implements ClaimCreditNoteAttributes {
|
||||||
public creditNoteId!: string;
|
public creditNoteId!: string;
|
||||||
@ -30,7 +43,20 @@ class ClaimCreditNote extends Model<ClaimCreditNoteAttributes, ClaimCreditNoteCr
|
|||||||
public invoiceId?: string;
|
public invoiceId?: string;
|
||||||
public creditNoteNumber?: string;
|
public creditNoteNumber?: string;
|
||||||
public creditNoteDate?: Date;
|
public creditNoteDate?: Date;
|
||||||
public creditNoteAmount?: number;
|
public creditNoteAmount!: number;
|
||||||
|
public gstRate?: number;
|
||||||
|
public gstAmt?: number;
|
||||||
|
public cgstRate?: number;
|
||||||
|
public cgstAmt?: number;
|
||||||
|
public sgstRate?: number;
|
||||||
|
public sgstAmt?: number;
|
||||||
|
public igstRate?: number;
|
||||||
|
public igstAmt?: number;
|
||||||
|
public utgstRate?: number;
|
||||||
|
public utgstAmt?: number;
|
||||||
|
public cessRate?: number;
|
||||||
|
public cessAmt?: number;
|
||||||
|
public totalAmt?: number;
|
||||||
public sapDocumentNumber?: string;
|
public sapDocumentNumber?: string;
|
||||||
public creditNoteFilePath?: string;
|
public creditNoteFilePath?: string;
|
||||||
public status?: string;
|
public status?: string;
|
||||||
@ -86,8 +112,73 @@ ClaimCreditNote.init(
|
|||||||
},
|
},
|
||||||
creditNoteAmount: {
|
creditNoteAmount: {
|
||||||
type: DataTypes.DECIMAL(15, 2),
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: false,
|
||||||
|
field: 'credit_amount'
|
||||||
|
},
|
||||||
|
gstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
field: 'credit_amount',
|
field: 'gst_rate'
|
||||||
|
},
|
||||||
|
gstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'gst_amt'
|
||||||
|
},
|
||||||
|
cgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cgst_rate'
|
||||||
|
},
|
||||||
|
cgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cgst_amt'
|
||||||
|
},
|
||||||
|
sgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sgst_rate'
|
||||||
|
},
|
||||||
|
sgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sgst_amt'
|
||||||
|
},
|
||||||
|
igstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'igst_rate'
|
||||||
|
},
|
||||||
|
igstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'igst_amt'
|
||||||
|
},
|
||||||
|
utgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'utgst_rate'
|
||||||
|
},
|
||||||
|
utgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'utgst_amt'
|
||||||
|
},
|
||||||
|
cessRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cess_rate'
|
||||||
|
},
|
||||||
|
cessAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cess_amt'
|
||||||
|
},
|
||||||
|
totalAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'total_amt'
|
||||||
},
|
},
|
||||||
sapDocumentNumber: {
|
sapDocumentNumber: {
|
||||||
type: DataTypes.STRING(100),
|
type: DataTypes.STRING(100),
|
||||||
|
|||||||
@ -6,11 +6,36 @@ interface ClaimInvoiceAttributes {
|
|||||||
invoiceId: string;
|
invoiceId: string;
|
||||||
requestId: string;
|
requestId: string;
|
||||||
invoiceNumber?: string;
|
invoiceNumber?: string;
|
||||||
invoiceDate?: Date;
|
|
||||||
amount?: number;
|
|
||||||
dmsNumber?: string;
|
dmsNumber?: string;
|
||||||
invoiceFilePath?: string;
|
invoiceDate?: Date;
|
||||||
status?: string;
|
amount: number;
|
||||||
|
status: string;
|
||||||
|
irn?: string | null;
|
||||||
|
ackNo?: string | null;
|
||||||
|
ackDate?: Date | null;
|
||||||
|
signedInvoice?: string | null;
|
||||||
|
signedInvoiceUrl?: string | null;
|
||||||
|
dealerClaimNumber?: string | null;
|
||||||
|
dealerClaimDate?: Date | null;
|
||||||
|
billingNo?: string | null;
|
||||||
|
billingDate?: Date | null;
|
||||||
|
taxableValue?: number | null;
|
||||||
|
cgstTotal?: number | null;
|
||||||
|
sgstTotal?: number | null;
|
||||||
|
igstTotal?: number | null;
|
||||||
|
utgstTotal?: number | null;
|
||||||
|
cessTotal?: number | null;
|
||||||
|
tcsAmt?: number | null;
|
||||||
|
roundOffAmt?: number | null;
|
||||||
|
placeOfSupply?: string | null;
|
||||||
|
totalValueInWords?: string | null;
|
||||||
|
taxValueInWords?: string | null;
|
||||||
|
creditNature?: string | null;
|
||||||
|
consignorGsin?: string | null;
|
||||||
|
gstinDate?: Date | null;
|
||||||
|
filePath?: string | null;
|
||||||
|
qrCode?: string | null;
|
||||||
|
qrImage?: string | null;
|
||||||
errorMessage?: string;
|
errorMessage?: string;
|
||||||
generatedAt?: Date;
|
generatedAt?: Date;
|
||||||
description?: string;
|
description?: string;
|
||||||
@ -18,17 +43,42 @@ interface ClaimInvoiceAttributes {
|
|||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ClaimInvoiceCreationAttributes extends Optional<ClaimInvoiceAttributes, 'invoiceId' | 'invoiceNumber' | 'invoiceDate' | 'amount' | 'dmsNumber' | 'invoiceFilePath' | 'status' | 'errorMessage' | 'generatedAt' | 'description' | 'createdAt' | 'updatedAt'> {}
|
interface ClaimInvoiceCreationAttributes extends Optional<ClaimInvoiceAttributes, 'invoiceId' | 'invoiceNumber' | 'dmsNumber' | 'invoiceDate' | 'irn' | 'ackNo' | 'ackDate' | 'signedInvoice' | 'signedInvoiceUrl' | 'dealerClaimNumber' | 'dealerClaimDate' | 'billingNo' | 'billingDate' | 'taxableValue' | 'cgstTotal' | 'sgstTotal' | 'igstTotal' | 'utgstTotal' | 'cessTotal' | 'tcsAmt' | 'roundOffAmt' | 'placeOfSupply' | 'totalValueInWords' | 'taxValueInWords' | 'creditNature' | 'consignorGsin' | 'gstinDate' | 'filePath' | 'qrCode' | 'qrImage' | 'errorMessage' | 'generatedAt' | 'description' | 'createdAt' | 'updatedAt'> { }
|
||||||
|
|
||||||
class ClaimInvoice extends Model<ClaimInvoiceAttributes, ClaimInvoiceCreationAttributes> implements ClaimInvoiceAttributes {
|
class ClaimInvoice extends Model<ClaimInvoiceAttributes, ClaimInvoiceCreationAttributes> implements ClaimInvoiceAttributes {
|
||||||
public invoiceId!: string;
|
public invoiceId!: string;
|
||||||
public requestId!: string;
|
public requestId!: string;
|
||||||
public invoiceNumber?: string;
|
public invoiceNumber?: string;
|
||||||
public invoiceDate?: Date;
|
|
||||||
public amount?: number;
|
|
||||||
public dmsNumber?: string;
|
public dmsNumber?: string;
|
||||||
public invoiceFilePath?: string;
|
public invoiceDate?: Date;
|
||||||
public status?: string;
|
public amount!: number;
|
||||||
|
public status!: string;
|
||||||
|
public irn?: string | null;
|
||||||
|
public ackNo?: string | null;
|
||||||
|
public ackDate?: Date | null;
|
||||||
|
public signedInvoice?: string | null;
|
||||||
|
public signedInvoiceUrl?: string | null;
|
||||||
|
public dealerClaimNumber?: string | null;
|
||||||
|
public dealerClaimDate?: Date | null;
|
||||||
|
public billingNo?: string | null;
|
||||||
|
public billingDate?: Date | null;
|
||||||
|
public taxableValue?: number | null;
|
||||||
|
public cgstTotal?: number | null;
|
||||||
|
public sgstTotal?: number | null;
|
||||||
|
public igstTotal?: number | null;
|
||||||
|
public utgstTotal?: number | null;
|
||||||
|
public cessTotal?: number | null;
|
||||||
|
public tcsAmt?: number | null;
|
||||||
|
public roundOffAmt?: number | null;
|
||||||
|
public placeOfSupply?: string | null;
|
||||||
|
public totalValueInWords?: string | null;
|
||||||
|
public taxValueInWords?: string | null;
|
||||||
|
public creditNature?: string | null;
|
||||||
|
public consignorGsin?: string | null;
|
||||||
|
public gstinDate?: Date | null;
|
||||||
|
public filePath?: string | null;
|
||||||
|
public qrCode?: string | null;
|
||||||
|
public qrImage?: string | null;
|
||||||
public errorMessage?: string;
|
public errorMessage?: string;
|
||||||
public generatedAt?: Date;
|
public generatedAt?: Date;
|
||||||
public description?: string;
|
public description?: string;
|
||||||
@ -61,6 +111,11 @@ ClaimInvoice.init(
|
|||||||
allowNull: true,
|
allowNull: true,
|
||||||
field: 'invoice_number',
|
field: 'invoice_number',
|
||||||
},
|
},
|
||||||
|
dmsNumber: {
|
||||||
|
type: DataTypes.STRING(100),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'dms_number',
|
||||||
|
},
|
||||||
invoiceDate: {
|
invoiceDate: {
|
||||||
type: DataTypes.DATEONLY,
|
type: DataTypes.DATEONLY,
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
@ -68,23 +123,143 @@ ClaimInvoice.init(
|
|||||||
},
|
},
|
||||||
amount: {
|
amount: {
|
||||||
type: DataTypes.DECIMAL(15, 2),
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
allowNull: true,
|
allowNull: false,
|
||||||
field: 'invoice_amount',
|
field: 'invoice_amount',
|
||||||
},
|
},
|
||||||
dmsNumber: {
|
|
||||||
type: DataTypes.STRING(100),
|
|
||||||
allowNull: true,
|
|
||||||
field: 'dms_number',
|
|
||||||
},
|
|
||||||
invoiceFilePath: {
|
|
||||||
type: DataTypes.STRING(500),
|
|
||||||
allowNull: true,
|
|
||||||
field: 'invoice_file_path',
|
|
||||||
},
|
|
||||||
status: {
|
status: {
|
||||||
type: DataTypes.STRING(50),
|
type: DataTypes.STRING(50),
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 'PENDING',
|
||||||
|
field: 'generation_status'
|
||||||
|
},
|
||||||
|
irn: {
|
||||||
|
type: DataTypes.STRING(500),
|
||||||
|
allowNull: true
|
||||||
|
},
|
||||||
|
ackNo: {
|
||||||
|
type: DataTypes.STRING(255),
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
field: 'generation_status',
|
field: 'ack_no'
|
||||||
|
},
|
||||||
|
ackDate: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'ack_date'
|
||||||
|
},
|
||||||
|
signedInvoice: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'signed_invoice'
|
||||||
|
},
|
||||||
|
signedInvoiceUrl: {
|
||||||
|
type: DataTypes.STRING(500),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'signed_invoice_url'
|
||||||
|
},
|
||||||
|
dealerClaimNumber: {
|
||||||
|
type: DataTypes.STRING(100),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'dealer_claim_number'
|
||||||
|
},
|
||||||
|
dealerClaimDate: {
|
||||||
|
type: DataTypes.DATEONLY,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'dealer_claim_date'
|
||||||
|
},
|
||||||
|
billingNo: {
|
||||||
|
type: DataTypes.STRING(100),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'billing_no'
|
||||||
|
},
|
||||||
|
billingDate: {
|
||||||
|
type: DataTypes.DATEONLY,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'billing_date'
|
||||||
|
},
|
||||||
|
taxableValue: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'taxable_value'
|
||||||
|
},
|
||||||
|
cgstTotal: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cgst_total'
|
||||||
|
},
|
||||||
|
sgstTotal: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sgst_total'
|
||||||
|
},
|
||||||
|
igstTotal: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'igst_total'
|
||||||
|
},
|
||||||
|
utgstTotal: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'utgst_total'
|
||||||
|
},
|
||||||
|
cessTotal: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cess_total'
|
||||||
|
},
|
||||||
|
tcsAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'tcs_amt'
|
||||||
|
},
|
||||||
|
roundOffAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'round_off_amt'
|
||||||
|
},
|
||||||
|
placeOfSupply: {
|
||||||
|
type: DataTypes.STRING(255),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'place_of_supply'
|
||||||
|
},
|
||||||
|
totalValueInWords: {
|
||||||
|
type: DataTypes.STRING(500),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'total_value_in_words'
|
||||||
|
},
|
||||||
|
taxValueInWords: {
|
||||||
|
type: DataTypes.STRING(500),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'tax_value_in_words'
|
||||||
|
},
|
||||||
|
creditNature: {
|
||||||
|
type: DataTypes.STRING(100),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'credit_nature'
|
||||||
|
},
|
||||||
|
consignorGsin: {
|
||||||
|
type: DataTypes.STRING(255),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'consignor_gsin'
|
||||||
|
},
|
||||||
|
gstinDate: {
|
||||||
|
type: DataTypes.DATEONLY,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'gstin_date'
|
||||||
|
},
|
||||||
|
filePath: {
|
||||||
|
type: DataTypes.STRING(500),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'file_path'
|
||||||
|
},
|
||||||
|
qrCode: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'qr_code'
|
||||||
|
},
|
||||||
|
qrImage: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: true,
|
||||||
|
field: 'qr_image'
|
||||||
},
|
},
|
||||||
errorMessage: {
|
errorMessage: {
|
||||||
type: DataTypes.TEXT,
|
type: DataTypes.TEXT,
|
||||||
|
|||||||
@ -9,11 +9,25 @@ interface DealerCompletionExpenseAttributes {
|
|||||||
completionId?: string | null;
|
completionId?: string | null;
|
||||||
description: string;
|
description: string;
|
||||||
amount: number;
|
amount: number;
|
||||||
|
gstRate?: number;
|
||||||
|
gstAmt?: number;
|
||||||
|
cgstRate?: number;
|
||||||
|
cgstAmt?: number;
|
||||||
|
sgstRate?: number;
|
||||||
|
sgstAmt?: number;
|
||||||
|
igstRate?: number;
|
||||||
|
igstAmt?: number;
|
||||||
|
utgstRate?: number;
|
||||||
|
utgstAmt?: number;
|
||||||
|
cessRate?: number;
|
||||||
|
cessAmt?: number;
|
||||||
|
totalAmt?: number;
|
||||||
|
expenseDate: Date;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DealerCompletionExpenseCreationAttributes extends Optional<DealerCompletionExpenseAttributes, 'expenseId' | 'completionId' | 'createdAt' | 'updatedAt'> {}
|
interface DealerCompletionExpenseCreationAttributes extends Optional<DealerCompletionExpenseAttributes, 'expenseId' | 'completionId' | 'createdAt' | 'updatedAt'> { }
|
||||||
|
|
||||||
class DealerCompletionExpense extends Model<DealerCompletionExpenseAttributes, DealerCompletionExpenseCreationAttributes> implements DealerCompletionExpenseAttributes {
|
class DealerCompletionExpense extends Model<DealerCompletionExpenseAttributes, DealerCompletionExpenseCreationAttributes> implements DealerCompletionExpenseAttributes {
|
||||||
public expenseId!: string;
|
public expenseId!: string;
|
||||||
@ -21,6 +35,20 @@ class DealerCompletionExpense extends Model<DealerCompletionExpenseAttributes, D
|
|||||||
public completionId?: string | null;
|
public completionId?: string | null;
|
||||||
public description!: string;
|
public description!: string;
|
||||||
public amount!: number;
|
public amount!: number;
|
||||||
|
public gstRate?: number;
|
||||||
|
public gstAmt?: number;
|
||||||
|
public cgstRate?: number;
|
||||||
|
public cgstAmt?: number;
|
||||||
|
public sgstRate?: number;
|
||||||
|
public sgstAmt?: number;
|
||||||
|
public igstRate?: number;
|
||||||
|
public igstAmt?: number;
|
||||||
|
public utgstRate?: number;
|
||||||
|
public utgstAmt?: number;
|
||||||
|
public cessRate?: number;
|
||||||
|
public cessAmt?: number;
|
||||||
|
public totalAmt?: number;
|
||||||
|
public expenseDate!: Date;
|
||||||
public createdAt!: Date;
|
public createdAt!: Date;
|
||||||
public updatedAt!: Date;
|
public updatedAt!: Date;
|
||||||
}
|
}
|
||||||
@ -63,6 +91,76 @@ DealerCompletionExpense.init(
|
|||||||
allowNull: false,
|
allowNull: false,
|
||||||
field: 'amount',
|
field: 'amount',
|
||||||
},
|
},
|
||||||
|
gstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'gst_rate'
|
||||||
|
},
|
||||||
|
gstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'gst_amt'
|
||||||
|
},
|
||||||
|
cgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cgst_rate'
|
||||||
|
},
|
||||||
|
cgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cgst_amt'
|
||||||
|
},
|
||||||
|
sgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sgst_rate'
|
||||||
|
},
|
||||||
|
sgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sgst_amt'
|
||||||
|
},
|
||||||
|
igstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'igst_rate'
|
||||||
|
},
|
||||||
|
igstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'igst_amt'
|
||||||
|
},
|
||||||
|
utgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'utgst_rate'
|
||||||
|
},
|
||||||
|
utgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'utgst_amt'
|
||||||
|
},
|
||||||
|
cessRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cess_rate'
|
||||||
|
},
|
||||||
|
cessAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cess_amt'
|
||||||
|
},
|
||||||
|
totalAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'total_amt'
|
||||||
|
},
|
||||||
|
expenseDate: {
|
||||||
|
type: DataTypes.DATE,
|
||||||
|
allowNull: false,
|
||||||
|
field: 'expense_date',
|
||||||
|
},
|
||||||
createdAt: {
|
createdAt: {
|
||||||
type: DataTypes.DATE,
|
type: DataTypes.DATE,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
|||||||
@ -9,12 +9,25 @@ interface DealerProposalCostItemAttributes {
|
|||||||
requestId: string;
|
requestId: string;
|
||||||
itemDescription: string;
|
itemDescription: string;
|
||||||
amount: number;
|
amount: number;
|
||||||
|
gstRate?: number;
|
||||||
|
gstAmt?: number;
|
||||||
|
cgstRate?: number;
|
||||||
|
cgstAmt?: number;
|
||||||
|
sgstRate?: number;
|
||||||
|
sgstAmt?: number;
|
||||||
|
igstRate?: number;
|
||||||
|
igstAmt?: number;
|
||||||
|
utgstRate?: number;
|
||||||
|
utgstAmt?: number;
|
||||||
|
cessRate?: number;
|
||||||
|
cessAmt?: number;
|
||||||
|
totalAmt?: number;
|
||||||
itemOrder: number;
|
itemOrder: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DealerProposalCostItemCreationAttributes extends Optional<DealerProposalCostItemAttributes, 'costItemId' | 'itemOrder' | 'createdAt' | 'updatedAt'> {}
|
interface DealerProposalCostItemCreationAttributes extends Optional<DealerProposalCostItemAttributes, 'costItemId' | 'itemOrder' | 'createdAt' | 'updatedAt'> { }
|
||||||
|
|
||||||
class DealerProposalCostItem extends Model<DealerProposalCostItemAttributes, DealerProposalCostItemCreationAttributes> implements DealerProposalCostItemAttributes {
|
class DealerProposalCostItem extends Model<DealerProposalCostItemAttributes, DealerProposalCostItemCreationAttributes> implements DealerProposalCostItemAttributes {
|
||||||
public costItemId!: string;
|
public costItemId!: string;
|
||||||
@ -22,6 +35,19 @@ class DealerProposalCostItem extends Model<DealerProposalCostItemAttributes, Dea
|
|||||||
public requestId!: string;
|
public requestId!: string;
|
||||||
public itemDescription!: string;
|
public itemDescription!: string;
|
||||||
public amount!: number;
|
public amount!: number;
|
||||||
|
public gstRate?: number;
|
||||||
|
public gstAmt?: number;
|
||||||
|
public cgstRate?: number;
|
||||||
|
public cgstAmt?: number;
|
||||||
|
public sgstRate?: number;
|
||||||
|
public sgstAmt?: number;
|
||||||
|
public igstRate?: number;
|
||||||
|
public igstAmt?: number;
|
||||||
|
public utgstRate?: number;
|
||||||
|
public utgstAmt?: number;
|
||||||
|
public cessRate?: number;
|
||||||
|
public cessAmt?: number;
|
||||||
|
public totalAmt?: number;
|
||||||
public itemOrder!: number;
|
public itemOrder!: number;
|
||||||
public createdAt!: Date;
|
public createdAt!: Date;
|
||||||
public updatedAt!: Date;
|
public updatedAt!: Date;
|
||||||
@ -66,6 +92,71 @@ DealerProposalCostItem.init(
|
|||||||
type: DataTypes.DECIMAL(15, 2),
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
|
gstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'gst_rate'
|
||||||
|
},
|
||||||
|
gstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'gst_amt'
|
||||||
|
},
|
||||||
|
cgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cgst_rate'
|
||||||
|
},
|
||||||
|
cgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cgst_amt'
|
||||||
|
},
|
||||||
|
sgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sgst_rate'
|
||||||
|
},
|
||||||
|
sgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'sgst_amt'
|
||||||
|
},
|
||||||
|
igstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'igst_rate'
|
||||||
|
},
|
||||||
|
igstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'igst_amt'
|
||||||
|
},
|
||||||
|
utgstRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'utgst_rate'
|
||||||
|
},
|
||||||
|
utgstAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'utgst_amt'
|
||||||
|
},
|
||||||
|
cessRate: {
|
||||||
|
type: DataTypes.DECIMAL(5, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cess_rate'
|
||||||
|
},
|
||||||
|
cessAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'cess_amt'
|
||||||
|
},
|
||||||
|
totalAmt: {
|
||||||
|
type: DataTypes.DECIMAL(15, 2),
|
||||||
|
allowNull: true,
|
||||||
|
field: 'total_amt'
|
||||||
|
},
|
||||||
itemOrder: {
|
itemOrder: {
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
|||||||
@ -157,6 +157,7 @@ async function runMigrations(): Promise<void> {
|
|||||||
const m42 = require('../migrations/20250125-create-activity-types');
|
const m42 = require('../migrations/20250125-create-activity-types');
|
||||||
const m43 = require('../migrations/20260113-redesign-dealer-claim-history');
|
const m43 = require('../migrations/20260113-redesign-dealer-claim-history');
|
||||||
const m44 = require('../migrations/20260123-fix-template-id-schema');
|
const m44 = require('../migrations/20260123-fix-template-id-schema');
|
||||||
|
const m45 = require('../migrations/20260209-add-gst-and-pwc-fields');
|
||||||
|
|
||||||
const migrations = [
|
const migrations = [
|
||||||
{ name: '2025103000-create-users', module: m0 },
|
{ name: '2025103000-create-users', module: m0 },
|
||||||
@ -206,6 +207,7 @@ async function runMigrations(): Promise<void> {
|
|||||||
{ name: '20250125-create-activity-types', module: m42 },
|
{ name: '20250125-create-activity-types', module: m42 },
|
||||||
{ name: '20260113-redesign-dealer-claim-history', module: m43 },
|
{ name: '20260113-redesign-dealer-claim-history', module: m43 },
|
||||||
{ name: '20260123-fix-template-id-schema', module: m44 },
|
{ name: '20260123-fix-template-id-schema', module: m44 },
|
||||||
|
{ name: '20260209-add-gst-and-pwc-fields', module: m45 },
|
||||||
];
|
];
|
||||||
|
|
||||||
// Dynamically import sequelize after secrets are loaded
|
// Dynamically import sequelize after secrets are loaded
|
||||||
|
|||||||
@ -47,6 +47,7 @@ import * as m41 from '../migrations/20250120-create-dealers-table';
|
|||||||
import * as m42 from '../migrations/20250125-create-activity-types';
|
import * as m42 from '../migrations/20250125-create-activity-types';
|
||||||
import * as m43 from '../migrations/20260113-redesign-dealer-claim-history';
|
import * as m43 from '../migrations/20260113-redesign-dealer-claim-history';
|
||||||
import * as m44 from '../migrations/20260123-fix-template-id-schema';
|
import * as m44 from '../migrations/20260123-fix-template-id-schema';
|
||||||
|
import * as m45 from '../migrations/20260209-add-gst-and-pwc-fields';
|
||||||
|
|
||||||
interface Migration {
|
interface Migration {
|
||||||
name: string;
|
name: string;
|
||||||
@ -108,6 +109,7 @@ const migrations: Migration[] = [
|
|||||||
{ name: '20250125-create-activity-types', module: m42 },
|
{ name: '20250125-create-activity-types', module: m42 },
|
||||||
{ name: '20260113-redesign-dealer-claim-history', module: m43 },
|
{ name: '20260113-redesign-dealer-claim-history', module: m43 },
|
||||||
{ name: '20260123-fix-template-id-schema', module: m44 },
|
{ name: '20260123-fix-template-id-schema', module: m44 },
|
||||||
|
{ name: '20260209-add-gst-and-pwc-fields', module: m45 }
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -247,3 +247,42 @@ export async function searchDealers(searchTerm: string, limit: number = 10): Pro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find dealer in local table by code or email (tiered lookup)
|
||||||
|
* Used as a fallback until external API is available
|
||||||
|
* @param dealerCode - Optional dealer code (dlrcode)
|
||||||
|
* @param email - Optional email (domainId or dealerPrincipalEmailId)
|
||||||
|
*/
|
||||||
|
export async function findDealerLocally(dealerCode?: string, email?: string): Promise<DealerInfo | null> {
|
||||||
|
try {
|
||||||
|
// 1. Try Lookup by Dealer Code
|
||||||
|
if (dealerCode) {
|
||||||
|
const dealer = await getDealerByCode(dealerCode);
|
||||||
|
if (dealer) return dealer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Try Lookup by Email (checks both domainId and dealerPrincipalEmailId)
|
||||||
|
if (email) {
|
||||||
|
const dealer = await Dealer.findOne({
|
||||||
|
where: {
|
||||||
|
[Op.or]: [
|
||||||
|
{ domainId: { [Op.iLike]: email.toLowerCase() } as any },
|
||||||
|
{ dealerPrincipalEmailId: { [Op.iLike]: email.toLowerCase() } as any }
|
||||||
|
],
|
||||||
|
isActive: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dealer) {
|
||||||
|
// reuse same logic as getDealerByEmail for consistency
|
||||||
|
return getDealerByEmail(dealer.domainId || dealer.dealerPrincipalEmailId || email);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('[DealerService] Error in local dealer fallback lookup:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,12 +18,16 @@ import { DealerClaimApprovalService } from './dealerClaimApproval.service';
|
|||||||
import { generateRequestNumber } from '../utils/helpers';
|
import { generateRequestNumber } from '../utils/helpers';
|
||||||
import { Priority, WorkflowStatus, ApprovalStatus, ParticipantType } from '../types/common.types';
|
import { Priority, WorkflowStatus, ApprovalStatus, ParticipantType } from '../types/common.types';
|
||||||
import { sapIntegrationService } from './sapIntegration.service';
|
import { sapIntegrationService } from './sapIntegration.service';
|
||||||
import { dmsIntegrationService } from './dmsIntegration.service';
|
import { pwcIntegrationService } from './pwcIntegration.service';
|
||||||
import { notificationService } from './notification.service';
|
import { notificationService } from './notification.service';
|
||||||
import { activityService } from './activity.service';
|
import { activityService } from './activity.service';
|
||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
|
import { dmsIntegrationService } from './dmsIntegration.service';
|
||||||
|
import { findDealerLocally } from './dealer.service';
|
||||||
import logger from '../utils/logger';
|
import logger from '../utils/logger';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dealer Claim Service
|
* Dealer Claim Service
|
||||||
* Handles business logic specific to dealer claim management workflow
|
* Handles business logic specific to dealer claim management workflow
|
||||||
@ -83,6 +87,15 @@ export class DealerClaimService {
|
|||||||
throw new Error('Initiator not found');
|
throw new Error('Initiator not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback: Enrichment from local dealer table if data is missing or incomplete
|
||||||
|
const localDealer = await findDealerLocally(claimData.dealerCode, claimData.dealerEmail);
|
||||||
|
if (localDealer) {
|
||||||
|
logger.info(`[DealerClaimService] Enriched claim request with local dealer data: ${localDealer.dealerCode}`);
|
||||||
|
claimData.dealerName = claimData.dealerName || localDealer.dealerName;
|
||||||
|
claimData.dealerEmail = claimData.dealerEmail || localDealer.dealerPrincipalEmailId || localDealer.email;
|
||||||
|
claimData.dealerPhone = claimData.dealerPhone || localDealer.phone;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate approvers array is provided
|
// Validate approvers array is provided
|
||||||
if (!claimData.approvers || !Array.isArray(claimData.approvers) || claimData.approvers.length === 0) {
|
if (!claimData.approvers || !Array.isArray(claimData.approvers) || claimData.approvers.length === 0) {
|
||||||
throw new Error('Approvers array is required. Please assign approvers for all workflow steps.');
|
throw new Error('Approvers array is required. Please assign approvers for all workflow steps.');
|
||||||
@ -1260,6 +1273,19 @@ export class DealerClaimService {
|
|||||||
requestId,
|
requestId,
|
||||||
itemDescription: item.description || item.itemDescription || '',
|
itemDescription: item.description || item.itemDescription || '',
|
||||||
amount: Number(item.amount) || 0,
|
amount: Number(item.amount) || 0,
|
||||||
|
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,
|
||||||
|
utgstRate: Number(item.utgstRate) || 0,
|
||||||
|
utgstAmt: Number(item.utgstAmt) || 0,
|
||||||
|
cessRate: Number(item.cessRate) || 0,
|
||||||
|
cessAmt: Number(item.cessAmt) || 0,
|
||||||
|
totalAmt: Number(item.totalAmt) || Number(item.amount) || 0,
|
||||||
itemOrder: index
|
itemOrder: index
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -1397,7 +1423,21 @@ export class DealerClaimService {
|
|||||||
requestId,
|
requestId,
|
||||||
completionId,
|
completionId,
|
||||||
description: item.description,
|
description: item.description,
|
||||||
amount: item.amount,
|
amount: Number(item.amount) || 0,
|
||||||
|
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,
|
||||||
|
utgstRate: Number(item.utgstRate) || 0,
|
||||||
|
utgstAmt: Number(item.utgstAmt) || 0,
|
||||||
|
cessRate: Number(item.cessRate) || 0,
|
||||||
|
cessAmt: Number(item.cessAmt) || 0,
|
||||||
|
totalAmt: Number(item.totalAmt) || Number(item.amount) || 0,
|
||||||
|
expenseDate: item.date instanceof Date ? item.date : (item.date ? new Date(item.date) : (completionData.activityCompletionDate || new Date())),
|
||||||
}));
|
}));
|
||||||
await DealerCompletionExpense.bulkCreate(expenseRows);
|
await DealerCompletionExpense.bulkCreate(expenseRows);
|
||||||
}
|
}
|
||||||
@ -1874,33 +1914,31 @@ export class DealerClaimService {
|
|||||||
|| budgetTracking?.initialEstimatedBudget
|
|| budgetTracking?.initialEstimatedBudget
|
||||||
|| 0;
|
|| 0;
|
||||||
|
|
||||||
const invoiceResult = await dmsIntegrationService.generateEInvoice({
|
const invoiceResult = await pwcIntegrationService.generateSignedInvoice(requestId);
|
||||||
requestNumber,
|
|
||||||
dealerCode: claimDetails.dealerCode,
|
|
||||||
dealerName: claimDetails.dealerName,
|
|
||||||
amount: invoiceAmount,
|
|
||||||
description: invoiceData?.description || `E-Invoice for claim request ${requestNumber}`,
|
|
||||||
ioNumber: internalOrder?.ioNumber || undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!invoiceResult.success) {
|
if (!invoiceResult.success) {
|
||||||
throw new Error(`Failed to generate e-invoice: ${invoiceResult.error}`);
|
throw new Error(`Failed to generate signed e-invoice via PWC: ${invoiceResult.error}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await ClaimInvoice.upsert({
|
await ClaimInvoice.upsert({
|
||||||
requestId,
|
requestId,
|
||||||
invoiceNumber: invoiceResult.eInvoiceNumber,
|
invoiceNumber: invoiceResult.ackNo, // Using Ack No as primary identifier for now
|
||||||
invoiceDate: invoiceResult.invoiceDate || new Date(),
|
invoiceDate: invoiceResult.ackDate instanceof Date ? invoiceResult.ackDate : (invoiceResult.ackDate ? new Date(invoiceResult.ackDate) : new Date()),
|
||||||
dmsNumber: invoiceResult.dmsNumber,
|
irn: invoiceResult.irn,
|
||||||
|
ackNo: invoiceResult.ackNo,
|
||||||
|
ackDate: invoiceResult.ackDate instanceof Date ? invoiceResult.ackDate : (invoiceResult.ackDate ? new Date(invoiceResult.ackDate) : null),
|
||||||
|
signedInvoice: invoiceResult.signedInvoice,
|
||||||
|
qrCode: invoiceResult.qrCode,
|
||||||
|
qrImage: invoiceResult.qrImage,
|
||||||
amount: invoiceAmount,
|
amount: invoiceAmount,
|
||||||
status: 'GENERATED',
|
status: 'GENERATED',
|
||||||
generatedAt: new Date(),
|
generatedAt: new Date(),
|
||||||
description: invoiceData?.description || `E-Invoice for claim request ${requestNumber}`,
|
description: invoiceData?.description || `PWC Signed Invoice for claim request ${requestNumber}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.info(`[DealerClaimService] E-Invoice generated via DMS for request: ${requestId}`, {
|
logger.info(`[DealerClaimService] Signed Invoice generated via PWC for request: ${requestId}`, {
|
||||||
eInvoiceNumber: invoiceResult.eInvoiceNumber,
|
ackNo: invoiceResult.ackNo,
|
||||||
dmsNumber: invoiceResult.dmsNumber
|
irn: invoiceResult.irn
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Manual entry - just update the fields
|
// Manual entry - just update the fields
|
||||||
@ -1909,7 +1947,7 @@ export class DealerClaimService {
|
|||||||
invoiceNumber: invoiceData.eInvoiceNumber,
|
invoiceNumber: invoiceData.eInvoiceNumber,
|
||||||
invoiceDate: invoiceData.eInvoiceDate || new Date(),
|
invoiceDate: invoiceData.eInvoiceDate || new Date(),
|
||||||
dmsNumber: invoiceData.dmsNumber,
|
dmsNumber: invoiceData.dmsNumber,
|
||||||
amount: invoiceData.amount,
|
amount: Number(invoiceData.amount) || 0,
|
||||||
status: 'UPDATED',
|
status: 'UPDATED',
|
||||||
generatedAt: new Date(),
|
generatedAt: new Date(),
|
||||||
description: invoiceData.description,
|
description: invoiceData.description,
|
||||||
@ -2067,7 +2105,7 @@ export class DealerClaimService {
|
|||||||
invoiceId: claimInvoice.invoiceId,
|
invoiceId: claimInvoice.invoiceId,
|
||||||
creditNoteNumber: creditNoteResult.creditNoteNumber,
|
creditNoteNumber: creditNoteResult.creditNoteNumber,
|
||||||
creditNoteDate: creditNoteResult.creditNoteDate || new Date(),
|
creditNoteDate: creditNoteResult.creditNoteDate || new Date(),
|
||||||
creditNoteAmount: creditNoteResult.creditNoteAmount,
|
creditNoteAmount: Number(creditNoteResult.creditNoteAmount) || 0,
|
||||||
status: 'GENERATED',
|
status: 'GENERATED',
|
||||||
confirmedAt: new Date(),
|
confirmedAt: new Date(),
|
||||||
reason: creditNoteData?.reason || 'Claim settlement',
|
reason: creditNoteData?.reason || 'Claim settlement',
|
||||||
@ -2100,7 +2138,7 @@ export class DealerClaimService {
|
|||||||
invoiceId: claimInvoice?.invoiceId || undefined, // Allow undefined if no invoice
|
invoiceId: claimInvoice?.invoiceId || undefined, // Allow undefined if no invoice
|
||||||
creditNoteNumber: creditNoteData.creditNoteNumber,
|
creditNoteNumber: creditNoteData.creditNoteNumber,
|
||||||
creditNoteDate: creditNoteData.creditNoteDate || new Date(),
|
creditNoteDate: creditNoteData.creditNoteDate || new Date(),
|
||||||
creditNoteAmount: creditNoteData.creditNoteAmount,
|
creditNoteAmount: Number(creditNoteData.creditNoteAmount) || 0,
|
||||||
status: 'UPDATED',
|
status: 'UPDATED',
|
||||||
confirmedAt: new Date(),
|
confirmedAt: new Date(),
|
||||||
reason: creditNoteData?.reason,
|
reason: creditNoteData?.reason,
|
||||||
|
|||||||
@ -119,7 +119,7 @@ export class DMSWebhookService {
|
|||||||
amount: payload.total_amount || payload.claim_amount,
|
amount: payload.total_amount || payload.claim_amount,
|
||||||
status: 'GENERATED',
|
status: 'GENERATED',
|
||||||
generatedAt: new Date(),
|
generatedAt: new Date(),
|
||||||
invoiceFilePath: payload.invoice_file_path || null,
|
filePath: payload.invoice_file_path || null,
|
||||||
errorMessage: payload.error_message || null,
|
errorMessage: payload.error_message || null,
|
||||||
description: this.buildInvoiceDescription(payload),
|
description: this.buildInvoiceDescription(payload),
|
||||||
});
|
});
|
||||||
@ -137,7 +137,7 @@ export class DMSWebhookService {
|
|||||||
amount: payload.total_amount || payload.claim_amount,
|
amount: payload.total_amount || payload.claim_amount,
|
||||||
status: 'GENERATED',
|
status: 'GENERATED',
|
||||||
generatedAt: new Date(),
|
generatedAt: new Date(),
|
||||||
invoiceFilePath: payload.invoice_file_path || null,
|
filePath: payload.invoice_file_path || null,
|
||||||
errorMessage: payload.error_message || null,
|
errorMessage: payload.error_message || null,
|
||||||
// Store additional DMS data in description or separate fields if needed
|
// Store additional DMS data in description or separate fields if needed
|
||||||
description: this.buildInvoiceDescription(payload),
|
description: this.buildInvoiceDescription(payload),
|
||||||
@ -296,7 +296,7 @@ export class DMSWebhookService {
|
|||||||
*/
|
*/
|
||||||
private buildInvoiceDescription(payload: any): string {
|
private buildInvoiceDescription(payload: any): string {
|
||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
|
|
||||||
if (payload.irn_no) {
|
if (payload.irn_no) {
|
||||||
parts.push(`IRN: ${payload.irn_no}`);
|
parts.push(`IRN: ${payload.irn_no}`);
|
||||||
}
|
}
|
||||||
@ -318,7 +318,7 @@ export class DMSWebhookService {
|
|||||||
*/
|
*/
|
||||||
private buildCreditNoteDescription(payload: any): string {
|
private buildCreditNoteDescription(payload: any): string {
|
||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
|
|
||||||
if (payload.irn_no) {
|
if (payload.irn_no) {
|
||||||
parts.push(`IRN: ${payload.irn_no}`);
|
parts.push(`IRN: ${payload.irn_no}`);
|
||||||
}
|
}
|
||||||
@ -404,7 +404,7 @@ export class DMSWebhookService {
|
|||||||
attributes: ['userId'],
|
attributes: ['userId'],
|
||||||
});
|
});
|
||||||
dealerUserId = dealerUser?.userId || null;
|
dealerUserId = dealerUser?.userId || null;
|
||||||
|
|
||||||
if (dealerUserId) {
|
if (dealerUserId) {
|
||||||
logger.info('[DMSWebhook] Found dealer user for notification', {
|
logger.info('[DMSWebhook] Found dealer user for notification', {
|
||||||
requestId,
|
requestId,
|
||||||
@ -512,9 +512,9 @@ export class DMSWebhookService {
|
|||||||
const dealerClaimService = new DealerClaimService();
|
const dealerClaimService = new DealerClaimService();
|
||||||
const invoice = await ClaimInvoice.findOne({ where: { requestId } });
|
const invoice = await ClaimInvoice.findOne({ where: { requestId } });
|
||||||
const invoiceNumber = invoice?.invoiceNumber || 'N/A';
|
const invoiceNumber = invoice?.invoiceNumber || 'N/A';
|
||||||
|
|
||||||
await dealerClaimService.logEInvoiceGenerationActivity(requestId, invoiceNumber);
|
await dealerClaimService.logEInvoiceGenerationActivity(requestId, invoiceNumber);
|
||||||
|
|
||||||
logger.info('[DMSWebhook] E-Invoice Generation activity logged successfully', {
|
logger.info('[DMSWebhook] E-Invoice Generation activity logged successfully', {
|
||||||
requestId,
|
requestId,
|
||||||
requestNumber,
|
requestNumber,
|
||||||
|
|||||||
171
src/services/pwcIntegration.service.ts
Normal file
171
src/services/pwcIntegration.service.ts
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import logger from '../utils/logger';
|
||||||
|
import { Dealer } from '../models/Dealer';
|
||||||
|
import { ActivityType } from '../models/ActivityType';
|
||||||
|
import { WorkflowRequest } from '../models/WorkflowRequest';
|
||||||
|
import { ClaimInvoice } from '../models/ClaimInvoice';
|
||||||
|
import { InternalOrder } from '../models/InternalOrder';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PWC E-Invoice Integration Service
|
||||||
|
* Handles communication with PWC API for signed invoice generation
|
||||||
|
*/
|
||||||
|
export class PWCIntegrationService {
|
||||||
|
private apiUrl: string;
|
||||||
|
private appKey: string;
|
||||||
|
private appSecret: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.apiUrl = process.env.PWC_API_URL || 'https://api.qa.einvoice.aw.navigatetax.pwc.co.in';
|
||||||
|
this.appKey = process.env.PWC_APP_KEY || '';
|
||||||
|
this.appSecret = process.env.PWC_APP_SECRET || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve GL Code based on Activity Type and Internal Order
|
||||||
|
*/
|
||||||
|
private async resolveGLCode(activityTypeId: string, ioNumber?: string): Promise<string> {
|
||||||
|
const activity = await ActivityType.findByPk(activityTypeId);
|
||||||
|
if (activity?.glCode) {
|
||||||
|
return activity.glCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default Fallback or IO based logic if required
|
||||||
|
// Based on "IO GL will be changed" comment in user screenshot
|
||||||
|
if (ioNumber) {
|
||||||
|
const io = await InternalOrder.findOne({ where: { ioNumber } });
|
||||||
|
// Logic to derive GL from IO if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
return '610000'; // Default placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Signed Invoice via PWC API
|
||||||
|
*/
|
||||||
|
async generateSignedInvoice(requestId: string): Promise<{
|
||||||
|
success: boolean;
|
||||||
|
irn?: string;
|
||||||
|
ackNo?: string;
|
||||||
|
ackDate?: Date | string;
|
||||||
|
signedInvoice?: string;
|
||||||
|
qrCode?: string;
|
||||||
|
qrImage?: string;
|
||||||
|
error?: string;
|
||||||
|
}> {
|
||||||
|
try {
|
||||||
|
const request = await WorkflowRequest.findByPk(requestId, {
|
||||||
|
include: ['claimDetails', 'initiator']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!request) return { success: false, error: 'Request not found' };
|
||||||
|
|
||||||
|
const dealer = await Dealer.findOne({ where: { dlrcode: (request as any).claimDetails?.dealerCode } });
|
||||||
|
const activity = await ActivityType.findOne({ where: { title: (request as any).claimDetails?.activityType } });
|
||||||
|
|
||||||
|
if (!dealer || !activity) {
|
||||||
|
return { success: false, error: 'Dealer or Activity details missing' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct PWC Payload (keeping existing logic for now)
|
||||||
|
const payload = {
|
||||||
|
UserGstin: "33AAACE3882D1ZZ",
|
||||||
|
DocDtls: {
|
||||||
|
Typ: "INV",
|
||||||
|
No: `INV-${Date.now()}`,
|
||||||
|
Dt: new Date().toLocaleDateString('en-GB').replace(/\//g, '-')
|
||||||
|
},
|
||||||
|
SellerDtls: {
|
||||||
|
Gstin: dealer.gst || "33AAACE3882D1ZZ",
|
||||||
|
LglNm: dealer.dealership || 'Dealer',
|
||||||
|
Addr1: dealer.showroomAddress || "Address Line 1",
|
||||||
|
Loc: dealer.location || "Location",
|
||||||
|
Pin: 600001,
|
||||||
|
Stcd: "33"
|
||||||
|
},
|
||||||
|
BuyerDtls: {
|
||||||
|
Gstin: "33AAACE3882D1ZZ",
|
||||||
|
LglNm: "ROYAL ENFIELD (A UNIT OF EICHER MOTORS LTD)",
|
||||||
|
Addr1: "No. 2, Thiruvottiyur High Road",
|
||||||
|
Loc: "Thiruvottiyur",
|
||||||
|
Pin: 600019,
|
||||||
|
Stcd: "33",
|
||||||
|
Pos: "33"
|
||||||
|
},
|
||||||
|
ItemList: [
|
||||||
|
{
|
||||||
|
SlNo: "1",
|
||||||
|
PrdDesc: activity.title,
|
||||||
|
IsServc: "Y",
|
||||||
|
HsnCd: activity.hsnCode || activity.sacCode || "9983",
|
||||||
|
Qty: 1,
|
||||||
|
Unit: "OTH",
|
||||||
|
UnitPrce: (request as any).amount,
|
||||||
|
TotAmt: (request as any).amount,
|
||||||
|
GstRt: activity.gstRate || 18,
|
||||||
|
AssAmt: (request as any).amount,
|
||||||
|
IgstAmt: activity.gstRate === 18 ? ((request as any).amount * 0.18) : 0,
|
||||||
|
TotItemVal: (request as any).amount * 1.18
|
||||||
|
}
|
||||||
|
],
|
||||||
|
ValDtls: {
|
||||||
|
AssVal: (request as any).amount,
|
||||||
|
IgstVal: activity.gstRate === 18 ? ((request as any).amount * 0.18) : 0,
|
||||||
|
TotInvVal: (request as any).amount * 1.18
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.info(`[PWC] Sending e-invoice request for ${request.requestNumber}`);
|
||||||
|
|
||||||
|
const response = await axios.post(`${this.apiUrl}/generate`, payload, {
|
||||||
|
headers: { 'AppKey': this.appKey, 'AppSecret': this.appSecret }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Parse PWC Response based on provided structure
|
||||||
|
// Sample response is an array: [{ pwc_response, irp_response, qr_b64_encoded }]
|
||||||
|
const responseData = Array.isArray(response.data) ? response.data[0] : response.data;
|
||||||
|
const irpData = responseData?.irp_response?.data;
|
||||||
|
const nicData = irpData?.nic_response_data;
|
||||||
|
const qrB64 = responseData?.qr_b64_encoded;
|
||||||
|
|
||||||
|
let irn = nicData?.Irn;
|
||||||
|
let ackNo = nicData?.AckNo;
|
||||||
|
let ackDate = nicData?.AckDt;
|
||||||
|
let signedInvoice = nicData?.SignedInvoice;
|
||||||
|
let qrCode = nicData?.SignedQRCode;
|
||||||
|
|
||||||
|
// Handle Duplicate IRN Case
|
||||||
|
if (!irn && irpData?.InfoDtls) {
|
||||||
|
const dupInfo = irpData.InfoDtls.find((info: any) => info.InfCd === 'DUPIRN');
|
||||||
|
if (dupInfo?.Desc) {
|
||||||
|
irn = dupInfo.Desc.Irn;
|
||||||
|
ackNo = dupInfo.Desc.AckNo;
|
||||||
|
ackDate = dupInfo.Desc.AckDt;
|
||||||
|
logger.info(`[PWC] Handled duplicate IRN for ${request.requestNumber}: ${irn}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!irn) {
|
||||||
|
const errorMsg = responseData?.irp_response?.message || 'E-Invoice generation failed';
|
||||||
|
logger.error(`[PWC] E-Invoice failed for ${request.requestNumber}: ${errorMsg}`);
|
||||||
|
return { success: false, error: errorMsg };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
irn,
|
||||||
|
ackNo: String(ackNo),
|
||||||
|
ackDate: ackDate ? new Date(ackDate) : undefined,
|
||||||
|
signedInvoice,
|
||||||
|
qrCode,
|
||||||
|
qrImage: qrB64
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('[PWC] Error generating e-invoice:', error);
|
||||||
|
return { success: false, error: error instanceof Error ? error.message : 'Unknown error' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pwcIntegrationService = new PWCIntegrationService();
|
||||||
Loading…
Reference in New Issue
Block a user