From 06a1ee518e2b0bc9e3d57573bf91ce44bdb326cd Mon Sep 17 00:00:00 2001 From: Syed Waseem Date: Mon, 10 Aug 2026 15:18:20 +0530 Subject: [PATCH 1/2] feat: implement recovery incident service and controller with metric aggregation and CRUD operations --- .../recovery-incident.controller.ts | 15 ++ .../recovery-incident.service.ts | 191 ++++++++++++++++++ 2 files changed, 206 insertions(+) diff --git a/src/modules/recovery-incident/recovery-incident.controller.ts b/src/modules/recovery-incident/recovery-incident.controller.ts index 70c31af..73e2a7d 100644 --- a/src/modules/recovery-incident/recovery-incident.controller.ts +++ b/src/modules/recovery-incident/recovery-incident.controller.ts @@ -22,12 +22,27 @@ export class RecoveryIncidentController { return this.recoveryIncidentService.findAll(); } + @Get('metrics') + @ApiOperation({ summary: 'Get recovery incidents metrics summary' }) + getMetrics() { + return this.recoveryIncidentService.getMetrics(); + } + @Get(':id') @ApiOperation({ summary: 'Get a recovery incident by ID' }) findOne(@Param('id') id: string) { return this.recoveryIncidentService.findOne(id); } + @Patch(':id/status') + @ApiOperation({ summary: 'Update status of a recovery incident' }) + updateStatus( + @Param('id') id: string, + @Body('status') status: string, + ) { + return this.recoveryIncidentService.updateStatus(id, status); + } + @Patch(':id') @ApiOperation({ summary: 'Update a recovery incident' }) update(@Param('id') id: string, @Body() updateDto: UpdateRecoveryIncidentDto) { diff --git a/src/modules/recovery-incident/recovery-incident.service.ts b/src/modules/recovery-incident/recovery-incident.service.ts index 889342d..607eaa4 100644 --- a/src/modules/recovery-incident/recovery-incident.service.ts +++ b/src/modules/recovery-incident/recovery-incident.service.ts @@ -6,6 +6,16 @@ import { CreateRecoveryIncidentDto } from './dto/create-recovery-incident.dto'; import { UpdateRecoveryIncidentDto } from './dto/update-recovery-incident.dto'; import { getTenantId } from '../../common/tenant/tenant.context'; +export interface MetricCardData { + id?: string; + title: string; + value?: string; + trendText: string; + trendValue: string; + trendType: 'positive' | 'negative' | 'neutral'; + sparklineColor: 'green' | 'red'; +} + @Injectable() export class RecoveryIncidentService { constructor( @@ -31,6 +41,181 @@ export class RecoveryIncidentService { }); } + async getMetrics(): Promise { + const tenantId = getTenantId(); + const incidents = await this.recoveryIncidentRepo.find({ + where: { tenantId }, + }); + + const now = new Date(); + const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); + const fourteenDaysAgo = new Date(now.getTime() - 14 * 24 * 60 * 60 * 1000); + + const getIncidentDate = (i: RecoveryIncident): Date => { + if (i.date) return new Date(i.date); + if (i.createdAt) return new Date(i.createdAt); + return now; + }; + + const currentWeekIncidents = incidents.filter((i) => getIncidentDate(i) >= sevenDaysAgo); + const previousWeekIncidents = incidents.filter((i) => { + const d = getIncidentDate(i); + return d >= fourteenDaysAgo && d < sevenDaysAgo; + }); + + // Helper for parsing currency string into number + const parseValue = (val?: string): number => { + if (!val) return 0; + const num = parseFloat(val.replace(/[^0-9.]/g, '')) || 0; + return num; + }; + + // Helper for formatting sum into string (e.g. $412k, $1.2M, $500) + const formatCurrency = (amount: number): string => { + if (amount >= 1000000) { + return `$${(amount / 1000000).toFixed(1).replace(/\.0$/, '')}M`; + } + if (amount >= 1000) { + return `$${Math.round(amount / 1000)}k`; + } + return `$${amount.toLocaleString()}`; + }; + + // Helper to check if an incident is satisfied + const isSatisfied = (i: RecoveryIncident): boolean => { + const s = (i.status || '').toLowerCase(); + return s.includes('appr') || s.includes('active') || s.includes('success') || Boolean(i.isPerksClaimed); + }; + + // Helper to check if an incident is pending + const isPending = (i: RecoveryIncident): boolean => { + const s = (i.status || '').toLowerCase(); + return s.includes('pending') || s.includes('review') || s.includes('new'); + }; + + // 1. Total Recoveries + const totalCount = incidents.length; + const currentWeekTotal = currentWeekIncidents.length; + const previousWeekTotal = previousWeekIncidents.length; + let totalTrendVal = '0%'; + let totalTrendType: 'positive' | 'negative' | 'neutral' = 'neutral'; + let totalSparkColor: 'green' | 'red' = 'green'; + + if (previousWeekTotal > 0) { + const pct = Math.round(((currentWeekTotal - previousWeekTotal) / previousWeekTotal) * 100); + totalTrendVal = `${pct >= 0 ? '+' : ''}${pct}%`; + totalTrendType = pct >= 0 ? 'positive' : 'negative'; + totalSparkColor = pct >= 0 ? 'green' : 'red'; + } else if (currentWeekTotal > 0) { + totalTrendVal = '+100%'; + totalTrendType = 'positive'; + totalSparkColor = 'green'; + } + + // 2. Pending Approval + const pendingIncidents = incidents.filter(isPending); + const pendingCount = pendingIncidents.length; + const currentWeekPending = currentWeekIncidents.filter(isPending).length; + const previousWeekPending = previousWeekIncidents.filter(isPending).length; + let pendingTrendVal = '0%'; + let pendingTrendType: 'positive' | 'negative' | 'neutral' = 'neutral'; + let pendingSparkColor: 'green' | 'red' = 'green'; + + if (previousWeekPending > 0) { + const pct = Math.round(((currentWeekPending - previousWeekPending) / previousWeekPending) * 100); + pendingTrendVal = `${pct >= 0 ? '+' : ''}${pct}%`; + pendingTrendType = pct >= 0 ? 'positive' : 'negative'; + pendingSparkColor = pct >= 0 ? 'green' : 'red'; + } else if (pendingCount > 0) { + pendingTrendVal = 'High Priority'; + pendingTrendType = 'positive'; + pendingSparkColor = 'green'; + } + + // 3. Refund Value + const totalRefundSum = incidents.reduce((acc, curr) => acc + parseValue(curr.value), 0); + const currentWeekRefundSum = currentWeekIncidents.reduce((acc, curr) => acc + parseValue(curr.value), 0); + const previousWeekRefundSum = previousWeekIncidents.reduce((acc, curr) => acc + parseValue(curr.value), 0); + let refundTrendVal = '0%'; + let refundTrendType: 'positive' | 'negative' | 'neutral' = 'neutral'; + let refundSparkColor: 'green' | 'red' = 'green'; + + if (previousWeekRefundSum > 0) { + const pct = Math.round(((currentWeekRefundSum - previousWeekRefundSum) / previousWeekRefundSum) * 100); + refundTrendVal = `${pct >= 0 ? '+' : ''}${pct}%`; + refundTrendType = pct >= 0 ? 'positive' : 'negative'; + refundSparkColor = pct >= 0 ? 'green' : 'red'; + } else if (currentWeekRefundSum > 0) { + refundTrendVal = '+100%'; + refundTrendType = 'positive'; + refundSparkColor = 'green'; + } + + // 4. Customer Satisfaction + const satisfiedCount = incidents.filter(isSatisfied).length; + const satisfactionRate = totalCount > 0 ? Math.round((satisfiedCount / totalCount) * 100) : 0; + + const currentSatisfied = currentWeekIncidents.filter(isSatisfied).length; + const currentSatRate = currentWeekIncidents.length > 0 ? Math.round((currentSatisfied / currentWeekIncidents.length) * 100) : 0; + + const previousSatisfied = previousWeekIncidents.filter(isSatisfied).length; + const previousSatRate = previousWeekIncidents.length > 0 ? Math.round((previousSatisfied / previousWeekIncidents.length) * 100) : 0; + + let satTrendVal = '0%'; + let satTrendType: 'positive' | 'negative' | 'neutral' = 'neutral'; + let satSparkColor: 'green' | 'red' = 'green'; + + if (previousWeekIncidents.length > 0 && currentWeekIncidents.length > 0) { + const diff = currentSatRate - previousSatRate; + satTrendVal = `${diff >= 0 ? '+' : ''}${diff}%`; + satTrendType = diff >= 0 ? 'positive' : 'negative'; + satSparkColor = diff >= 0 ? 'green' : 'red'; + } else if (satisfactionRate > 0) { + satTrendVal = `+${satisfactionRate}%`; + satTrendType = 'positive'; + satSparkColor = 'green'; + } + + return [ + { + id: 'total-recoveries', + title: 'Total Recoveries', + value: totalCount.toLocaleString(), + trendValue: totalTrendVal, + trendText: 'since last week', + trendType: totalTrendType, + sparklineColor: totalSparkColor, + }, + { + id: 'pending-approval', + title: 'Pending Approval', + value: pendingCount.toLocaleString(), + trendValue: pendingTrendVal, + trendText: 'since last week', + trendType: pendingTrendType, + sparklineColor: pendingSparkColor, + }, + { + id: 'refund-value', + title: 'Refund Value', + value: formatCurrency(totalRefundSum), + trendValue: refundTrendVal, + trendText: 'since last week', + trendType: refundTrendType, + sparklineColor: refundSparkColor, + }, + { + id: 'customer-satisfaction', + title: 'Customer Satisfaction', + value: `${satisfactionRate}%`, + trendValue: satTrendVal, + trendText: 'since last week', + trendType: satTrendType, + sparklineColor: satSparkColor, + }, + ]; + } + async findOne(id: string): Promise { const tenantId = getTenantId(); const incident = await this.recoveryIncidentRepo.findOne({ @@ -56,6 +241,12 @@ export class RecoveryIncidentService { return this.recoveryIncidentRepo.save(incident); } + async updateStatus(id: string, status: string): Promise { + const incident = await this.findOne(id); + incident.status = status; + return this.recoveryIncidentRepo.save(incident); + } + async remove(id: string): Promise { const incident = await this.findOne(id); await this.recoveryIncidentRepo.remove(incident); From dfce163ca0d17f0e5e61d2bd3240d4c930cfad7b Mon Sep 17 00:00:00 2001 From: Syed Waseem Date: Tue, 11 Aug 2026 12:59:01 +0530 Subject: [PATCH 2/2] feat: implement master-data module with core entity definitions, schema migration, and CRUD endpoints --- database/schema.sql | 645 ++++++++++-------- database/seed-master-data.sql | 370 +++++----- src/database/database.module.ts | 7 +- .../entities/action-category.entity.ts | 2 +- .../action-submission-value.entity.ts | 2 +- .../entities/action-submission.entity.ts | 2 +- .../entities/action-type.entity.ts | 2 +- .../entities/airline-responsibility.entity.ts | 2 +- .../entities/amount-type.entity.ts | 2 +- .../entities/ancillary-purchase.entity.ts | 2 +- .../entities/atc-restriction.entity.ts | 2 +- .../entities/booking-channel.entity.ts | 2 +- .../entities/cabin-class.entity.ts | 2 +- .../entities/cancellation-reason.entity.ts | 2 +- .../entities/carrier-type.entity.ts | 2 +- .../compensation-eligibility.entity.ts | 2 +- .../entities/compensation-type.entity.ts | 2 +- .../entities/condition-field.entity.ts | 42 ++ .../entities/condition-group.entity.ts | 33 + .../master-data/entities/currency.entity.ts | 2 +- .../entities/customer-value.entity.ts | 2 +- .../entities/delay-duration.entity.ts | 2 +- .../entities/delay-reason.entity.ts | 2 +- .../entities/diversion-reason.entity.ts | 2 +- .../extraordinary-circumstance.entity.ts | 2 +- .../entities/fare-flexibility.entity.ts | 2 +- .../entities/field-definition.entity.ts | 2 +- .../entities/flight-disruption-type.entity.ts | 2 +- .../entities/flight-type.entity.ts | 2 +- .../entities/journey-type.entity.ts | 2 +- .../entities/jurisdiction.entity.ts | 2 +- .../entities/membership-tier.entity.ts | 2 +- .../missed-connection-reason.entity.ts | 2 +- .../master-data/entities/operator.entity.ts | 2 +- .../entities/passenger-type.entity.ts | 2 +- .../entities/refund-basis.entity.ts | 2 +- .../entities/refund-method.entity.ts | 2 +- .../entities/refund-type.entity.ts | 2 +- .../master-data/entities/region.entity.ts | 2 +- .../entities/revenue-segment.entity.ts | 2 +- .../entities/rule-category-group.entity.ts | 27 + .../entities/rule-category.entity.ts | 8 +- .../special-assistance-type.entity.ts | 2 +- .../technical-fault-category.entity.ts | 2 +- .../entities/trip-purpose.entity.ts | 2 +- .../entities/weather-condition.entity.ts | 2 +- .../master-data/master-data.controller.ts | 30 + src/modules/master-data/master-data.module.ts | 7 + .../master-data/master-data.service.ts | 150 +++- 49 files changed, 898 insertions(+), 499 deletions(-) create mode 100644 src/modules/master-data/entities/condition-field.entity.ts create mode 100644 src/modules/master-data/entities/condition-group.entity.ts create mode 100644 src/modules/master-data/entities/rule-category-group.entity.ts diff --git a/database/schema.sql b/database/schema.sql index b4386ad..4e0ab83 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -3,22 +3,15 @@ -- PostgreSQL 14+ -- Generated from TypeORM entities (aeroresolve_backend) -- ============================================================================= --- --- Usage: --- psql -h -U -d -f database/schema.sql --- --- Notes: --- - Column names use camelCase to match TypeORM entity field names. --- - In local/dev, TypeORM can also sync via DB_SYNCHRONIZE=true. --- - Run scripts/seed-master-data.ts after schema creation for demo data. --- ============================================================================= CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- ─── Schemas ──────────────────────────────────────────────────────────────── CREATE SCHEMA IF NOT EXISTS tenant; -CREATE SCHEMA IF NOT EXISTS masters; +CREATE SCHEMA IF NOT EXISTS masters_rule_engine; +CREATE SCHEMA IF NOT EXISTS masters_action_builder; +CREATE SCHEMA IF NOT EXISTS masters_lookup; CREATE SCHEMA IF NOT EXISTS cohort; CREATE SCHEMA IF NOT EXISTS policy_engine; @@ -57,9 +50,9 @@ CREATE TABLE IF NOT EXISTS tenant.tbl_tenants ( CONSTRAINT uq_tbl_tenants_slug UNIQUE (slug) ); --- ─── Master Data ──────────────────────────────────────────────────────────── +-- ─── 1. Masters Lookup Schema (Domain Master Tables) ───────────────────────── -CREATE TABLE IF NOT EXISTS masters.tbl_membership_tiers ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_membership_tiers ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -68,7 +61,7 @@ CREATE TABLE IF NOT EXISTS masters.tbl_membership_tiers ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_customer_values ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_customer_values ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -77,7 +70,7 @@ CREATE TABLE IF NOT EXISTS masters.tbl_customer_values ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_regions ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_regions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -86,7 +79,7 @@ CREATE TABLE IF NOT EXISTS masters.tbl_regions ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_trip_purposes ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_trip_purposes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -95,7 +88,7 @@ CREATE TABLE IF NOT EXISTS masters.tbl_trip_purposes ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_cabin_classes ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_cabin_classes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -104,7 +97,7 @@ CREATE TABLE IF NOT EXISTS masters.tbl_cabin_classes ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_passenger_types ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_passenger_types ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -113,7 +106,7 @@ CREATE TABLE IF NOT EXISTS masters.tbl_passenger_types ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_ancillary_purchases ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_ancillary_purchases ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -122,7 +115,7 @@ CREATE TABLE IF NOT EXISTS masters.tbl_ancillary_purchases ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_revenue_segments ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_revenue_segments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -131,7 +124,7 @@ CREATE TABLE IF NOT EXISTS masters.tbl_revenue_segments ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_jurisdictions ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_jurisdictions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), label VARCHAR NOT NULL, value VARCHAR NOT NULL, @@ -140,7 +133,226 @@ CREATE TABLE IF NOT EXISTS masters.tbl_jurisdictions ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_rules_categories ( +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_booking_channels ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_flight_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_journey_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_fare_flexibilities ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_carrier_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_special_assistance_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_delay_reasons ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_delay_durations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_extraordinary_circumstances ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_cancellation_reasons ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_diversion_reasons ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_missed_connection_reasons ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_compensation_eligibilities ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_compensation_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_refund_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_flight_disruption_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_airline_responsibilities ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_weather_conditions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_atc_restrictions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_technical_fault_categories ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_refund_bases ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_currencies ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + symbol VARCHAR, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_refund_methods ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_lookup.tbl_amount_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + label VARCHAR NOT NULL, + value VARCHAR NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +-- ─── 2. Masters Rule Engine Schema (Condition & Category Metadata) ─────────── + +CREATE TABLE IF NOT EXISTS masters_rule_engine.tbl_rules_categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), code VARCHAR(100) NOT NULL UNIQUE, name VARCHAR(150) NOT NULL, @@ -152,187 +364,39 @@ CREATE TABLE IF NOT EXISTS masters.tbl_rules_categories ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_booking_channels ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +CREATE TABLE IF NOT EXISTS masters_rule_engine.tbl_condition_groups ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + code VARCHAR(100) NOT NULL UNIQUE, + name VARCHAR(150) NOT NULL, + "displayOrder" INT DEFAULT 0, + "isActive" BOOLEAN DEFAULT TRUE, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_flight_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +CREATE TABLE IF NOT EXISTS masters_rule_engine.tbl_rule_category_groups ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "ruleCategoryId" UUID NOT NULL REFERENCES masters_rule_engine.tbl_rules_categories(id) ON DELETE CASCADE, + "conditionGroupId" UUID NOT NULL REFERENCES masters_rule_engine.tbl_condition_groups(id) ON DELETE CASCADE, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + CONSTRAINT uq_rule_category_group UNIQUE ("ruleCategoryId", "conditionGroupId") ); -CREATE TABLE IF NOT EXISTS masters.tbl_journey_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +CREATE TABLE IF NOT EXISTS masters_rule_engine.tbl_condition_fields ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "groupId" UUID NOT NULL REFERENCES masters_rule_engine.tbl_condition_groups(id) ON DELETE CASCADE, + code VARCHAR(100) NOT NULL UNIQUE, + name VARCHAR(150) NOT NULL, + "lookupTable" VARCHAR, + "dataType" VARCHAR NOT NULL DEFAULT 'STRING', + "operatorType" VARCHAR NOT NULL DEFAULT 'COMPARISON', + "displayOrder" INT DEFAULT 0, + "isActive" BOOLEAN DEFAULT TRUE, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE TABLE IF NOT EXISTS masters.tbl_fare_flexibilities ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_carrier_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_special_assistance_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_delay_reasons ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_delay_durations ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_extraordinary_circumstances ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_cancellation_reasons ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_diversion_reasons ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_missed_connection_reasons ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_compensation_eligibilities ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_compensation_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_refund_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_flight_disruption_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_airline_responsibilities ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_weather_conditions ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_atc_restrictions ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_technical_fault_categories ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_operators ( +CREATE TABLE IF NOT EXISTS masters_rule_engine.tbl_operators ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), code VARCHAR(50) NOT NULL UNIQUE, name VARCHAR(100) NOT NULL, @@ -344,6 +408,80 @@ CREATE TABLE IF NOT EXISTS masters.tbl_operators ( "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); +-- ─── 3. Masters Action Builder Schema ─────────────────────────────────────── + +CREATE TABLE IF NOT EXISTS masters_action_builder.tbl_action_categories ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + code VARCHAR NOT NULL UNIQUE, + name VARCHAR NOT NULL, + description TEXT, + "displayOrder" INT DEFAULT 0, + "isActive" BOOLEAN DEFAULT TRUE, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_action_builder.tbl_action_types ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "categoryId" UUID NOT NULL REFERENCES masters_action_builder.tbl_action_categories(id) ON DELETE CASCADE, + code VARCHAR NOT NULL UNIQUE, + name VARCHAR NOT NULL, + description TEXT, + "displayOrder" INT DEFAULT 0, + "isActive" BOOLEAN DEFAULT TRUE, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_action_builder.tbl_field_definitions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "actionTypeId" UUID NOT NULL REFERENCES masters_action_builder.tbl_action_types(id) ON DELETE CASCADE, + "fieldCode" VARCHAR NOT NULL, + "fieldName" VARCHAR NOT NULL, + "fieldType" VARCHAR NOT NULL, + "lookupSource" VARCHAR, + "isRequired" BOOLEAN NOT NULL DEFAULT false, + "defaultValue" TEXT, + placeholder VARCHAR, + "helpText" TEXT, + width VARCHAR NOT NULL DEFAULT 'full', + section VARCHAR, + "displayOrder" INT NOT NULL DEFAULT 0, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "validationJson" JSONB, + "visibilityConditionJson" JSONB, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE UNIQUE INDEX IF NOT EXISTS uq_field_definition_action_type_code + ON masters_action_builder.tbl_field_definitions("actionTypeId", "fieldCode"); + +CREATE TABLE IF NOT EXISTS masters_action_builder.tbl_action_submissions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "categoryId" UUID NOT NULL REFERENCES masters_action_builder.tbl_action_categories(id) ON DELETE CASCADE, + "actionTypeId" UUID NOT NULL REFERENCES masters_action_builder.tbl_action_types(id) ON DELETE CASCADE, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS masters_action_builder.tbl_action_submission_values ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "submissionId" UUID NOT NULL REFERENCES masters_action_builder.tbl_action_submissions(id) ON DELETE CASCADE, + "fieldDefinitionId" UUID REFERENCES masters_action_builder.tbl_field_definitions(id) ON DELETE CASCADE, + "fieldCode" VARCHAR, + "valueIndex" INT NOT NULL DEFAULT 0, + "selectedValueId" VARCHAR, + "textValue" TEXT, + "numberValue" NUMERIC, + "booleanValue" BOOLEAN, + "dateValue" DATE, + "timeValue" TIME, + "timestampValue" TIMESTAMP WITH TIME ZONE, + "createdAt" TIMESTAMP NOT NULL DEFAULT now(), + "updatedAt" TIMESTAMP NOT NULL DEFAULT now() +); + -- ─── Cohorts ──────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS cohort.tbl_cohorts ( @@ -366,141 +504,53 @@ CREATE INDEX IF NOT EXISTS idx_tbl_cohorts_tenant ON cohort.tbl_cohorts("tenantI CREATE TABLE IF NOT EXISTS cohort.tbl_cohort_cabin_classes ( "cohortId" UUID NOT NULL REFERENCES cohort.tbl_cohorts(id) ON DELETE CASCADE, - "cabinClassId" UUID NOT NULL REFERENCES masters.tbl_cabin_classes(id) ON DELETE CASCADE, + "cabinClassId" UUID NOT NULL REFERENCES masters_lookup.tbl_cabin_classes(id) ON DELETE CASCADE, PRIMARY KEY ("cohortId", "cabinClassId") ); CREATE TABLE IF NOT EXISTS cohort.tbl_cohort_passenger_types ( "cohortId" UUID NOT NULL REFERENCES cohort.tbl_cohorts(id) ON DELETE CASCADE, - "passengerTypeId" UUID NOT NULL REFERENCES masters.tbl_passenger_types(id) ON DELETE CASCADE, + "passengerTypeId" UUID NOT NULL REFERENCES masters_lookup.tbl_passenger_types(id) ON DELETE CASCADE, PRIMARY KEY ("cohortId", "passengerTypeId") ); CREATE TABLE IF NOT EXISTS cohort.tbl_cohort_ancillary_purchases ( "cohortId" UUID NOT NULL REFERENCES cohort.tbl_cohorts(id) ON DELETE CASCADE, - "ancillaryPurchaseId" UUID NOT NULL REFERENCES masters.tbl_ancillary_purchases(id) ON DELETE CASCADE, + "ancillaryPurchaseId" UUID NOT NULL REFERENCES masters_lookup.tbl_ancillary_purchases(id) ON DELETE CASCADE, PRIMARY KEY ("cohortId", "ancillaryPurchaseId") ); CREATE TABLE IF NOT EXISTS cohort.tbl_cohort_loyalty_tiers ( "cohortId" UUID NOT NULL REFERENCES cohort.tbl_cohorts(id) ON DELETE CASCADE, - "membershipTierId" UUID NOT NULL REFERENCES masters.tbl_membership_tiers(id) ON DELETE CASCADE, + "membershipTierId" UUID NOT NULL REFERENCES masters_lookup.tbl_membership_tiers(id) ON DELETE CASCADE, PRIMARY KEY ("cohortId", "membershipTierId") ); CREATE TABLE IF NOT EXISTS cohort.tbl_cohort_revenue_segments ( "cohortId" UUID NOT NULL REFERENCES cohort.tbl_cohorts(id) ON DELETE CASCADE, - "revenueSegmentId" UUID NOT NULL REFERENCES masters.tbl_revenue_segments(id) ON DELETE CASCADE, + "revenueSegmentId" UUID NOT NULL REFERENCES masters_lookup.tbl_revenue_segments(id) ON DELETE CASCADE, PRIMARY KEY ("cohortId", "revenueSegmentId") ); CREATE TABLE IF NOT EXISTS cohort.tbl_cohort_regions ( "cohortId" UUID NOT NULL REFERENCES cohort.tbl_cohorts(id) ON DELETE CASCADE, - "regionId" UUID NOT NULL REFERENCES masters.tbl_regions(id) ON DELETE CASCADE, + "regionId" UUID NOT NULL REFERENCES masters_lookup.tbl_regions(id) ON DELETE CASCADE, PRIMARY KEY ("cohortId", "regionId") ); CREATE TABLE IF NOT EXISTS cohort.tbl_cohort_trip_purposes ( "cohortId" UUID NOT NULL REFERENCES cohort.tbl_cohorts(id) ON DELETE CASCADE, - "tripPurposeId" UUID NOT NULL REFERENCES masters.tbl_trip_purposes(id) ON DELETE CASCADE, + "tripPurposeId" UUID NOT NULL REFERENCES masters_lookup.tbl_trip_purposes(id) ON DELETE CASCADE, PRIMARY KEY ("cohortId", "tripPurposeId") ); --- ─── Action Builder & Metadata-Driven Field Definitions ──────────────────── - -CREATE TABLE IF NOT EXISTS masters.tbl_field_definitions ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "actionTypeId" UUID NOT NULL REFERENCES masters.tbl_action_types(id) ON DELETE CASCADE, - "fieldCode" VARCHAR NOT NULL, - "fieldName" VARCHAR NOT NULL, - "fieldType" VARCHAR NOT NULL, - "lookupSource" VARCHAR, - "isRequired" BOOLEAN NOT NULL DEFAULT false, - "defaultValue" TEXT, - placeholder VARCHAR, - "helpText" TEXT, - width VARCHAR NOT NULL DEFAULT 'full', - section VARCHAR, - "displayOrder" INT NOT NULL DEFAULT 0, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "validationJson" JSONB, - "visibilityConditionJson" JSONB, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE UNIQUE INDEX IF NOT EXISTS uq_field_definition_action_type_code - ON masters.tbl_field_definitions("actionTypeId", "fieldCode"); - -CREATE TABLE IF NOT EXISTS masters.tbl_action_submissions ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "categoryId" UUID NOT NULL REFERENCES masters.tbl_action_categories(id) ON DELETE CASCADE, - "actionTypeId" UUID NOT NULL REFERENCES masters.tbl_action_types(id) ON DELETE CASCADE, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_action_submission_values ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "submissionId" UUID NOT NULL REFERENCES masters.tbl_action_submissions(id) ON DELETE CASCADE, - "fieldDefinitionId" UUID REFERENCES masters.tbl_field_definitions(id) ON DELETE CASCADE, - "fieldCode" VARCHAR, - "valueIndex" INT NOT NULL DEFAULT 0, - "selectedValueId" VARCHAR, - "textValue" TEXT, - "numberValue" NUMERIC, - "booleanValue" BOOLEAN, - "dateValue" DATE, - "timeValue" TIME, - "timestampValue" TIMESTAMP WITH TIME ZONE, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_refund_bases ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_currencies ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - symbol VARCHAR, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_refund_methods ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -CREATE TABLE IF NOT EXISTS masters.tbl_amount_types ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - label VARCHAR NOT NULL, - value VARCHAR NOT NULL, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP NOT NULL DEFAULT now(), - "updatedAt" TIMESTAMP NOT NULL DEFAULT now() -); - -- ─── Policy Engine ────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS policy_engine.tbl_policies ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, policy_name VARCHAR(200) NOT NULL, - jurisdiction_id UUID REFERENCES masters.tbl_jurisdictions(id) ON DELETE SET NULL, + jurisdiction_id UUID REFERENCES masters_lookup.tbl_jurisdictions(id) ON DELETE SET NULL, description TEXT, status VARCHAR NOT NULL DEFAULT 'draft', version INT NOT NULL DEFAULT 1, @@ -521,7 +571,7 @@ CREATE TABLE IF NOT EXISTS policy_engine.tbl_policy_target_audiences ( CREATE TABLE IF NOT EXISTS policy_engine.tbl_policy_rules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), policy_id UUID NOT NULL REFERENCES policy_engine.tbl_policies(id) ON DELETE CASCADE, - rule_category_id UUID REFERENCES masters.tbl_rule_categories(id) ON DELETE SET NULL, + rule_category_id UUID REFERENCES masters_rule_engine.tbl_rules_categories(id) ON DELETE SET NULL, priority INT NOT NULL DEFAULT 0 ); @@ -538,14 +588,14 @@ CREATE TABLE IF NOT EXISTS policy_engine.tbl_policy_rule_conditions ( CREATE TABLE IF NOT EXISTS policy_engine.tbl_policy_actions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), rule_id UUID NOT NULL REFERENCES policy_engine.tbl_policy_rules(id) ON DELETE CASCADE, - action_type_id UUID NOT NULL REFERENCES masters.tbl_action_types(id) ON DELETE CASCADE, + action_type_id UUID NOT NULL REFERENCES masters_action_builder.tbl_action_types(id) ON DELETE CASCADE, sequence INT NOT NULL DEFAULT 0 ); CREATE TABLE IF NOT EXISTS policy_engine.tbl_policy_action_values ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), action_id UUID NOT NULL REFERENCES policy_engine.tbl_policy_actions(id) ON DELETE CASCADE, - field_definition_id UUID REFERENCES masters.tbl_field_definitions(id) ON DELETE SET NULL, + field_definition_id UUID REFERENCES masters_action_builder.tbl_field_definitions(id) ON DELETE SET NULL, field_code VARCHAR NOT NULL, value_index INT NOT NULL DEFAULT 0, selected_value_id VARCHAR, @@ -562,8 +612,3 @@ CREATE TABLE IF NOT EXISTS policy_engine.tbl_policy_action_values ( CREATE INDEX IF NOT EXISTS idx_tbl_policy_action_values_action ON policy_engine.tbl_policy_action_values(action_id); - - - - - diff --git a/database/seed-master-data.sql b/database/seed-master-data.sql index 846a95e..8bc9cd1 100644 --- a/database/seed-master-data.sql +++ b/database/seed-master-data.sql @@ -4,7 +4,7 @@ -- ============================================================================= -- 1. Action Categories -INSERT INTO masters.tbl_action_categories (code, name, "displayOrder", "isActive") +INSERT INTO masters_action_builder.tbl_action_categories (code, name, "displayOrder", "isActive") SELECT code, name, displayOrder, true FROM (VALUES ('REFUNDS', 'Refunds', 1), ('CASH_COMPENSATION', 'Cash Compensation', 2), @@ -21,10 +21,10 @@ SELECT code, name, displayOrder, true FROM (VALUES ('FINANCE', 'Finance', 13), ('SYSTEM_INTEGRATION', 'System Integration', 14) ) AS t(code, name, displayOrder) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_action_categories WHERE masters.tbl_action_categories.code = t.code); +WHERE NOT EXISTS (SELECT 1 FROM masters_action_builder.tbl_action_categories WHERE masters_action_builder.tbl_action_categories.code = t.code); -- 2. Action Types -INSERT INTO masters.tbl_action_types (code, "categoryId", name, "displayOrder", "isActive") +INSERT INTO masters_action_builder.tbl_action_types (code, "categoryId", name, "displayOrder", "isActive") SELECT v.code, c.id, v.name, v.display_order, true FROM (VALUES -- Refunds @@ -113,11 +113,11 @@ FROM (VALUES ('CREATE_AUDIT_RECORD', 'SYSTEM_INTEGRATION', 'Create Audit Record', 4), ('TRIGGER_WEBHOOK_API', 'SYSTEM_INTEGRATION', 'Trigger Webhook / API', 5) ) AS v(code, cat_code, name, display_order) -JOIN masters.tbl_action_categories c ON c.code = v.cat_code -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_action_types WHERE masters.tbl_action_types.code = v.code); +JOIN masters_action_builder.tbl_action_categories c ON c.code = v.cat_code +WHERE NOT EXISTS (SELECT 1 FROM masters_action_builder.tbl_action_types WHERE masters_action_builder.tbl_action_types.code = v.code); -- 3. Membership Tiers -INSERT INTO masters.tbl_membership_tiers (label, value, "isActive") +INSERT INTO masters_lookup.tbl_membership_tiers (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Platinum', 'platinum'), ('Gold', 'gold'), @@ -126,19 +126,19 @@ SELECT label, value, true FROM (VALUES ('Basic', 'basic'), ('Non-Member', 'non-member') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_membership_tiers WHERE masters.tbl_membership_tiers.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_membership_tiers WHERE masters_lookup.tbl_membership_tiers.value = t.value); -- 4. Customer Values -INSERT INTO masters.tbl_customer_values (label, value, "isActive") +INSERT INTO masters_lookup.tbl_customer_values (label, value, "isActive") SELECT label, value, true FROM (VALUES ('High Value', 'high'), ('Medium Value', 'medium'), ('Low Value', 'low') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_customer_values WHERE masters.tbl_customer_values.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_customer_values WHERE masters_lookup.tbl_customer_values.value = t.value); -- 5. Regions -INSERT INTO masters.tbl_regions (label, value, "isActive") +INSERT INTO masters_lookup.tbl_regions (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Global', 'global'), ('Americas', 'americas'), @@ -147,40 +147,40 @@ SELECT label, value, true FROM (VALUES ('Asia Pacific', 'asia-pacific'), ('Africa', 'africa') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_regions WHERE masters.tbl_regions.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_regions WHERE masters_lookup.tbl_regions.value = t.value); -- 6. Trip Purposes -INSERT INTO masters.tbl_trip_purposes (label, value, "isActive") +INSERT INTO masters_lookup.tbl_trip_purposes (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Business', 'business'), ('Leisure', 'leisure'), ('Corporate', 'corporate'), ('Government', 'government') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_trip_purposes WHERE masters.tbl_trip_purposes.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_trip_purposes WHERE masters_lookup.tbl_trip_purposes.value = t.value); -- 7. Cabin Classes -INSERT INTO masters.tbl_cabin_classes (label, value, "isActive") +INSERT INTO masters_lookup.tbl_cabin_classes (label, value, "isActive") SELECT label, value, true FROM (VALUES ('First Class', 'first-class'), ('Business Class', 'business-class'), ('Premium Economy', 'premium-economy'), ('Economy', 'economy') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_cabin_classes WHERE masters.tbl_cabin_classes.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_cabin_classes WHERE masters_lookup.tbl_cabin_classes.value = t.value); -- 8. Passenger Types -INSERT INTO masters.tbl_passenger_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_passenger_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Adult', 'adult'), ('Child', 'child'), ('Infant', 'infant'), ('Senior Citizen', 'senior') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_passenger_types WHERE masters.tbl_passenger_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_passenger_types WHERE masters_lookup.tbl_passenger_types.value = t.value); -- 9. Ancillary Purchases -INSERT INTO masters.tbl_ancillary_purchases (label, value, "isActive") +INSERT INTO masters_lookup.tbl_ancillary_purchases (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Preferred Seat', 'preferred-seat'), ('Extra Legroom', 'extra-legroom'), @@ -200,19 +200,19 @@ SELECT label, value, true FROM (VALUES ('Power Outlet', 'power-outlet'), ('Carbon Offset', 'carbon-offset') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_ancillary_purchases WHERE masters.tbl_ancillary_purchases.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_ancillary_purchases WHERE masters_lookup.tbl_ancillary_purchases.value = t.value); -- 10. Revenue Segments -INSERT INTO masters.tbl_revenue_segments (label, value, "isActive") +INSERT INTO masters_lookup.tbl_revenue_segments (label, value, "isActive") SELECT label, value, true FROM (VALUES ('High Value', 'high'), ('Medium Value', 'medium'), ('Low Value', 'low') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_revenue_segments WHERE masters.tbl_revenue_segments.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_revenue_segments WHERE masters_lookup.tbl_revenue_segments.value = t.value); -- 11. Jurisdictions -INSERT INTO masters.tbl_jurisdictions (label, value, "isActive") +INSERT INTO masters_lookup.tbl_jurisdictions (label, value, "isActive") SELECT label, value, true FROM (VALUES ('United Arab Emirates', 'uae'), ('European Union', 'eu'), @@ -222,92 +222,28 @@ SELECT label, value, true FROM (VALUES ('Asia Pacific', 'apac'), ('Global', 'global') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_jurisdictions WHERE masters.tbl_jurisdictions.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_jurisdictions WHERE masters_lookup.tbl_jurisdictions.value = t.value); --- 12. Rule Categories -INSERT INTO masters.tbl_rules_categories (code, name, "tableName", description, "displayOrder", "isActive") -SELECT code, name, "tableName", description, "displayOrder", true FROM (VALUES - ('passenger-type', 'Passenger Type', 'tbl_passenger_types', 'Passenger Type master', 1), - ('cabin-class', 'Cabin Class', 'tbl_cabin_classes', 'Cabin Class master', 2), - ('booking-channel', 'Booking Channel', 'tbl_booking_channels', 'Booking Channel master', 3), - ('membership-tier', 'Membership Tier', 'tbl_membership_tiers', 'Membership Tier master', 4), - ('loyalty-tier', 'Loyalty Tier', 'tbl_membership_tiers', 'Loyalty Tier master', 4), - ('flight-type', 'Flight Type', 'tbl_flight_types', 'Flight Type master', 5), - ('journey-type', 'Journey Type', 'tbl_journey_types', 'Journey Type master', 6), - ('fare-flexibility', 'Fare Flexibility', 'tbl_fare_flexibilities', 'Fare Flexibility master', 7), - ('trip-purpose', 'Trip Purpose', 'tbl_trip_purposes', 'Trip Purpose master', 8), - ('carrier-type', 'Carrier Type', 'tbl_carrier_types', 'Carrier Type master', 9), - ('special-assistance-type', 'Special Assistance Type', 'tbl_special_assistance_types', 'Special Assistance Type master', 10), - ('delay-reason', 'Delay Reason', 'tbl_delay_reasons', 'Delay Reason master', 11), - ('delay-duration', 'Delay Duration', 'tbl_delay_durations', 'Delay Duration master', 12), - ('extraordinary-circumstances', 'Extraordinary Circumstances', 'tbl_extraordinary_circumstances', 'Extraordinary Circumstances master', 13), - ('cancellation-reason', 'Cancellation Reason', 'tbl_cancellation_reasons', 'Cancellation Reason master', 14), - ('diversion-reason', 'Diversion Reason', 'tbl_diversion_reasons', 'Diversion Reason master', 15), - ('missed-connection-reason', 'Missed Connection Reason', 'tbl_missed_connection_reasons', 'Missed Connection Reason master', 16), - ('compensation-eligibility', 'Compensation Eligibility', 'tbl_compensation_eligibilities', 'Compensation Eligibility master', 17), - ('compensation-type', 'Compensation Type', 'tbl_compensation_types', 'Compensation Type master', 18), - ('refund-type', 'Refund Type', 'tbl_refund_types', 'Refund Type master', 19), - ('flight-disruption-type', 'Flight Disruption Type', 'tbl_flight_disruption_types', 'Flight Disruption Type master', 20), - ('airline-responsibility', 'Airline Responsibility', 'tbl_airline_responsibilities', 'Airline Responsibility master', 21), - ('weather-condition', 'Weather Condition', 'tbl_weather_conditions', 'Weather Condition master', 22), - ('atc-restriction', 'ATC Restriction', 'tbl_atc_restrictions', 'ATC Restriction master', 23), - ('technical-fault-category', 'Technical Fault Category', 'tbl_technical_fault_categories', 'Technical Fault Category master', 24), - ('refund-basis', 'Refund Basis', 'tbl_refund_bases', 'Refund Basis master', 25), - ('currency', 'Currency', 'tbl_currencies', 'Currency master', 26), - ('refund-method', 'Refund Method', 'tbl_refund_methods', 'Refund Method master', 27), - ('ancillary-purchase', 'Ancillary Purchase', 'tbl_ancillary_purchases', 'Ancillary Purchase master', 28), - ('customer-value', 'Customer Value', 'tbl_customer_values', 'Customer Value master', 29), - ('region', 'Region', 'tbl_regions', 'Region master', 30), - ('revenue-segment', 'Revenue Segment', 'tbl_revenue_segments', 'Revenue Segment master', 31), - ('jurisdiction', 'Jurisdiction', 'tbl_jurisdictions', 'Jurisdiction master', 32), - ('operator', 'Operator', 'tbl_operators', 'Operator master', 33), - ('amount-type', 'Amount Type', 'tbl_amount_types', 'Amount Type master', 34) -) AS t(code, name, "tableName", description, "displayOrder") -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_rules_categories WHERE masters.tbl_rules_categories.code = t.code); +-- 12. Rule Categories (Business Rule Categories) +DELETE FROM masters_rule_engine.tbl_rules_categories +WHERE code NOT IN ( + 'FLIGHT_OPERATIONS', 'BAGGAGE_ISSUES', 'CABIN_DOWNGRADES', + 'ANCILLARY_FAILURES', 'DENIED_BOARDING', 'MISSED_CONNECTIONS' +); -UPDATE masters.tbl_rules_categories c -SET "tableName" = v."tableName" -FROM (VALUES - ('passenger-type', 'tbl_passenger_types'), - ('cabin-class', 'tbl_cabin_classes'), - ('booking-channel', 'tbl_booking_channels'), - ('membership-tier', 'tbl_membership_tiers'), - ('loyalty-tier', 'tbl_membership_tiers'), - ('flight-type', 'tbl_flight_types'), - ('journey-type', 'tbl_journey_types'), - ('fare-flexibility', 'tbl_fare_flexibilities'), - ('trip-purpose', 'tbl_trip_purposes'), - ('carrier-type', 'tbl_carrier_types'), - ('special-assistance-type', 'tbl_special_assistance_types'), - ('delay-reason', 'tbl_delay_reasons'), - ('delay-duration', 'tbl_delay_durations'), - ('extraordinary-circumstances', 'tbl_extraordinary_circumstances'), - ('cancellation-reason', 'tbl_cancellation_reasons'), - ('diversion-reason', 'tbl_diversion_reasons'), - ('missed-connection-reason', 'tbl_missed_connection_reasons'), - ('compensation-eligibility', 'tbl_compensation_eligibilities'), - ('compensation-type', 'tbl_compensation_types'), - ('refund-type', 'tbl_refund_types'), - ('flight-disruption-type', 'tbl_flight_disruption_types'), - ('airline-responsibility', 'tbl_airline_responsibilities'), - ('weather-condition', 'tbl_weather_conditions'), - ('atc-restriction', 'tbl_atc_restrictions'), - ('technical-fault-category', 'tbl_technical_fault_categories'), - ('refund-basis', 'tbl_refund_bases'), - ('currency', 'tbl_currencies'), - ('refund-method', 'tbl_refund_methods'), - ('ancillary-purchase', 'tbl_ancillary_purchases'), - ('customer-value', 'tbl_customer_values'), - ('region', 'tbl_regions'), - ('revenue-segment', 'tbl_revenue_segments'), - ('jurisdiction', 'tbl_jurisdictions'), - ('operator', 'tbl_operators'), - ('amount-type', 'tbl_amount_types') -) AS v(code, "tableName") -WHERE c.code = v.code AND (c."tableName" IS NULL OR c."tableName" != v."tableName"); +INSERT INTO masters_rule_engine.tbl_rules_categories (code, name, description, "displayOrder", "isActive") +SELECT code, name, description, displayOrder, true FROM (VALUES + ('FLIGHT_OPERATIONS', 'Flight Operations', 'Rules for flight disruptions, delays, cancellations, and diversions', 1), + ('BAGGAGE_ISSUES', 'Baggage Issues', 'Rules for delayed, damaged, or lost baggage recovery', 2), + ('CABIN_DOWNGRADES', 'Cabin Downgrades', 'Rules for involuntary cabin downgrades and seat reassignments', 3), + ('ANCILLARY_FAILURES', 'Ancillary Failures', 'Rules for unfulfilled ancillary services like Wi-Fi, meals, seats', 4), + ('DENIED_BOARDING', 'Denied Boarding', 'Rules for overbooking and involuntary denied boarding', 5), + ('MISSED_CONNECTIONS', 'Missed Connections', 'Rules for tight connection failures and rebooking compensation', 6) +) AS t(code, name, description, displayOrder) +ON CONFLICT (code) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description; -- 13. Booking Channels -INSERT INTO masters.tbl_booking_channels (label, value, "isActive") +INSERT INTO masters_lookup.tbl_booking_channels (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Airline Website', 'airline-website'), ('Airline Mobile App', 'airline-mobile-app'), @@ -318,27 +254,27 @@ SELECT label, value, true FROM (VALUES ('Online Travel Agency', 'online-travel-agency'), ('Travel Agent', 'travel-agent') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_booking_channels WHERE masters.tbl_booking_channels.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_booking_channels WHERE masters_lookup.tbl_booking_channels.value = t.value); -- 14. Flight Types -INSERT INTO masters.tbl_flight_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_flight_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Domestic', 'domestic'), ('International', 'international') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_flight_types WHERE masters.tbl_flight_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_flight_types WHERE masters_lookup.tbl_flight_types.value = t.value); -- 15. Journey Types -INSERT INTO masters.tbl_journey_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_journey_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('One Way', 'one-way'), ('Round Trip', 'round-trip'), ('Multi City', 'multi-city') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_journey_types WHERE masters.tbl_journey_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_journey_types WHERE masters_lookup.tbl_journey_types.value = t.value); -- 16. Fare Flexibilities -INSERT INTO masters.tbl_fare_flexibilities (label, value, "isActive") +INSERT INTO masters_lookup.tbl_fare_flexibilities (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Non Refundable', 'non-refundable'), ('Partially Refundable', 'partially-refundable'), @@ -346,10 +282,10 @@ SELECT label, value, true FROM (VALUES ('Exchangeable', 'exchangeable'), ('Non Changeable', 'non-changeable') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_fare_flexibilities WHERE masters.tbl_fare_flexibilities.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_fare_flexibilities WHERE masters_lookup.tbl_fare_flexibilities.value = t.value); -- 17. Carrier Types -INSERT INTO masters.tbl_carrier_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_carrier_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Operating Carrier', 'operating-carrier'), ('Marketing Carrier', 'marketing-carrier'), @@ -359,10 +295,10 @@ SELECT label, value, true FROM (VALUES ('Full Service Carrier', 'full-service-carrier'), ('Charter Carrier', 'charter-carrier') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_carrier_types WHERE masters.tbl_carrier_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_carrier_types WHERE masters_lookup.tbl_carrier_types.value = t.value); -- 18. Special Assistance Types -INSERT INTO masters.tbl_special_assistance_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_special_assistance_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Wheelchair Assistance', 'wheelchair-assistance'), ('Wheelchair Ramp', 'wheelchair-ramp'), @@ -379,10 +315,10 @@ SELECT label, value, true FROM (VALUES ('Elderly Passenger', 'elderly-passenger'), ('Other', 'other') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_special_assistance_types WHERE masters.tbl_special_assistance_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_special_assistance_types WHERE masters_lookup.tbl_special_assistance_types.value = t.value); -- 19. Delay Reasons -INSERT INTO masters.tbl_delay_reasons (label, value, "isActive") +INSERT INTO masters_lookup.tbl_delay_reasons (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Air Traffic Control Restriction', 'air-traffic-control-restriction'), ('Aircraft Rotation', 'aircraft-rotation'), @@ -399,10 +335,10 @@ SELECT label, value, true FROM (VALUES ('Technical Fault', 'technical-fault'), ('Other', 'other') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_delay_reasons WHERE masters.tbl_delay_reasons.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_delay_reasons WHERE masters_lookup.tbl_delay_reasons.value = t.value); -- 20. Delay Durations -INSERT INTO masters.tbl_delay_durations (label, value, "isActive") +INSERT INTO masters_lookup.tbl_delay_durations (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Less than 1 Hour', 'less-than-1-hour'), ('1-2 Hours', '1-2-hours'), @@ -410,10 +346,10 @@ SELECT label, value, true FROM (VALUES ('3-4 Hours', '3-4-hours'), ('More than 4 Hours', 'more-than-4-hours') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_delay_durations WHERE masters.tbl_delay_durations.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_delay_durations WHERE masters_lookup.tbl_delay_durations.value = t.value); -- 21. Extraordinary Circumstances -INSERT INTO masters.tbl_extraordinary_circumstances (label, value, "isActive") +INSERT INTO masters_lookup.tbl_extraordinary_circumstances (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Air Traffic Management Decision', 'air-traffic-management-decision'), ('Airport Closure', 'airport-closure'), @@ -427,10 +363,10 @@ SELECT label, value, true FROM (VALUES ('War', 'war'), ('Other', 'other') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_extraordinary_circumstances WHERE masters.tbl_extraordinary_circumstances.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_extraordinary_circumstances WHERE masters_lookup.tbl_extraordinary_circumstances.value = t.value); -- 22. Cancellation Reasons -INSERT INTO masters.tbl_cancellation_reasons (label, value, "isActive") +INSERT INTO masters_lookup.tbl_cancellation_reasons (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Air Traffic Control Restriction', 'air-traffic-control-restriction'), ('Airport Closure', 'airport-closure'), @@ -443,10 +379,10 @@ SELECT label, value, true FROM (VALUES ('Strike', 'strike'), ('Technical Fault', 'technical-fault') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_cancellation_reasons WHERE masters.tbl_cancellation_reasons.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_cancellation_reasons WHERE masters_lookup.tbl_cancellation_reasons.value = t.value); -- 23. Diversion Reasons -INSERT INTO masters.tbl_diversion_reasons (label, value, "isActive") +INSERT INTO masters_lookup.tbl_diversion_reasons (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Airport Closure', 'airport-closure'), ('Destination Weather', 'destination-weather'), @@ -456,10 +392,10 @@ SELECT label, value, true FROM (VALUES ('Security Threat', 'security-threat'), ('Technical Fault', 'technical-fault') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_diversion_reasons WHERE masters.tbl_diversion_reasons.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_diversion_reasons WHERE masters_lookup.tbl_diversion_reasons.value = t.value); -- 24. Missed Connection Reasons -INSERT INTO masters.tbl_missed_connection_reasons (label, value, "isActive") +INSERT INTO masters_lookup.tbl_missed_connection_reasons (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Customs Delay', 'customs-delay'), ('Flight Delay', 'flight-delay'), @@ -467,19 +403,19 @@ SELECT label, value, true FROM (VALUES ('Passenger Delay', 'passenger-delay'), ('Security Screening Delay', 'security-screening-delay') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_missed_connection_reasons WHERE masters.tbl_missed_connection_reasons.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_missed_connection_reasons WHERE masters_lookup.tbl_missed_connection_reasons.value = t.value); -- 25. Compensation Eligibilities -INSERT INTO masters.tbl_compensation_eligibilities (label, value, "isActive") +INSERT INTO masters_lookup.tbl_compensation_eligibilities (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Eligible', 'eligible'), ('Not Eligible', 'not-eligible'), ('Requires Manual Review', 'requires-manual-review') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_compensation_eligibilities WHERE masters.tbl_compensation_eligibilities.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_compensation_eligibilities WHERE masters_lookup.tbl_compensation_eligibilities.value = t.value); -- 26. Compensation Types -INSERT INTO masters.tbl_compensation_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_compensation_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Cash', 'cash'), ('Cheque', 'cheque'), @@ -489,10 +425,10 @@ SELECT label, value, true FROM (VALUES ('Hotel Accommodation', 'hotel-accommodation'), ('Ground Transport', 'ground-transport') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_compensation_types WHERE masters.tbl_compensation_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_compensation_types WHERE masters_lookup.tbl_compensation_types.value = t.value); -- 27. Refund Types -INSERT INTO masters.tbl_refund_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_refund_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Full Refund', 'full-refund'), ('Partial Refund', 'partial-refund'), @@ -501,10 +437,10 @@ SELECT label, value, true FROM (VALUES ('Tax Refund Only', 'tax-refund-only'), ('Telephone Reimbursement', 'telephone-reimbursement') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_refund_types WHERE masters.tbl_refund_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_refund_types WHERE masters_lookup.tbl_refund_types.value = t.value); -- 28. Flight Disruption Types -INSERT INTO masters.tbl_flight_disruption_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_flight_disruption_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Cancellation', 'cancellation'), ('Delay', 'delay'), @@ -512,10 +448,10 @@ SELECT label, value, true FROM (VALUES ('Diversion', 'diversion'), ('Missed Connection', 'missed-connection') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_flight_disruption_types WHERE masters.tbl_flight_disruption_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_flight_disruption_types WHERE masters_lookup.tbl_flight_disruption_types.value = t.value); -- 29. Airline Responsibilities -INSERT INTO masters.tbl_airline_responsibilities (label, value, "isActive") +INSERT INTO masters_lookup.tbl_airline_responsibilities (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Airline Responsible', 'airline-responsible'), ('Airport Responsible', 'airport-responsible'), @@ -525,10 +461,10 @@ SELECT label, value, true FROM (VALUES ('Third Party Responsible', 'third-party-responsible'), ('Snow', 'snow') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_airline_responsibilities WHERE masters.tbl_airline_responsibilities.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_airline_responsibilities WHERE masters_lookup.tbl_airline_responsibilities.value = t.value); -- 30. Weather Conditions -INSERT INTO masters.tbl_weather_conditions (label, value, "isActive") +INSERT INTO masters_lookup.tbl_weather_conditions (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Fog', 'fog'), ('Heavy Rain', 'heavy-rain'), @@ -538,10 +474,10 @@ SELECT label, value, true FROM (VALUES ('Sandstorm', 'sandstorm'), ('Thunderstorm', 'thunderstorm') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_weather_conditions WHERE masters.tbl_weather_conditions.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_weather_conditions WHERE masters_lookup.tbl_weather_conditions.value = t.value); -- 31. ATC Restrictions -INSERT INTO masters.tbl_atc_restrictions (label, value, "isActive") +INSERT INTO masters_lookup.tbl_atc_restrictions (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Airspace Closure', 'airspace-closure'), ('Flow Control', 'flow-control'), @@ -550,10 +486,10 @@ SELECT label, value, true FROM (VALUES ('Traffic Congestion', 'traffic-congestion'), ('Navigation System', 'navigation-system') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_atc_restrictions WHERE masters.tbl_atc_restrictions.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_atc_restrictions WHERE masters_lookup.tbl_atc_restrictions.value = t.value); -- 32. Technical Fault Categories -INSERT INTO masters.tbl_technical_fault_categories (label, value, "isActive") +INSERT INTO masters_lookup.tbl_technical_fault_categories (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Aircraft Damage', 'aircraft-damage'), ('Avionics', 'avionics'), @@ -564,10 +500,10 @@ SELECT label, value, true FROM (VALUES ('Volcanic Ash', 'volcanic-ash'), ('Wind Shear', 'wind-shear') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_technical_fault_categories WHERE masters.tbl_technical_fault_categories.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_technical_fault_categories WHERE masters_lookup.tbl_technical_fault_categories.value = t.value); -- 33. Operators -INSERT INTO masters.tbl_operators (code, name, symbol, "displayOrder", "isActive") +INSERT INTO masters_rule_engine.tbl_operators (code, name, symbol, "displayOrder", "isActive") SELECT code, name, symbol, displayOrder, true FROM (VALUES ('EQ', 'Equals', '=', 1), ('NE', 'Not Equals', '!=', 2), @@ -580,19 +516,19 @@ SELECT code, name, symbol, displayOrder, true FROM (VALUES ('IN', 'In', 'IN', 9), ('IS_EMPTY', 'Is Empty', 'IS EMPTY', 10) ) AS t(code, name, symbol, displayOrder) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_operators WHERE masters.tbl_operators.code = t.code); +WHERE NOT EXISTS (SELECT 1 FROM masters_rule_engine.tbl_operators WHERE masters_rule_engine.tbl_operators.code = t.code); -- 34. Refund Bases -INSERT INTO masters.tbl_refund_bases (label, value, "isActive") +INSERT INTO masters_lookup.tbl_refund_bases (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Base Fare', 'base-fare'), ('Taxes', 'taxes'), ('Total Fare', 'total-fare') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_refund_bases WHERE masters.tbl_refund_bases.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_refund_bases WHERE masters_lookup.tbl_refund_bases.value = t.value); -- 35. Currencies -INSERT INTO masters.tbl_currencies (label, value, symbol, "isActive") +INSERT INTO masters_lookup.tbl_currencies (label, value, symbol, "isActive") SELECT label, value, symbol, true FROM (VALUES ('United States Dollar', 'USD', '$'), ('Euro', 'EUR', '€'), @@ -610,26 +546,154 @@ SELECT label, value, symbol, true FROM (VALUES ('Bahraini Dinar', 'BHD', 'BHD'), ('Omani Rial', 'OMR', 'OMR') ) AS t(label, value, symbol) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_currencies WHERE masters.tbl_currencies.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_currencies WHERE masters_lookup.tbl_currencies.value = t.value); -- 36. Refund Methods -INSERT INTO masters.tbl_refund_methods (label, value, "isActive") +INSERT INTO masters_lookup.tbl_refund_methods (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Original Payment Method', 'original-payment-method'), ('Wallet', 'wallet'), ('Bank Transfer', 'bank-transfer'), ('Voucher', 'voucher') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_refund_methods WHERE masters.tbl_refund_methods.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_refund_methods WHERE masters_lookup.tbl_refund_methods.value = t.value); -- 37. Amount Types -INSERT INTO masters.tbl_amount_types (label, value, "isActive") +INSERT INTO masters_lookup.tbl_amount_types (label, value, "isActive") SELECT label, value, true FROM (VALUES ('Fixed', 'fixed'), ('Percentage', 'percentage'), ('Formula', 'formula') ) AS t(label, value) -WHERE NOT EXISTS (SELECT 1 FROM masters.tbl_amount_types WHERE masters.tbl_amount_types.value = t.value); +WHERE NOT EXISTS (SELECT 1 FROM masters_lookup.tbl_amount_types WHERE masters_lookup.tbl_amount_types.value = t.value); + +-- ============================================================================= +-- 38. Condition Groups (Level 2) +-- ============================================================================= +INSERT INTO masters_rule_engine.tbl_condition_groups (code, name, "displayOrder", "isActive") +SELECT code, name, displayOrder, true FROM (VALUES + ('FLIGHT', 'Flight Details', 1), + ('DISRUPTION', 'Disruption Details', 2), + ('PASSENGER', 'Passenger Profile', 3), + ('JOURNEY', 'Journey & Itinerary', 4), + ('BOOKING', 'Booking & Fare', 5), + ('BAGGAGE', 'Baggage Details', 6), + ('CABIN', 'Cabin & Seating', 7), + ('ANCILLARY', 'Ancillary Service Details', 8) +) AS t(code, name, displayOrder) +ON CONFLICT (code) DO UPDATE SET name = EXCLUDED.name; + +-- ============================================================================= +-- 40. Rule Category Groups Mapping (Level 1 -> Level 2) +-- ============================================================================= +INSERT INTO masters_rule_engine.tbl_rule_category_groups ("ruleCategoryId", "conditionGroupId") +SELECT c.id, g.id +FROM (VALUES + ('FLIGHT_OPERATIONS', 'FLIGHT'), + ('FLIGHT_OPERATIONS', 'DISRUPTION'), + ('FLIGHT_OPERATIONS', 'PASSENGER'), + ('FLIGHT_OPERATIONS', 'JOURNEY'), + ('FLIGHT_OPERATIONS', 'BOOKING'), + ('BAGGAGE_ISSUES', 'PASSENGER'), + ('BAGGAGE_ISSUES', 'JOURNEY'), + ('BAGGAGE_ISSUES', 'BAGGAGE'), + ('CABIN_DOWNGRADES', 'PASSENGER'), + ('CABIN_DOWNGRADES', 'JOURNEY'), + ('CABIN_DOWNGRADES', 'CABIN'), + ('CABIN_DOWNGRADES', 'BOOKING'), + ('ANCILLARY_FAILURES', 'PASSENGER'), + ('ANCILLARY_FAILURES', 'ANCILLARY'), + ('ANCILLARY_FAILURES', 'BOOKING'), + ('DENIED_BOARDING', 'FLIGHT'), + ('DENIED_BOARDING', 'PASSENGER'), + ('DENIED_BOARDING', 'JOURNEY'), + ('DENIED_BOARDING', 'BOOKING'), + ('MISSED_CONNECTIONS', 'FLIGHT'), + ('MISSED_CONNECTIONS', 'PASSENGER'), + ('MISSED_CONNECTIONS', 'JOURNEY'), + ('MISSED_CONNECTIONS', 'BOOKING') +) AS v(cat_code, group_code) +JOIN masters_rule_engine.tbl_rules_categories c ON c.code = v.cat_code +JOIN masters_rule_engine.tbl_condition_groups g ON g.code = v.group_code +WHERE NOT EXISTS ( + SELECT 1 FROM masters_rule_engine.tbl_rule_category_groups rcg + WHERE rcg."ruleCategoryId" = c.id AND rcg."conditionGroupId" = g.id +); + +-- ============================================================================= +-- 41. Condition Fields (Level 3) +-- ============================================================================= +INSERT INTO masters_rule_engine.tbl_condition_fields ("groupId", code, name, "lookupTable", "dataType", "operatorType", "displayOrder", "isActive") +SELECT g.id, v.code, v.name, v.lookup_table, v.data_type, v.operator_type, v.display_order, true +FROM (VALUES + -- FLIGHT + ('FLIGHT', 'flight_type', 'Flight Type', 'tbl_flight_types', 'ENUM', 'COMPARISON', 1), + ('FLIGHT', 'origin_airport', 'Origin Airport', NULL, 'STRING', 'TEXT', 2), + ('FLIGHT', 'destination_airport', 'Destination Airport', NULL, 'STRING', 'TEXT', 3), + ('FLIGHT', 'operating_carrier', 'Operating Carrier', 'tbl_carrier_types', 'ENUM', 'COMPARISON', 4), + ('FLIGHT', 'marketing_carrier', 'Marketing Carrier', 'tbl_carrier_types', 'ENUM', 'COMPARISON', 5), + ('FLIGHT', 'flight_distance', 'Flight Distance (km)', NULL, 'NUMBER', 'COMPARISON', 6), + + -- DISRUPTION + ('DISRUPTION', 'delay_duration', 'Delay Duration (mins)', 'tbl_delay_durations', 'NUMBER', 'COMPARISON', 1), + ('DISRUPTION', 'delay_reason', 'Delay Reason', 'tbl_delay_reasons', 'ENUM', 'SET', 2), + ('DISRUPTION', 'cancellation_reason', 'Cancellation Reason', 'tbl_cancellation_reasons', 'ENUM', 'SET', 3), + ('DISRUPTION', 'diversion_reason', 'Diversion Reason', 'tbl_diversion_reasons', 'ENUM', 'SET', 4), + ('DISRUPTION', 'weather_condition', 'Weather Condition', 'tbl_weather_conditions', 'ENUM', 'SET', 5), + ('DISRUPTION', 'atc_restriction', 'ATC Restriction', 'tbl_atc_restrictions', 'ENUM', 'SET', 6), + ('DISRUPTION', 'technical_fault', 'Technical Fault', 'tbl_technical_fault_categories', 'ENUM', 'SET', 7), + ('DISRUPTION', 'extraordinary_circumstance', 'Extraordinary Circumstance', 'tbl_extraordinary_circumstances', 'ENUM', 'SET', 8), + ('DISRUPTION', 'airline_responsibility', 'Airline Responsibility', 'tbl_airline_responsibilities', 'ENUM', 'COMPARISON', 9), + + -- PASSENGER + ('PASSENGER', 'passenger_type', 'Passenger Type', 'tbl_passenger_types', 'ENUM', 'SET', 1), + ('PASSENGER', 'cabin_class', 'Cabin Class', 'tbl_cabin_classes', 'ENUM', 'SET', 2), + ('PASSENGER', 'membership_tier', 'Membership Tier', 'tbl_membership_tiers', 'ENUM', 'SET', 3), + ('PASSENGER', 'loyalty_tier', 'Loyalty Tier', 'tbl_membership_tiers', 'ENUM', 'SET', 4), + ('PASSENGER', 'customer_value', 'Customer Value', 'tbl_customer_values', 'ENUM', 'COMPARISON', 5), + ('PASSENGER', 'corporate_customer', 'Corporate Customer', NULL, 'BOOLEAN', 'BOOLEAN', 6), + ('PASSENGER', 'group_booking', 'Group Booking', NULL, 'BOOLEAN', 'BOOLEAN', 7), + ('PASSENGER', 'special_assistance', 'Special Assistance Type', 'tbl_special_assistance_types', 'ENUM', 'SET', 8), + + -- JOURNEY + ('JOURNEY', 'journey_type', 'Journey Type', 'tbl_journey_types', 'ENUM', 'COMPARISON', 1), + ('JOURNEY', 'protected_connection', 'Protected Connection', NULL, 'BOOLEAN', 'BOOLEAN', 2), + ('JOURNEY', 'self_transfer', 'Self Transfer', NULL, 'BOOLEAN', 'BOOLEAN', 3), + ('JOURNEY', 'number_of_segments', 'Number Of Segments', NULL, 'NUMBER', 'COMPARISON', 4), + ('JOURNEY', 'final_destination_delay', 'Final Destination Delay (mins)', NULL, 'NUMBER', 'COMPARISON', 5), + + -- BOOKING + ('BOOKING', 'booking_channel', 'Booking Channel', 'tbl_booking_channels', 'ENUM', 'SET', 1), + ('BOOKING', 'refundable_ticket', 'Refundable Ticket', NULL, 'BOOLEAN', 'BOOLEAN', 2), + ('BOOKING', 'fare_flexibility', 'Fare Flexibility', 'tbl_fare_flexibilities', 'ENUM', 'COMPARISON', 3), + ('BOOKING', 'ticket_value', 'Ticket Value', NULL, 'NUMBER', 'COMPARISON', 4), + ('BOOKING', 'ancillary_purchased', 'Ancillary Purchased', 'tbl_ancillary_purchases', 'ENUM', 'SET', 5), + + -- BAGGAGE + ('BAGGAGE', 'bag_status', 'Bag Status', NULL, 'STRING', 'TEXT', 1), + ('BAGGAGE', 'bag_type', 'Bag Type', NULL, 'STRING', 'TEXT', 2), + ('BAGGAGE', 'bag_delay', 'Bag Delay Duration (hrs)', NULL, 'NUMBER', 'COMPARISON', 3), + ('BAGGAGE', 'bag_value', 'Bag Value', NULL, 'NUMBER', 'COMPARISON', 4), + ('BAGGAGE', 'pir_created', 'PIR Created', NULL, 'BOOLEAN', 'BOOLEAN', 5), + + -- CABIN + ('CABIN', 'original_cabin', 'Original Cabin', 'tbl_cabin_classes', 'ENUM', 'COMPARISON', 1), + ('CABIN', 'assigned_cabin', 'Assigned Cabin', 'tbl_cabin_classes', 'ENUM', 'COMPARISON', 2), + ('CABIN', 'downgrade_level', 'Downgrade Level', NULL, 'NUMBER', 'COMPARISON', 3), + ('CABIN', 'seat_type', 'Seat Type', NULL, 'STRING', 'TEXT', 4), + + -- ANCILLARY + ('ANCILLARY', 'ancillary_type', 'Ancillary Type', 'tbl_ancillary_purchases', 'ENUM', 'SET', 1), + ('ANCILLARY', 'ancillary_delivered', 'Ancillary Delivered', NULL, 'BOOLEAN', 'BOOLEAN', 2), + ('ANCILLARY', 'service_value', 'Service Value', NULL, 'NUMBER', 'COMPARISON', 3) +) AS v(group_code, code, name, lookup_table, data_type, operator_type, display_order) +JOIN masters_rule_engine.tbl_condition_groups g ON g.code = v.group_code +ON CONFLICT (code) DO UPDATE SET + name = EXCLUDED.name, + "lookupTable" = EXCLUDED."lookupTable", + "dataType" = EXCLUDED."dataType", + "operatorType" = EXCLUDED."operatorType", + "displayOrder" = EXCLUDED."displayOrder"; diff --git a/src/database/database.module.ts b/src/database/database.module.ts index 5ce2bbe..056dfd6 100644 --- a/src/database/database.module.ts +++ b/src/database/database.module.ts @@ -30,8 +30,13 @@ import { ConfigModule, ConfigService } from '@nestjs/config'; await dataSource.initialize(); // Create schemas if they don't exist + await dataSource.query(`DROP SCHEMA IF EXISTS "masters" CASCADE;`); + await dataSource.query(`DROP SCHEMA IF EXISTS "cohort" CASCADE;`); + await dataSource.query(`DROP SCHEMA IF EXISTS "policy_engine" CASCADE;`); await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "tenant";`); - await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "masters";`); + await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "masters_rule_engine";`); + await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "masters_action_builder";`); + await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "masters_lookup";`); await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "cohort";`); await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "policy_engine";`); await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "recovery_incident";`); diff --git a/src/modules/master-data/entities/action-category.entity.ts b/src/modules/master-data/entities/action-category.entity.ts index d29de6d..6ca721e 100644 --- a/src/modules/master-data/entities/action-category.entity.ts +++ b/src/modules/master-data/entities/action-category.entity.ts @@ -9,7 +9,7 @@ import { } from 'typeorm'; import { ActionType } from './action-type.entity'; -@Entity({ name: 'tbl_action_categories', schema: 'masters' }) +@Entity({ name: 'tbl_action_categories', schema: 'masters_action_builder' }) @Index('UQ_action_category_code', ['code'], { unique: true }) export class ActionCategory { @PrimaryGeneratedColumn('uuid') diff --git a/src/modules/master-data/entities/action-submission-value.entity.ts b/src/modules/master-data/entities/action-submission-value.entity.ts index 59088c9..43a99e8 100644 --- a/src/modules/master-data/entities/action-submission-value.entity.ts +++ b/src/modules/master-data/entities/action-submission-value.entity.ts @@ -10,7 +10,7 @@ import { import { ActionSubmission } from './action-submission.entity'; import { FieldDefinition } from './field-definition.entity'; -@Entity({ name: 'tbl_action_submission_values', schema: 'masters' }) +@Entity({ name: 'tbl_action_submission_values', schema: 'masters_action_builder' }) export class ActionSubmissionValue { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/action-submission.entity.ts b/src/modules/master-data/entities/action-submission.entity.ts index 39ae20c..cabeba3 100644 --- a/src/modules/master-data/entities/action-submission.entity.ts +++ b/src/modules/master-data/entities/action-submission.entity.ts @@ -12,7 +12,7 @@ import { ActionCategory } from './action-category.entity'; import { ActionType } from './action-type.entity'; import { ActionSubmissionValue } from './action-submission-value.entity'; -@Entity({ name: 'tbl_action_submissions', schema: 'masters' }) +@Entity({ name: 'tbl_action_submissions', schema: 'masters_action_builder' }) export class ActionSubmission { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/action-type.entity.ts b/src/modules/master-data/entities/action-type.entity.ts index 7843bc6..7d45d65 100644 --- a/src/modules/master-data/entities/action-type.entity.ts +++ b/src/modules/master-data/entities/action-type.entity.ts @@ -11,7 +11,7 @@ import { import { ActionCategory } from './action-category.entity'; import { FieldDefinition } from './field-definition.entity'; -@Entity({ name: 'tbl_action_types', schema: 'masters' }) +@Entity({ name: 'tbl_action_types', schema: 'masters_action_builder' }) export class ActionType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/airline-responsibility.entity.ts b/src/modules/master-data/entities/airline-responsibility.entity.ts index 77d4a43..55a171b 100644 --- a/src/modules/master-data/entities/airline-responsibility.entity.ts +++ b/src/modules/master-data/entities/airline-responsibility.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_airline_responsibilities', schema: 'masters' }) +@Entity({ name: 'tbl_airline_responsibilities', schema: 'masters_lookup' }) export class AirlineResponsibility { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/amount-type.entity.ts b/src/modules/master-data/entities/amount-type.entity.ts index b108a53..7ac304a 100644 --- a/src/modules/master-data/entities/amount-type.entity.ts +++ b/src/modules/master-data/entities/amount-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_amount_types', schema: 'masters' }) +@Entity({ name: 'tbl_amount_types', schema: 'masters_lookup' }) export class AmountType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/ancillary-purchase.entity.ts b/src/modules/master-data/entities/ancillary-purchase.entity.ts index bd04a1c..654f676 100644 --- a/src/modules/master-data/entities/ancillary-purchase.entity.ts +++ b/src/modules/master-data/entities/ancillary-purchase.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_ancillary_purchases', schema: 'masters' }) +@Entity({ name: 'tbl_ancillary_purchases', schema: 'masters_lookup' }) export class AncillaryPurchase { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/atc-restriction.entity.ts b/src/modules/master-data/entities/atc-restriction.entity.ts index 85a888f..5dd3560 100644 --- a/src/modules/master-data/entities/atc-restriction.entity.ts +++ b/src/modules/master-data/entities/atc-restriction.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_atc_restrictions', schema: 'masters' }) +@Entity({ name: 'tbl_atc_restrictions', schema: 'masters_lookup' }) export class AtcRestriction { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/booking-channel.entity.ts b/src/modules/master-data/entities/booking-channel.entity.ts index 124b9a6..73982ef 100644 --- a/src/modules/master-data/entities/booking-channel.entity.ts +++ b/src/modules/master-data/entities/booking-channel.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_booking_channels', schema: 'masters' }) +@Entity({ name: 'tbl_booking_channels', schema: 'masters_lookup' }) export class BookingChannel { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/cabin-class.entity.ts b/src/modules/master-data/entities/cabin-class.entity.ts index 3fa2a9a..2c0cfa1 100644 --- a/src/modules/master-data/entities/cabin-class.entity.ts +++ b/src/modules/master-data/entities/cabin-class.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_cabin_classes', schema: 'masters' }) +@Entity({ name: 'tbl_cabin_classes', schema: 'masters_lookup' }) export class CabinClass { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/cancellation-reason.entity.ts b/src/modules/master-data/entities/cancellation-reason.entity.ts index 8dc7306..3c309fd 100644 --- a/src/modules/master-data/entities/cancellation-reason.entity.ts +++ b/src/modules/master-data/entities/cancellation-reason.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_cancellation_reasons', schema: 'masters' }) +@Entity({ name: 'tbl_cancellation_reasons', schema: 'masters_lookup' }) export class CancellationReason { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/carrier-type.entity.ts b/src/modules/master-data/entities/carrier-type.entity.ts index 387965e..89ef634 100644 --- a/src/modules/master-data/entities/carrier-type.entity.ts +++ b/src/modules/master-data/entities/carrier-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_carrier_types', schema: 'masters' }) +@Entity({ name: 'tbl_carrier_types', schema: 'masters_lookup' }) export class CarrierType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/compensation-eligibility.entity.ts b/src/modules/master-data/entities/compensation-eligibility.entity.ts index 8eed022..dbe133d 100644 --- a/src/modules/master-data/entities/compensation-eligibility.entity.ts +++ b/src/modules/master-data/entities/compensation-eligibility.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_compensation_eligibilities', schema: 'masters' }) +@Entity({ name: 'tbl_compensation_eligibilities', schema: 'masters_lookup' }) export class CompensationEligibility { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/compensation-type.entity.ts b/src/modules/master-data/entities/compensation-type.entity.ts index c682478..cbced37 100644 --- a/src/modules/master-data/entities/compensation-type.entity.ts +++ b/src/modules/master-data/entities/compensation-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_compensation_types', schema: 'masters' }) +@Entity({ name: 'tbl_compensation_types', schema: 'masters_lookup' }) export class CompensationType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/condition-field.entity.ts b/src/modules/master-data/entities/condition-field.entity.ts new file mode 100644 index 0000000..87dde3d --- /dev/null +++ b/src/modules/master-data/entities/condition-field.entity.ts @@ -0,0 +1,42 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm'; +import { ConditionGroup } from './condition-group.entity'; + +@Entity({ name: 'tbl_condition_fields', schema: 'masters_rule_engine' }) +export class ConditionField { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column({ name: 'groupId', type: 'uuid' }) + groupId!: string; + + @ManyToOne(() => ConditionGroup, (group) => group.fields, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'groupId' }) + group!: ConditionGroup; + + @Column({ unique: true }) + code!: string; + + @Column() + name!: string; + + @Column({ name: 'lookupTable', type: 'varchar', nullable: true }) + lookupTable?: string; + + @Column({ name: 'dataType', type: 'varchar', default: 'STRING' }) + dataType!: string; + + @Column({ name: 'operatorType', type: 'varchar', default: 'COMPARISON' }) + operatorType!: string; + + @Column({ name: 'displayOrder', type: 'int', default: 0 }) + displayOrder!: number; + + @Column({ name: 'isActive', default: true }) + isActive!: boolean; + + @CreateDateColumn({ name: 'createdAt' }) + createdAt!: Date; + + @UpdateDateColumn({ name: 'updatedAt' }) + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/condition-group.entity.ts b/src/modules/master-data/entities/condition-group.entity.ts new file mode 100644 index 0000000..7b45250 --- /dev/null +++ b/src/modules/master-data/entities/condition-group.entity.ts @@ -0,0 +1,33 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm'; +import { ConditionField } from './condition-field.entity'; +import { RuleCategoryGroup } from './rule-category-group.entity'; + +@Entity({ name: 'tbl_condition_groups', schema: 'masters_rule_engine' }) +export class ConditionGroup { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column({ unique: true }) + code!: string; + + @Column() + name!: string; + + @Column({ name: 'displayOrder', type: 'int', default: 0 }) + displayOrder!: number; + + @Column({ name: 'isActive', default: true }) + isActive!: boolean; + + @CreateDateColumn({ name: 'createdAt' }) + createdAt!: Date; + + @UpdateDateColumn({ name: 'updatedAt' }) + updatedAt!: Date; + + @OneToMany(() => ConditionField, (field) => field.group) + fields!: ConditionField[]; + + @OneToMany(() => RuleCategoryGroup, (rcg) => rcg.conditionGroup) + categoryMappings!: RuleCategoryGroup[]; +} diff --git a/src/modules/master-data/entities/currency.entity.ts b/src/modules/master-data/entities/currency.entity.ts index 843a2ca..8351aa1 100644 --- a/src/modules/master-data/entities/currency.entity.ts +++ b/src/modules/master-data/entities/currency.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_currencies', schema: 'masters' }) +@Entity({ name: 'tbl_currencies', schema: 'masters_lookup' }) export class Currency { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/customer-value.entity.ts b/src/modules/master-data/entities/customer-value.entity.ts index e1b1c3d..d8f2082 100644 --- a/src/modules/master-data/entities/customer-value.entity.ts +++ b/src/modules/master-data/entities/customer-value.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_customer_values', schema: 'masters' }) +@Entity({ name: 'tbl_customer_values', schema: 'masters_lookup' }) export class CustomerValue { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/delay-duration.entity.ts b/src/modules/master-data/entities/delay-duration.entity.ts index fac6874..b55bcbf 100644 --- a/src/modules/master-data/entities/delay-duration.entity.ts +++ b/src/modules/master-data/entities/delay-duration.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_delay_durations', schema: 'masters' }) +@Entity({ name: 'tbl_delay_durations', schema: 'masters_lookup' }) export class DelayDuration { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/delay-reason.entity.ts b/src/modules/master-data/entities/delay-reason.entity.ts index e9e37e2..ccaf28c 100644 --- a/src/modules/master-data/entities/delay-reason.entity.ts +++ b/src/modules/master-data/entities/delay-reason.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_delay_reasons', schema: 'masters' }) +@Entity({ name: 'tbl_delay_reasons', schema: 'masters_lookup' }) export class DelayReason { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/diversion-reason.entity.ts b/src/modules/master-data/entities/diversion-reason.entity.ts index 48a6084..be6f585 100644 --- a/src/modules/master-data/entities/diversion-reason.entity.ts +++ b/src/modules/master-data/entities/diversion-reason.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_diversion_reasons', schema: 'masters' }) +@Entity({ name: 'tbl_diversion_reasons', schema: 'masters_lookup' }) export class DiversionReason { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/extraordinary-circumstance.entity.ts b/src/modules/master-data/entities/extraordinary-circumstance.entity.ts index 92b2cc3..892bace 100644 --- a/src/modules/master-data/entities/extraordinary-circumstance.entity.ts +++ b/src/modules/master-data/entities/extraordinary-circumstance.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_extraordinary_circumstances', schema: 'masters' }) +@Entity({ name: 'tbl_extraordinary_circumstances', schema: 'masters_lookup' }) export class ExtraordinaryCircumstance { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/fare-flexibility.entity.ts b/src/modules/master-data/entities/fare-flexibility.entity.ts index d608447..53eb297 100644 --- a/src/modules/master-data/entities/fare-flexibility.entity.ts +++ b/src/modules/master-data/entities/fare-flexibility.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_fare_flexibilities', schema: 'masters' }) +@Entity({ name: 'tbl_fare_flexibilities', schema: 'masters_lookup' }) export class FareFlexibility { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/field-definition.entity.ts b/src/modules/master-data/entities/field-definition.entity.ts index 40eabc6..714f607 100644 --- a/src/modules/master-data/entities/field-definition.entity.ts +++ b/src/modules/master-data/entities/field-definition.entity.ts @@ -10,7 +10,7 @@ import { } from 'typeorm'; import { ActionType } from './action-type.entity'; -@Entity({ name: 'tbl_field_definitions', schema: 'masters' }) +@Entity({ name: 'tbl_field_definitions', schema: 'masters_action_builder' }) @Index('UQ_field_definition_action_type_code', ['actionTypeId', 'fieldCode'], { unique: true }) export class FieldDefinition { @PrimaryGeneratedColumn('uuid') diff --git a/src/modules/master-data/entities/flight-disruption-type.entity.ts b/src/modules/master-data/entities/flight-disruption-type.entity.ts index d7224a7..f36f260 100644 --- a/src/modules/master-data/entities/flight-disruption-type.entity.ts +++ b/src/modules/master-data/entities/flight-disruption-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_flight_disruption_types', schema: 'masters' }) +@Entity({ name: 'tbl_flight_disruption_types', schema: 'masters_lookup' }) export class FlightDisruptionType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/flight-type.entity.ts b/src/modules/master-data/entities/flight-type.entity.ts index 441a0e2..2f4bca8 100644 --- a/src/modules/master-data/entities/flight-type.entity.ts +++ b/src/modules/master-data/entities/flight-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_flight_types', schema: 'masters' }) +@Entity({ name: 'tbl_flight_types', schema: 'masters_lookup' }) export class FlightType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/journey-type.entity.ts b/src/modules/master-data/entities/journey-type.entity.ts index 41103eb..4facdc5 100644 --- a/src/modules/master-data/entities/journey-type.entity.ts +++ b/src/modules/master-data/entities/journey-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_journey_types', schema: 'masters' }) +@Entity({ name: 'tbl_journey_types', schema: 'masters_lookup' }) export class JourneyType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/jurisdiction.entity.ts b/src/modules/master-data/entities/jurisdiction.entity.ts index 5b0317a..157d4c0 100644 --- a/src/modules/master-data/entities/jurisdiction.entity.ts +++ b/src/modules/master-data/entities/jurisdiction.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_jurisdictions', schema: 'masters' }) +@Entity({ name: 'tbl_jurisdictions', schema: 'masters_lookup' }) export class Jurisdiction { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/membership-tier.entity.ts b/src/modules/master-data/entities/membership-tier.entity.ts index 94fa8d4..c146fae 100644 --- a/src/modules/master-data/entities/membership-tier.entity.ts +++ b/src/modules/master-data/entities/membership-tier.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_membership_tiers', schema: 'masters' }) +@Entity({ name: 'tbl_membership_tiers', schema: 'masters_lookup' }) export class MembershipTier { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/missed-connection-reason.entity.ts b/src/modules/master-data/entities/missed-connection-reason.entity.ts index a73726a..1a3f1d1 100644 --- a/src/modules/master-data/entities/missed-connection-reason.entity.ts +++ b/src/modules/master-data/entities/missed-connection-reason.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_missed_connection_reasons', schema: 'masters' }) +@Entity({ name: 'tbl_missed_connection_reasons', schema: 'masters_lookup' }) export class MissedConnectionReason { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/operator.entity.ts b/src/modules/master-data/entities/operator.entity.ts index 87bad4f..c87a79f 100644 --- a/src/modules/master-data/entities/operator.entity.ts +++ b/src/modules/master-data/entities/operator.entity.ts @@ -7,7 +7,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_operators', schema: 'masters' }) +@Entity({ name: 'tbl_operators', schema: 'masters_rule_engine' }) @Index('UQ_operator_code', ['code'], { unique: true }) export class Operator { @PrimaryGeneratedColumn('uuid') diff --git a/src/modules/master-data/entities/passenger-type.entity.ts b/src/modules/master-data/entities/passenger-type.entity.ts index 7233289..4916fab 100644 --- a/src/modules/master-data/entities/passenger-type.entity.ts +++ b/src/modules/master-data/entities/passenger-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_passenger_types', schema: 'masters' }) +@Entity({ name: 'tbl_passenger_types', schema: 'masters_lookup' }) export class PassengerType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/refund-basis.entity.ts b/src/modules/master-data/entities/refund-basis.entity.ts index 332a7e9..ce0b5be 100644 --- a/src/modules/master-data/entities/refund-basis.entity.ts +++ b/src/modules/master-data/entities/refund-basis.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_refund_bases', schema: 'masters' }) +@Entity({ name: 'tbl_refund_bases', schema: 'masters_lookup' }) export class RefundBasis { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/refund-method.entity.ts b/src/modules/master-data/entities/refund-method.entity.ts index 6bcc642..11e785b 100644 --- a/src/modules/master-data/entities/refund-method.entity.ts +++ b/src/modules/master-data/entities/refund-method.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_refund_methods', schema: 'masters' }) +@Entity({ name: 'tbl_refund_methods', schema: 'masters_lookup' }) export class RefundMethod { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/refund-type.entity.ts b/src/modules/master-data/entities/refund-type.entity.ts index 2d1d3ea..c62f55e 100644 --- a/src/modules/master-data/entities/refund-type.entity.ts +++ b/src/modules/master-data/entities/refund-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_refund_types', schema: 'masters' }) +@Entity({ name: 'tbl_refund_types', schema: 'masters_lookup' }) export class RefundType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/region.entity.ts b/src/modules/master-data/entities/region.entity.ts index 2a494a3..bc6e00e 100644 --- a/src/modules/master-data/entities/region.entity.ts +++ b/src/modules/master-data/entities/region.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_regions', schema: 'masters' }) +@Entity({ name: 'tbl_regions', schema: 'masters_lookup' }) export class Region { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/revenue-segment.entity.ts b/src/modules/master-data/entities/revenue-segment.entity.ts index ddb3420..44b8412 100644 --- a/src/modules/master-data/entities/revenue-segment.entity.ts +++ b/src/modules/master-data/entities/revenue-segment.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_revenue_segments', schema: 'masters' }) +@Entity({ name: 'tbl_revenue_segments', schema: 'masters_lookup' }) export class RevenueSegment { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/rule-category-group.entity.ts b/src/modules/master-data/entities/rule-category-group.entity.ts new file mode 100644 index 0000000..7d80818 --- /dev/null +++ b/src/modules/master-data/entities/rule-category-group.entity.ts @@ -0,0 +1,27 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne, JoinColumn, Unique } from 'typeorm'; +import { RuleCategory } from './rule-category.entity'; +import { ConditionGroup } from './condition-group.entity'; + +@Entity({ name: 'tbl_rule_category_groups', schema: 'masters_rule_engine' }) +@Unique(['ruleCategoryId', 'conditionGroupId']) +export class RuleCategoryGroup { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column({ name: 'ruleCategoryId', type: 'uuid' }) + ruleCategoryId!: string; + + @ManyToOne(() => RuleCategory, (rc) => rc.groupMappings, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'ruleCategoryId' }) + ruleCategory!: RuleCategory; + + @Column({ name: 'conditionGroupId', type: 'uuid' }) + conditionGroupId!: string; + + @ManyToOne(() => ConditionGroup, (cg) => cg.categoryMappings, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'conditionGroupId' }) + conditionGroup!: ConditionGroup; + + @CreateDateColumn({ name: 'createdAt' }) + createdAt!: Date; +} diff --git a/src/modules/master-data/entities/rule-category.entity.ts b/src/modules/master-data/entities/rule-category.entity.ts index 42ffd31..0d5920d 100644 --- a/src/modules/master-data/entities/rule-category.entity.ts +++ b/src/modules/master-data/entities/rule-category.entity.ts @@ -5,9 +5,11 @@ import { CreateDateColumn, Index, UpdateDateColumn, + OneToMany, } from 'typeorm'; +import { RuleCategoryGroup } from './rule-category-group.entity'; -@Entity({ name: 'tbl_rules_categories', schema: 'masters' }) +@Entity({ name: 'tbl_rules_categories', schema: 'masters_rule_engine' }) @Index('UQ_rule_category_code', ['code'], { unique: true }) export class RuleCategory { @PrimaryGeneratedColumn('uuid') @@ -36,4 +38,8 @@ export class RuleCategory { @UpdateDateColumn() updatedAt!: Date; + + @OneToMany(() => RuleCategoryGroup, (rcg) => rcg.ruleCategory) + groupMappings!: RuleCategoryGroup[]; } + diff --git a/src/modules/master-data/entities/special-assistance-type.entity.ts b/src/modules/master-data/entities/special-assistance-type.entity.ts index f30ebe2..76d8da0 100644 --- a/src/modules/master-data/entities/special-assistance-type.entity.ts +++ b/src/modules/master-data/entities/special-assistance-type.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_special_assistance_types', schema: 'masters' }) +@Entity({ name: 'tbl_special_assistance_types', schema: 'masters_lookup' }) export class SpecialAssistanceType { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/technical-fault-category.entity.ts b/src/modules/master-data/entities/technical-fault-category.entity.ts index 0ac314c..6a37485 100644 --- a/src/modules/master-data/entities/technical-fault-category.entity.ts +++ b/src/modules/master-data/entities/technical-fault-category.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_technical_fault_categories', schema: 'masters' }) +@Entity({ name: 'tbl_technical_fault_categories', schema: 'masters_lookup' }) export class TechnicalFaultCategory { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/trip-purpose.entity.ts b/src/modules/master-data/entities/trip-purpose.entity.ts index 16a1d4a..80627fa 100644 --- a/src/modules/master-data/entities/trip-purpose.entity.ts +++ b/src/modules/master-data/entities/trip-purpose.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_trip_purposes', schema: 'masters' }) +@Entity({ name: 'tbl_trip_purposes', schema: 'masters_lookup' }) export class TripPurpose { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/weather-condition.entity.ts b/src/modules/master-data/entities/weather-condition.entity.ts index 4276da4..7055171 100644 --- a/src/modules/master-data/entities/weather-condition.entity.ts +++ b/src/modules/master-data/entities/weather-condition.entity.ts @@ -6,7 +6,7 @@ import { UpdateDateColumn, } from 'typeorm'; -@Entity({ name: 'tbl_weather_conditions', schema: 'masters' }) +@Entity({ name: 'tbl_weather_conditions', schema: 'masters_lookup' }) export class WeatherCondition { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/master-data.controller.ts b/src/modules/master-data/master-data.controller.ts index 18be71b..9c809ec 100644 --- a/src/modules/master-data/master-data.controller.ts +++ b/src/modules/master-data/master-data.controller.ts @@ -20,6 +20,13 @@ import { ActionSubmissionDto } from './dto/action-submission.dto'; export class MasterDataController { constructor(private readonly masterDataService: MasterDataService) { } + @Get('lookup-tables') + @ApiOperation({ summary: 'Get list of all master domain lookup tables' }) + @ApiResponse({ status: 200, description: 'List of master lookup tables' }) + async findAllLookupTables() { + return this.masterDataService.findAllLookupTables(); + } + @Get('categories') @ApiOperation({ summary: 'Get all masters table list as categories' }) @ApiResponse({ status: 200, description: 'List of masters table categories' }) @@ -77,6 +84,29 @@ export class MasterDataController { return this.masterDataService.findRuleCategoryValuesByCode(code); } + // --- 3-Level Policy Engine Metadata Endpoints --- + + @Get('rule-categories/:id/condition-groups') + @ApiOperation({ summary: 'Get allowed condition groups for a rule category' }) + @ApiParam({ name: 'id', type: String, description: 'Rule category code or id' }) + async findConditionGroupsByRuleCategory(@Param('id') id: string) { + return this.masterDataService.findConditionGroupsByRuleCategory(id); + } + + @Get('condition-groups/:groupId/fields') + @ApiOperation({ summary: 'Get condition fields for a condition group' }) + @ApiParam({ name: 'groupId', type: String, description: 'Condition group code or id' }) + async findConditionFieldsByGroup(@Param('groupId') groupId: string) { + return this.masterDataService.findConditionFieldsByGroup(groupId); + } + + @Get('condition-fields/:fieldId/lookup-values') + @ApiOperation({ summary: 'Get dynamic lookup drop-down values for a condition field' }) + @ApiParam({ name: 'fieldId', type: String, description: 'Condition field code or id' }) + async findLookupValuesForField(@Param('fieldId') fieldId: string) { + return this.masterDataService.findLookupValuesForField(fieldId); + } + @Get('operators') @ApiOperation({ summary: 'Get all operators' }) @ApiResponse({ status: 200, description: 'List of operators' }) diff --git a/src/modules/master-data/master-data.module.ts b/src/modules/master-data/master-data.module.ts index c9eaa20..7872e55 100644 --- a/src/modules/master-data/master-data.module.ts +++ b/src/modules/master-data/master-data.module.ts @@ -45,6 +45,10 @@ import { Currency } from './entities/currency.entity'; import { RefundMethod } from './entities/refund-method.entity'; import { AmountType } from './entities/amount-type.entity'; +import { ConditionGroup } from './entities/condition-group.entity'; +import { ConditionField } from './entities/condition-field.entity'; +import { RuleCategoryGroup } from './entities/rule-category-group.entity'; + @Module({ imports: [ TypeOrmModule.forFeature([ @@ -88,6 +92,9 @@ import { AmountType } from './entities/amount-type.entity'; Currency, RefundMethod, AmountType, + ConditionGroup, + ConditionField, + RuleCategoryGroup, ]), ], controllers: [MasterDataController], diff --git a/src/modules/master-data/master-data.service.ts b/src/modules/master-data/master-data.service.ts index 91d81e3..3daae44 100644 --- a/src/modules/master-data/master-data.service.ts +++ b/src/modules/master-data/master-data.service.ts @@ -45,6 +45,9 @@ import { RefundBasis } from './entities/refund-basis.entity'; import { Currency } from './entities/currency.entity'; import { RefundMethod } from './entities/refund-method.entity'; import { AmountType } from './entities/amount-type.entity'; +import { ConditionGroup } from './entities/condition-group.entity'; +import { ConditionField } from './entities/condition-field.entity'; +import { RuleCategoryGroup } from './entities/rule-category-group.entity'; import { CreateActionCategoryDto } from './dto/create-action-category.dto'; import { UpdateActionCategoryDto } from './dto/update-action-category.dto'; @@ -101,6 +104,9 @@ export class MasterDataService implements OnModuleInit { @InjectRepository(Currency) private currencyRepo: Repository, @InjectRepository(RefundMethod) private refundMethodRepo: Repository, @InjectRepository(AmountType) private amountTypeRepo: Repository, + @InjectRepository(ConditionGroup) private conditionGroupRepo: Repository, + @InjectRepository(ConditionField) private conditionFieldRepo: Repository, + @InjectRepository(RuleCategoryGroup) private ruleCategoryGroupRepo: Repository, ) { } private getRepositoryByCategory(category: string): Repository { @@ -303,6 +309,44 @@ export class MasterDataService implements OnModuleInit { }); } + async findAllLookupTables(): Promise> { + return [ + { code: 'membership-tier', name: 'Membership Tiers', tableName: 'tbl_membership_tiers', description: 'Passenger membership & loyalty tiers' }, + { code: 'customer-value', name: 'Customer Values', tableName: 'tbl_customer_values', description: 'Customer value segmentation' }, + { code: 'region', name: 'Regions', tableName: 'tbl_regions', description: 'Geographic regions' }, + { code: 'trip-purpose', name: 'Trip Purposes', tableName: 'tbl_trip_purposes', description: 'Passenger travel purposes' }, + { code: 'cabin-class', name: 'Cabin Classes', tableName: 'tbl_cabin_classes', description: 'Aircraft cabin classes' }, + { code: 'passenger-type', name: 'Passenger Types', tableName: 'tbl_passenger_types', description: 'Passenger age/type classification' }, + { code: 'ancillary-purchase', name: 'Ancillary Purchases', tableName: 'tbl_ancillary_purchases', description: 'Ancillary services and add-ons' }, + { code: 'revenue-segment', name: 'Revenue Segments', tableName: 'tbl_revenue_segments', description: 'Airline revenue tiers' }, + { code: 'jurisdiction', name: 'Jurisdictions', tableName: 'tbl_jurisdictions', description: 'Regulatory jurisdictions' }, + { code: 'booking-channel', name: 'Booking Channels', tableName: 'tbl_booking_channels', description: 'Sales and distribution channels' }, + { code: 'flight-type', name: 'Flight Types', tableName: 'tbl_flight_types', description: 'Flight route types' }, + { code: 'journey-type', name: 'Journey Types', tableName: 'tbl_journey_types', description: 'Passenger itinerary structure' }, + { code: 'fare-flexibility', name: 'Fare Flexibilities', tableName: 'tbl_fare_flexibilities', description: 'Ticket flexibility and change rules' }, + { code: 'carrier-type', name: 'Carrier Types', tableName: 'tbl_carrier_types', description: 'Airline operational carrier types' }, + { code: 'special-assistance-type', name: 'Special Assistance Types', tableName: 'tbl_special_assistance_types', description: 'SSR and special assistance categories' }, + { code: 'delay-reason', name: 'Delay Reasons', tableName: 'tbl_delay_reasons', description: 'Primary root causes of flight delays' }, + { code: 'delay-duration', name: 'Delay Durations', tableName: 'tbl_delay_durations', description: 'Standard delay duration brackets' }, + { code: 'extraordinary-circumstances', name: 'Extraordinary Circumstances', tableName: 'tbl_extraordinary_circumstances', description: 'Force majeure and non-airline events' }, + { code: 'cancellation-reason', name: 'Cancellation Reasons', tableName: 'tbl_cancellation_reasons', description: 'Flight cancellation root causes' }, + { code: 'diversion-reason', name: 'Diversion Reasons', tableName: 'tbl_diversion_reasons', description: 'Flight diversion causes' }, + { code: 'missed-connection-reason', name: 'Missed Connection Reasons', tableName: 'tbl_missed_connection_reasons', description: 'Causes for passenger missed connections' }, + { code: 'compensation-eligibility', name: 'Compensation Eligibilities', tableName: 'tbl_compensation_eligibilities', description: 'Eligibility statuses for compensation' }, + { code: 'compensation-type', name: 'Compensation Types', tableName: 'tbl_compensation_types', description: 'Offered compensation forms' }, + { code: 'refund-type', name: 'Refund Types', tableName: 'tbl_refund_types', description: 'Ticket refund types' }, + { code: 'flight-disruption-type', name: 'Flight Disruption Types', tableName: 'tbl_flight_disruption_types', description: 'Disruption classifications' }, + { code: 'airline-responsibility', name: 'Airline Responsibilities', tableName: 'tbl_airline_responsibilities', description: 'Disruption responsibility allocation' }, + { code: 'weather-condition', name: 'Weather Conditions', tableName: 'tbl_weather_conditions', description: 'Severe weather disruption categories' }, + { code: 'atc-restriction', name: 'ATC Restrictions', tableName: 'tbl_atc_restrictions', description: 'Air Traffic Control restriction types' }, + { code: 'technical-fault-category', name: 'Technical Fault Categories', tableName: 'tbl_technical_fault_categories', description: 'Aircraft maintenance & fault categories' }, + { code: 'refund-basis', name: 'Refund Bases', tableName: 'tbl_refund_bases', description: 'Calculation bases for refunds' }, + { code: 'currency', name: 'Currencies', tableName: 'tbl_currencies', description: 'Supported monetary currencies' }, + { code: 'refund-method', name: 'Refund Methods', tableName: 'tbl_refund_methods', description: 'Payment payout channels for refunds' }, + { code: 'amount-type', name: 'Amount Types', tableName: 'tbl_amount_types', description: 'Amount calculation types (percentage, fixed, formula)' }, + ]; + } + async findOneRuleCategory(id: string): Promise { const item = await this.ruleCategoryRepo.findOne({ where: { id } }); if (!item) { @@ -332,18 +376,24 @@ export class MasterDataService implements OnModuleInit { where: { code }, }); - if (!category && code && code.includes('-')) { + if (!category && code && (code.includes('-') || code.length === 36)) { category = await this.ruleCategoryRepo.findOne({ where: { id: code }, }); } - if (!category) { - throw new BadRequestException(`Rule category with code or id ${code} not found`); + const targetKey = category ? (category.tableName || category.code) : code; + let repo: Repository | null = null; + try { + repo = this.getRepositoryByCategory(targetKey); + } catch { + repo = null; + } + + if (!repo) { + return []; } - const targetKey = category.tableName || category.code; - const repo = this.getRepositoryByCategory(targetKey); const items = await repo.find({ where: { isActive: true }, }); @@ -358,6 +408,96 @@ export class MasterDataService implements OnModuleInit { })); } + // --- 3-Level Metadata Methods --- + + async findConditionGroupsByRuleCategory(ruleCategoryCodeOrId: string): Promise { + let category = await this.ruleCategoryRepo.findOne({ + where: { code: ruleCategoryCodeOrId, isActive: true }, + }); + + if (!category && ruleCategoryCodeOrId) { + category = await this.ruleCategoryRepo.findOne({ + where: { id: ruleCategoryCodeOrId, isActive: true }, + }); + } + + if (!category) { + return this.conditionGroupRepo.find({ + where: { isActive: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + }); + } + + const mappings = await this.ruleCategoryGroupRepo.find({ + where: { ruleCategoryId: category.id }, + relations: { conditionGroup: true }, + }); + + const groups = mappings + .map((m) => m.conditionGroup) + .filter((g) => g && g.isActive) + .sort((a, b) => (a.displayOrder || 0) - (b.displayOrder || 0)); + + return groups.length > 0 + ? groups + : this.conditionGroupRepo.find({ + where: { isActive: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + }); + } + + async findConditionFieldsByGroup(groupIdOrCode: string): Promise { + let group = await this.conditionGroupRepo.findOne({ + where: { code: groupIdOrCode, isActive: true }, + }); + + if (!group && groupIdOrCode) { + group = await this.conditionGroupRepo.findOne({ + where: { id: groupIdOrCode, isActive: true }, + }); + } + + if (!group) { + throw new BadRequestException(`Condition group with code/id '${groupIdOrCode}' not found`); + } + + return this.conditionFieldRepo.find({ + where: { groupId: group.id, isActive: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + }); + } + + async findLookupValuesForField(fieldIdOrCode: string): Promise { + let field = await this.conditionFieldRepo.findOne({ + where: { code: fieldIdOrCode, isActive: true }, + }); + + if (!field && fieldIdOrCode) { + field = await this.conditionFieldRepo.findOne({ + where: { id: fieldIdOrCode, isActive: true }, + }); + } + + if (!field) { + throw new BadRequestException(`Condition field with code/id '${fieldIdOrCode}' not found`); + } + + if (!field.lookupTable) { + return []; + } + + const repo = this.getRepositoryByCategory(field.lookupTable); + const items = await repo.find({ where: { isActive: true } }); + return items.map((item) => ({ + id: item.id, + code: item.value || item.code, + label: item.label || item.name || item.value, + value: item.label || item.name || item.value, + displayOrder: item.displayOrder ?? 0, + isActive: item.isActive, + })); + } + async findAllOperators(): Promise { return this.operatorRepo.find({ where: { isActive: true },