Re_Backend/src/migrations/20260113-redesign-dealer-claim-history.ts

135 lines
5.2 KiB
TypeScript

import { QueryInterface, DataTypes } from 'sequelize';
export const up = async (queryInterface: QueryInterface) => {
// 1. Drop and recreate the enum type for snapshot_type to ensure all values are included
// This ensures APPROVE is always present when table is recreated
// Note: Table should be dropped manually before running this migration
try {
await queryInterface.sequelize.query(`
DO $$
BEGIN
-- Drop enum if it exists (cascade will handle any dependencies)
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'enum_dealer_claim_history_snapshot_type') THEN
DROP TYPE IF EXISTS enum_dealer_claim_history_snapshot_type CASCADE;
END IF;
-- Create enum with all values including APPROVE
CREATE TYPE enum_dealer_claim_history_snapshot_type AS ENUM ('PROPOSAL', 'COMPLETION', 'INTERNAL_ORDER', 'WORKFLOW', 'APPROVE');
END $$;
`);
} catch (error) {
// If enum creation fails, log error but continue
console.error('Enum creation error:', error);
throw error;
}
// 2. Create new simplified level-based dealer_claim_history table
await queryInterface.createTable('dealer_claim_history', {
history_id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
},
request_id: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'workflow_requests',
key: 'request_id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
approval_level_id: {
type: DataTypes.UUID,
allowNull: true, // Nullable for workflow-level snapshots
references: {
model: 'approval_levels',
key: 'level_id'
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
},
level_number: {
type: DataTypes.INTEGER,
allowNull: true, // Nullable for workflow-level snapshots
comment: 'Level number for easier querying (e.g., 1=Dealer, 3=Dept Lead, 4/5=Completion)'
},
level_name: {
type: DataTypes.STRING(255),
allowNull: true, // Nullable for workflow-level snapshots
comment: 'Level name for consistent matching (e.g., "Dealer Proposal Submission", "Department Lead Approval")'
},
version: {
type: DataTypes.INTEGER,
allowNull: false,
comment: 'Version number for this specific level (starts at 1 per level)'
},
snapshot_type: {
type: DataTypes.ENUM('PROPOSAL', 'COMPLETION', 'INTERNAL_ORDER', 'WORKFLOW', 'APPROVE'),
allowNull: false,
comment: 'Type of snapshot: PROPOSAL (Step 1), COMPLETION (Step 4/5), INTERNAL_ORDER (Step 3), WORKFLOW (general), APPROVE (approver actions with comments)'
},
snapshot_data: {
type: DataTypes.JSONB,
allowNull: false,
comment: 'JSON object containing all snapshot data specific to this level and type. Structure varies by snapshot_type.'
},
change_reason: {
type: DataTypes.TEXT,
allowNull: true,
comment: 'Reason for this version change (e.g., "Revision Requested: ...")'
},
changed_by: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'users',
key: 'user_id'
}
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW
}
});
// Add indexes for efficient querying
await queryInterface.addIndex('dealer_claim_history', ['request_id', 'level_number', 'version'], {
name: 'idx_history_request_level_version'
});
await queryInterface.addIndex('dealer_claim_history', ['approval_level_id', 'version'], {
name: 'idx_history_level_version'
});
await queryInterface.addIndex('dealer_claim_history', ['request_id', 'snapshot_type'], {
name: 'idx_history_request_type'
});
await queryInterface.addIndex('dealer_claim_history', ['snapshot_type', 'level_number'], {
name: 'idx_history_type_level'
});
await queryInterface.addIndex('dealer_claim_history', ['request_id', 'level_name'], {
name: 'idx_history_request_level_name'
});
await queryInterface.addIndex('dealer_claim_history', ['level_name', 'snapshot_type'], {
name: 'idx_history_level_name_type'
});
// Index for JSONB queries on snapshot_data
await queryInterface.addIndex('dealer_claim_history', ['snapshot_type'], {
name: 'idx_history_snapshot_type',
using: 'BTREE'
});
};
export const down = async (queryInterface: QueryInterface) => {
// Note: Table should be dropped manually
// Drop the enum type
try {
await queryInterface.sequelize.query(`
DROP TYPE IF EXISTS enum_dealer_claim_history_snapshot_type CASCADE;
`);
} catch (error) {
console.warn('Enum drop warning:', error);
}
};