diff --git a/database/schema.sql b/database/schema.sql index 692bc65..284e9b0 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -60,125 +60,280 @@ CREATE TABLE IF NOT EXISTS tenant.tbl_tenants ( CREATE TABLE IF NOT EXISTS masters.tbl_membership_tiers ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, 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 INDEX IF NOT EXISTS idx_tbl_membership_tiers_tenant ON masters.tbl_membership_tiers("tenantId"); CREATE TABLE IF NOT EXISTS masters.tbl_customer_values ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, 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 INDEX IF NOT EXISTS idx_tbl_customer_values_tenant ON masters.tbl_customer_values("tenantId"); CREATE TABLE IF NOT EXISTS masters.tbl_regions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, 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 INDEX IF NOT EXISTS idx_tbl_regions_tenant ON masters.tbl_regions("tenantId"); CREATE TABLE IF NOT EXISTS masters.tbl_trip_purposes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, 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 INDEX IF NOT EXISTS idx_tbl_trip_purposes_tenant ON masters.tbl_trip_purposes("tenantId"); CREATE TABLE IF NOT EXISTS masters.tbl_cabin_classes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, 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 INDEX IF NOT EXISTS idx_tbl_cabin_classes_tenant ON masters.tbl_cabin_classes("tenantId"); CREATE TABLE IF NOT EXISTS masters.tbl_passenger_types ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, 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 INDEX IF NOT EXISTS idx_tbl_passenger_types_tenant ON masters.tbl_passenger_types("tenantId"); CREATE TABLE IF NOT EXISTS masters.tbl_ancillary_purchases ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, 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 INDEX IF NOT EXISTS idx_tbl_ancillary_purchases_tenant ON masters.tbl_ancillary_purchases("tenantId"); CREATE TABLE IF NOT EXISTS masters.tbl_revenue_segments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, 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 INDEX IF NOT EXISTS idx_tbl_revenue_segments_tenant ON masters.tbl_revenue_segments("tenantId"); + +CREATE TABLE IF NOT EXISTS masters.tbl_jurisdictions ( + 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_rules_categories ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, - code VARCHAR(100) NOT NULL, + code VARCHAR(100) NOT NULL UNIQUE, name VARCHAR(150) NOT NULL, + "tableName" VARCHAR, description TEXT, "displayOrder" INT DEFAULT 0, "isActive" BOOLEAN DEFAULT TRUE, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE INDEX IF NOT EXISTS idx_tbl_rules_categories_tenant ON masters.tbl_rules_categories("tenantId"); -CREATE UNIQUE INDEX IF NOT EXISTS uq_tbl_rules_categories_tenant_code - ON masters.tbl_rules_categories("tenantId", code); -CREATE TABLE IF NOT EXISTS masters.tbl_rule_categories_values ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, - "categoryId" UUID NOT NULL REFERENCES masters.tbl_rules_categories(id) ON DELETE CASCADE, - code VARCHAR(100), - value VARCHAR(255) 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_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.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.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.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 INDEX IF NOT EXISTS idx_tbl_rule_categories_values_tenant ON masters.tbl_rule_categories_values("tenantId"); -CREATE INDEX IF NOT EXISTS idx_tbl_rule_categories_values_category ON masters.tbl_rule_categories_values("categoryId"); CREATE TABLE IF NOT EXISTS masters.tbl_operators ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - "tenantId" UUID NOT NULL REFERENCES tenant.tbl_tenants(id) ON DELETE CASCADE, - code VARCHAR(50) NOT NULL, + code VARCHAR(50) NOT NULL UNIQUE, name VARCHAR(100) NOT NULL, symbol VARCHAR(20), "dataTypes" TEXT[], @@ -187,9 +342,6 @@ CREATE TABLE IF NOT EXISTS masters.tbl_operators ( "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now() ); -CREATE INDEX IF NOT EXISTS idx_tbl_operators_tenant ON masters.tbl_operators("tenantId"); -CREATE UNIQUE INDEX IF NOT EXISTS uq_tbl_operators_tenant_code - ON masters.tbl_operators("tenantId", code); -- ─── Cohorts ──────────────────────────────────────────────────────────────── @@ -252,3 +404,70 @@ CREATE TABLE IF NOT EXISTS cohort.tbl_cohort_trip_purposes ( "tripPurposeId" UUID NOT NULL REFERENCES masters.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, + data JSONB NOT NULL, + "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() +); + + + + diff --git a/database/seed-master-data.sql b/database/seed-master-data.sql new file mode 100644 index 0000000..efc9a23 --- /dev/null +++ b/database/seed-master-data.sql @@ -0,0 +1,610 @@ +-- ============================================================================= +-- AeroResolve Master Data Seed Script +-- PostgreSQL 14+ +-- ============================================================================= + +-- 1. Action Categories +INSERT INTO masters.tbl_action_categories (code, name, "displayOrder", "isActive") +SELECT code, name, displayOrder, true FROM (VALUES + ('REFUNDS', 'Refunds', 1), + ('CASH_COMPENSATION', 'Cash Compensation', 2), + ('TRAVEL_CREDITS', 'Travel Credits', 3), + ('LOYALTY_BENEFITS', 'Loyalty Benefits', 4), + ('ACCOMMODATION', 'Accommodation', 5), + ('MEALS', 'Meals', 6), + ('TRANSPORTATION', 'Transportation', 7), + ('REBOOKING_TRAVEL', 'Rebooking & Travel', 8), + ('UPGRADES', 'Upgrades', 9), + ('ANCILLARY_RECOVERY', 'Ancillary Recovery', 10), + ('COMMUNICATION', 'Communication', 11), + ('WORKFLOW', 'Workflow', 12), + ('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); + +-- 2. Action Types +INSERT INTO masters.tbl_action_types (code, "categoryId", name, "displayOrder", "isActive") +SELECT v.code, c.id, v.name, v.display_order, true +FROM (VALUES + -- Refunds + ('FULL_TICKET_REFUND', 'REFUNDS', 'Full Ticket Refund', 1), + ('PARTIAL_TICKET_REFUND', 'REFUNDS', 'Partial Ticket Refund', 2), + ('TAX_REFUND', 'REFUNDS', 'Tax Refund', 3), + ('ANCILLARY_REFUND', 'REFUNDS', 'Ancillary Refund', 4), + ('BAGGAGE_FEE_REFUND', 'REFUNDS', 'Baggage Fee Refund', 5), + ('CABIN_DOWNGRADE_REFUND', 'REFUNDS', 'Cabin Downgrade Refund', 6), + + -- Cash Compensation + ('REGULATORY_COMPENSATION', 'CASH_COMPENSATION', 'Regulatory Compensation', 1), + ('AIRLINE_GOODWILL_CASH', 'CASH_COMPENSATION', 'Airline Goodwill Cash', 2), + ('EX_GRATIA_COMPENSATION', 'CASH_COMPENSATION', 'Ex-Gratia Compensation', 3), + + -- Travel Credits + ('TRAVEL_VOUCHER', 'TRAVEL_CREDITS', 'Travel Voucher', 1), + ('FUTURE_TRAVEL_CREDIT', 'TRAVEL_CREDITS', 'Future Travel Credit', 2), + ('PROMO_CODE', 'TRAVEL_CREDITS', 'Promo Code', 3), + ('DISCOUNT_COUPON', 'TRAVEL_CREDITS', 'Discount Coupon', 4), + + -- Loyalty Benefits + ('AWARD_MILES', 'LOYALTY_BENEFITS', 'Award Miles', 1), + ('BONUS_MILES', 'LOYALTY_BENEFITS', 'Bonus Miles', 2), + ('TIER_POINTS', 'LOYALTY_BENEFITS', 'Tier Points', 3), + ('TIER_UPGRADE', 'LOYALTY_BENEFITS', 'Tier Upgrade', 4), + + -- Accommodation + ('HOTEL_ACCOMMODATION', 'ACCOMMODATION', 'Hotel Accommodation', 1), + ('AIRPORT_HOTEL', 'ACCOMMODATION', 'Airport Hotel', 2), + + -- Meals + ('MEAL_VOUCHER', 'MEALS', 'Meal Voucher', 1), + ('RESTAURANT_VOUCHER', 'MEALS', 'Restaurant Voucher', 2), + ('REFRESHMENT_COUPON', 'MEALS', 'Refreshment Coupon', 3), + + -- Transportation + ('TAXI', 'TRANSPORTATION', 'Taxi', 1), + ('AIRPORT_TRANSFER', 'TRANSPORTATION', 'Airport Transfer', 2), + ('BUS_TRANSFER', 'TRANSPORTATION', 'Bus Transfer', 3), + ('TRAIN_TICKET', 'TRANSPORTATION', 'Train Ticket', 4), + ('CHAUFFEUR_SERVICE', 'TRANSPORTATION', 'Chauffeur Service', 5), + + -- Rebooking & Travel + ('AUTO_REBOOK', 'REBOOKING_TRAVEL', 'Auto Rebook', 1), + ('PRIORITY_REBOOKING', 'REBOOKING_TRAVEL', 'Priority Rebooking', 2), + ('OPEN_TICKET', 'REBOOKING_TRAVEL', 'Open Ticket', 3), + ('ALTERNATE_AIRLINE', 'REBOOKING_TRAVEL', 'Alternate Airline', 4), + + -- Upgrades + ('CABIN_UPGRADE', 'UPGRADES', 'Cabin Upgrade', 1), + ('SEAT_UPGRADE', 'UPGRADES', 'Seat Upgrade', 2), + ('LOUNGE_ACCESS', 'UPGRADES', 'Lounge Access', 3), + ('FAST_TRACK_SECURITY', 'UPGRADES', 'Fast Track Security', 4), + ('PRIORITY_BOARDING', 'UPGRADES', 'Priority Boarding', 5), + + -- Ancillary Recovery + ('COMPLIMENTARY_WIFI', 'ANCILLARY_RECOVERY', 'Complimentary Wi-Fi', 1), + ('FREE_BAGGAGE', 'ANCILLARY_RECOVERY', 'Free Baggage', 2), + ('COMPLIMENTARY_MEAL', 'ANCILLARY_RECOVERY', 'Complimentary Meal', 3), + ('SEAT_SELECTION', 'ANCILLARY_RECOVERY', 'Seat Selection', 4), + ('CARBON_OFFSET_CREDIT', 'ANCILLARY_RECOVERY', 'Carbon Offset Credit', 5), + + -- Communication + ('PASSENGER_NOTIFICATION', 'COMMUNICATION', 'Passenger Notification', 1), + ('AGENT_NOTIFICATION', 'COMMUNICATION', 'Agent Notification', 2), + ('MANAGEMENT_ALERT', 'COMMUNICATION', 'Management Alert', 3), + + -- Workflow + ('AUTO_APPROVE', 'WORKFLOW', 'Auto Approve', 1), + ('MANUAL_REVIEW', 'WORKFLOW', 'Manual Review', 2), + ('ESCALATE', 'WORKFLOW', 'Escalate', 3), + ('CREATE_CASE', 'WORKFLOW', 'Create Case', 4), + ('HOLD_FOR_INVESTIGATION', 'WORKFLOW', 'Hold for Investigation', 5), + + -- Finance + ('TRIGGER_PAYMENT', 'FINANCE', 'Trigger Payment', 1), + ('GENERATE_CREDIT_NOTE', 'FINANCE', 'Generate Credit Note', 2), + ('GENERATE_INVOICE', 'FINANCE', 'Generate Invoice', 3), + ('WRITE_OFF', 'FINANCE', 'Write-off', 4), + + -- System Integration + ('UPDATE_CRM', 'SYSTEM_INTEGRATION', 'Update CRM', 1), + ('UPDATE_LOYALTY', 'SYSTEM_INTEGRATION', 'Update Loyalty', 2), + ('UPDATE_PSS', 'SYSTEM_INTEGRATION', 'Update PSS', 3), + ('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); + +-- 3. Membership Tiers +INSERT INTO masters.tbl_membership_tiers (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Platinum', 'platinum'), + ('Gold', 'gold'), + ('Silver', 'silver'), + ('Bronze', 'bronze'), + ('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); + +-- 4. Customer Values +INSERT INTO masters.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); + +-- 5. Regions +INSERT INTO masters.tbl_regions (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Global', 'global'), + ('Americas', 'americas'), + ('Europe', 'europe'), + ('Middle East', 'middle-east'), + ('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); + +-- 6. Trip Purposes +INSERT INTO masters.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); + +-- 7. Cabin Classes +INSERT INTO masters.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); + +-- 8. Passenger Types +INSERT INTO masters.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); + +-- 9. Ancillary Purchases +INSERT INTO masters.tbl_ancillary_purchases (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Preferred Seat', 'preferred-seat'), + ('Extra Legroom', 'extra-legroom'), + ('Wi-Fi', 'wi-fi'), + ('Lounge Access', 'lounge-access'), + ('Priority Boarding', 'priority-boarding'), + ('Fast Track', 'fast-track'), + ('Paid Meal', 'paid-meal'), + ('Special Meal', 'special-meal'), + ('Extra Baggage', 'extra-baggage'), + ('Upgrade Purchase', 'upgrade-purchase'), + ('Airport Transfer', 'airport-transfer'), + ('Chauffeur Service', 'chauffeur-service'), + ('Sports Equipment', 'sports-equipment'), + ('Musical Instrument', 'musical-instrument'), + ('In-flight Entertainment', 'in-flight-entertainment'), + ('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); + +-- 10. Revenue Segments +INSERT INTO masters.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); + +-- 11. Jurisdictions +INSERT INTO masters.tbl_jurisdictions (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('United Arab Emirates', 'uae'), + ('European Union', 'eu'), + ('United States', 'us'), + ('United Kingdom', 'uk'), + ('India', 'india'), + ('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); + +-- 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), + ('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) +) 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); + +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'), + ('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') +) AS v(code, "tableName") +WHERE c.code = v.code AND (c."tableName" IS NULL OR c."tableName" != v."tableName"); + +-- 13. Booking Channels +INSERT INTO masters.tbl_booking_channels (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Airline Website', 'airline-website'), + ('Airline Mobile App', 'airline-mobile-app'), + ('Airport Ticket Counter', 'airport-ticket-counter'), + ('Call Center', 'call-center'), + ('Corporate Booking Tool', 'corporate-booking-tool'), + ('Global Distribution System', 'global-distribution-system'), + ('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); + +-- 14. Flight Types +INSERT INTO masters.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); + +-- 15. Journey Types +INSERT INTO masters.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); + +-- 16. Fare Flexibilities +INSERT INTO masters.tbl_fare_flexibilities (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Non Refundable', 'non-refundable'), + ('Partially Refundable', 'partially-refundable'), + ('Refundable', 'refundable'), + ('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); + +-- 17. Carrier Types +INSERT INTO masters.tbl_carrier_types (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Operating Carrier', 'operating-carrier'), + ('Marketing Carrier', 'marketing-carrier'), + ('Partner Carrier', 'partner-carrier'), + ('Regional Carrier', 'regional-carrier'), + ('Low Cost Carrier', 'low-cost-carrier'), + ('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); + +-- 18. Special Assistance Types +INSERT INTO masters.tbl_special_assistance_types (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Wheelchair Assistance', 'wheelchair-assistance'), + ('Wheelchair Ramp', 'wheelchair-ramp'), + ('Wheelchair Steps', 'wheelchair-steps'), + ('Wheelchair Cabin', 'wheelchair-cabin'), + ('Blind Passenger', 'blind-passenger'), + ('Deaf Passenger', 'deaf-passenger'), + ('Medical Assistance', 'medical-assistance'), + ('Oxygen Required', 'oxygen-required'), + ('Stretcher', 'stretcher'), + ('Unaccompanied Minor', 'unaccompanied-minor'), + ('Service Animal', 'service-animal'), + ('Pregnant Passenger', 'pregnant-passenger'), + ('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); + +-- 19. Delay Reasons +INSERT INTO masters.tbl_delay_reasons (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Air Traffic Control Restriction', 'air-traffic-control-restriction'), + ('Aircraft Rotation', 'aircraft-rotation'), + ('Airport Congestion', 'airport-congestion'), + ('Crew Availability', 'crew-availability'), + ('Customs Delay', 'customs-delay'), + ('Fueling Delay', 'fueling-delay'), + ('Late Arrival of Aircraft', 'late-arrival-of-aircraft'), + ('Operational Decision', 'operational-decision'), + ('Passenger Handling', 'passenger-handling'), + ('Runway Closure', 'runway-closure'), + ('Security', 'security'), + ('Severe Weather', 'severe-weather'), + ('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); + +-- 20. Delay Durations +INSERT INTO masters.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'), + ('2-3 Hours', '2-3-hours'), + ('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); + +-- 21. Extraordinary Circumstances +INSERT INTO masters.tbl_extraordinary_circumstances (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Air Traffic Management Decision', 'air-traffic-management-decision'), + ('Airport Closure', 'airport-closure'), + ('Bird Strike', 'bird-strike'), + ('Civil Unrest', 'civil-unrest'), + ('Medical Emergency', 'medical-emergency'), + ('Political Instability', 'political-instability'), + ('Security Threat', 'security-threat'), + ('Severe Weather', 'severe-weather'), + ('Strike (External)', 'strike-external-'), + ('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); + +-- 22. Cancellation Reasons +INSERT INTO masters.tbl_cancellation_reasons (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Air Traffic Control Restriction', 'air-traffic-control-restriction'), + ('Airport Closure', 'airport-closure'), + ('Commercial Decision', 'commercial-decision'), + ('Crew Availability', 'crew-availability'), + ('Operational Decision', 'operational-decision'), + ('Overbooking', 'overbooking'), + ('Security', 'security'), + ('Severe Weather', 'severe-weather'), + ('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); + +-- 23. Diversion Reasons +INSERT INTO masters.tbl_diversion_reasons (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Airport Closure', 'airport-closure'), + ('Destination Weather', 'destination-weather'), + ('Fuel Emergency', 'fuel-emergency'), + ('Medical Emergency', 'medical-emergency'), + ('Runway Obstruction', 'runway-obstruction'), + ('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); + +-- 24. Missed Connection Reasons +INSERT INTO masters.tbl_missed_connection_reasons (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Customs Delay', 'customs-delay'), + ('Flight Delay', 'flight-delay'), + ('Immigration Delay', 'immigration-delay'), + ('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); + +-- 25. Compensation Eligibilities +INSERT INTO masters.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); + +-- 26. Compensation Types +INSERT INTO masters.tbl_compensation_types (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Cash', 'cash'), + ('Cheque', 'cheque'), + ('Flight Voucher', 'flight-voucher'), + ('Loyalty Miles', 'loyalty-miles'), + ('Meal Voucher', 'meal-voucher'), + ('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); + +-- 27. Refund Types +INSERT INTO masters.tbl_refund_types (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Full Refund', 'full-refund'), + ('Partial Refund', 'partial-refund'), + ('Future Travel Credit', 'future-travel-credit'), + ('Travel Voucher', 'travel-voucher'), + ('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); + +-- 28. Flight Disruption Types +INSERT INTO masters.tbl_flight_disruption_types (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Cancellation', 'cancellation'), + ('Delay', 'delay'), + ('Denied Boarding', 'denied-boarding'), + ('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); + +-- 29. Airline Responsibilities +INSERT INTO masters.tbl_airline_responsibilities (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Airline Responsible', 'airline-responsible'), + ('Airport Responsible', 'airport-responsible'), + ('ATC Responsible', 'atc-responsible'), + ('Passenger Responsible', 'passenger-responsible'), + ('Shared Responsibility', 'shared-responsibility'), + ('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); + +-- 30. Weather Conditions +INSERT INTO masters.tbl_weather_conditions (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Fog', 'fog'), + ('Heavy Rain', 'heavy-rain'), + ('Hurricane', 'hurricane'), + ('Ice', 'ice'), + ('Lightning', 'lightning'), + ('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); + +-- 31. ATC Restrictions +INSERT INTO masters.tbl_atc_restrictions (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Airspace Closure', 'airspace-closure'), + ('Flow Control', 'flow-control'), + ('Ground Stop', 'ground-stop'), + ('Slot Restriction', 'slot-restriction'), + ('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); + +-- 32. Technical Fault Categories +INSERT INTO masters.tbl_technical_fault_categories (label, value, "isActive") +SELECT label, value, true FROM (VALUES + ('Aircraft Damage', 'aircraft-damage'), + ('Avionics', 'avionics'), + ('Cabin Systems', 'cabin-systems'), + ('Engine', 'engine'), + ('Hydraulic System', 'hydraulic-system'), + ('Landing Gear', 'landing-gear'), + ('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); + +-- 33. Operators +INSERT INTO masters.tbl_operators (code, name, symbol, "displayOrder", "isActive") +SELECT code, name, symbol, displayOrder, true FROM (VALUES + ('EQ', 'Equals', '=', 1), + ('NE', 'Not Equals', '!=', 2), + ('GT', 'Greater Than', '>', 3), + ('GTE', 'Greater Than or Equal', '>=', 4), + ('LT', 'Less Than', '<', 5), + ('LTE', 'Less Than or Equal', '<=', 6), + ('BETWEEN', 'Between', 'BETWEEN', 7), + ('CONTAINS', 'Contains', 'CONTAINS', 8), + ('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); + +-- 34. Refund Bases +INSERT INTO masters.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); + +-- 35. Currencies +INSERT INTO masters.tbl_currencies (label, value, symbol, "isActive") +SELECT label, value, symbol, true FROM (VALUES + ('United States Dollar', 'USD', '$'), + ('Euro', 'EUR', '€'), + ('British Pound', 'GBP', '£'), + ('United Arab Emirates Dirham', 'AED', 'AED'), + ('Saudi Riyal', 'SAR', 'SAR'), + ('Indian Rupee', 'INR', '₹'), + ('Japanese Yen', 'JPY', '¥'), + ('Canadian Dollar', 'CAD', '$'), + ('Australian Dollar', 'AUD', '$'), + ('Swiss Franc', 'CHF', 'CHF'), + ('Singapore Dollar', 'SGD', '$'), + ('Qatari Riyal', 'QAR', 'QAR'), + ('Kuwaiti Dinar', 'KWD', 'KWD'), + ('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); + +-- 36. Refund Methods +INSERT INTO masters.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); + + + diff --git a/scripts/seed-master-data.ts b/scripts/seed-master-data.ts index aefbc85..23dc493 100644 --- a/scripts/seed-master-data.ts +++ b/scripts/seed-master-data.ts @@ -16,10 +16,8 @@ async function bootstrap() { const tenants = await tenantService.seedDemoTenants(); logger.log(`Seeded ${tenants.length} demo tenant(s)`); - for (const tenant of tenants) { - await masterDataService.seedData(tenant.id); - logger.log(`Master data ready for tenant: ${tenant.slug}`); - } + await masterDataService.seedData(); + logger.log('Master data ready (common across all tenants).'); logger.log('Seeding complete. Exiting...'); diff --git a/src/database/database.module.ts b/src/database/database.module.ts index 50ecc17..b0bbdd5 100644 --- a/src/database/database.module.ts +++ b/src/database/database.module.ts @@ -28,21 +28,21 @@ import { ConfigModule, ConfigService } from '@nestjs/config'; // Initialize without syncing first const dataSource = new DataSource({ ...options, synchronize: false }); await dataSource.initialize(); - + // Create schemas if they don't exist 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 "cohort";`); await dataSource.query(`CREATE SCHEMA IF NOT EXISTS "policy_engine";`); - + // Run synchronization manually if it was enabled if (options.synchronize) { await dataSource.synchronize(); } - + return dataSource; }, }), ], }) -export class DatabaseModule {} +export class DatabaseModule { } diff --git a/src/modules/master-data/dto/action-submission.dto.ts b/src/modules/master-data/dto/action-submission.dto.ts new file mode 100644 index 0000000..26cc7f3 --- /dev/null +++ b/src/modules/master-data/dto/action-submission.dto.ts @@ -0,0 +1,19 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString, IsNotEmpty, IsObject } from 'class-validator'; + +export class ActionSubmissionDto { + @ApiProperty({ description: 'Category ID', example: 'cat_comp' }) + @IsString() + @IsNotEmpty() + category_id!: string; + + @ApiProperty({ description: 'Action Type ID', example: 'at_cash_comp' }) + @IsString() + @IsNotEmpty() + action_type_id!: string; + + @ApiProperty({ description: 'Form submitted dynamic data dictionary' }) + @IsObject() + @IsNotEmpty() + data!: Record; +} diff --git a/src/modules/master-data/dto/create-action-category.dto.ts b/src/modules/master-data/dto/create-action-category.dto.ts new file mode 100644 index 0000000..a6db118 --- /dev/null +++ b/src/modules/master-data/dto/create-action-category.dto.ts @@ -0,0 +1,29 @@ +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { IsBoolean, IsNotEmpty, IsOptional, IsString, IsNumber } from 'class-validator'; + +export class CreateActionCategoryDto { + @ApiPropertyOptional({ example: 'passenger-compensation', description: 'Unique action category code' }) + @IsString() + @IsNotEmpty() + code: string; + + @ApiPropertyOptional({ example: 'Passenger Compensation', description: 'Display name for the action category' }) + @IsString() + @IsNotEmpty() + name: string; + + @ApiPropertyOptional({ example: 'Actions related to passenger compensation', description: 'Optional description' }) + @IsString() + @IsOptional() + description?: string; + + @ApiPropertyOptional({ example: 1, description: 'Order used for display sorting' }) + @IsNumber() + @IsOptional() + displayOrder?: number; + + @ApiPropertyOptional({ example: true, description: 'Whether the record is active' }) + @IsBoolean() + @IsOptional() + isActive?: boolean; +} diff --git a/src/modules/master-data/dto/create-rule-category-value.dto.ts b/src/modules/master-data/dto/create-action-type.dto.ts similarity index 55% rename from src/modules/master-data/dto/create-rule-category-value.dto.ts rename to src/modules/master-data/dto/create-action-type.dto.ts index 2f39399..6587d7e 100644 --- a/src/modules/master-data/dto/create-rule-category-value.dto.ts +++ b/src/modules/master-data/dto/create-action-type.dto.ts @@ -1,21 +1,26 @@ import { ApiPropertyOptional } from '@nestjs/swagger'; import { IsBoolean, IsNotEmpty, IsOptional, IsString, IsUUID, IsNumber } from 'class-validator'; -export class CreateRuleCategoryValueDto { - @ApiPropertyOptional({ example: '00000000-0000-0000-0000-000000000000', description: 'Parent rule category id' }) +export class CreateActionTypeDto { + @ApiPropertyOptional({ example: '00000000-0000-0000-0000-000000000000', description: 'Parent action category id' }) @IsUUID() @IsNotEmpty() categoryId: string; - @ApiPropertyOptional({ example: 'economy', description: 'Optional code for the value' }) - @IsString() - @IsOptional() - code?: string; - - @ApiPropertyOptional({ example: 'Economy', description: 'Display value' }) + @ApiPropertyOptional({ example: 'voucher-refund', description: 'Unique action type code' }) @IsString() @IsNotEmpty() - value: string; + code: string; + + @ApiPropertyOptional({ example: 'Voucher Refund', description: 'Display name for the action type' }) + @IsString() + @IsNotEmpty() + name: string; + + @ApiPropertyOptional({ example: 'Issue a compensation voucher refund', description: 'Optional description' }) + @IsString() + @IsOptional() + description?: string; @ApiPropertyOptional({ example: 1, description: 'Order used for display sorting' }) @IsNumber() diff --git a/src/modules/master-data/dto/create-field-definition.dto.ts b/src/modules/master-data/dto/create-field-definition.dto.ts new file mode 100644 index 0000000..a308ede --- /dev/null +++ b/src/modules/master-data/dto/create-field-definition.dto.ts @@ -0,0 +1,86 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { + IsString, + IsNotEmpty, + IsOptional, + IsBoolean, + IsInt, + IsObject, +} from 'class-validator'; + +export class CreateFieldDefinitionDto { + @ApiProperty({ description: 'Action type ID', example: 'at_cash_comp' }) + @IsString() + @IsNotEmpty() + actionTypeId!: string; + + @ApiProperty({ description: 'Unique field code within action type', example: 'payout_amount' }) + @IsString() + @IsNotEmpty() + fieldCode!: string; + + @ApiProperty({ description: 'Human readable field label', example: 'Payout Amount' }) + @IsString() + @IsNotEmpty() + fieldName!: string; + + @ApiProperty({ description: 'Control field type (textbox, currency, dropdown, etc.)', example: 'currency' }) + @IsString() + @IsNotEmpty() + fieldType!: string; + + @ApiPropertyOptional({ description: 'Master data code for lookup options (e.g. CURRENCIES)', example: 'CURRENCIES' }) + @IsString() + @IsOptional() + lookupSource?: string; + + @ApiPropertyOptional({ description: 'Required flag', example: true, default: false }) + @IsBoolean() + @IsOptional() + isRequired?: boolean; + + @ApiPropertyOptional({ description: 'Default value string', example: '600' }) + @IsString() + @IsOptional() + defaultValue?: string; + + @ApiPropertyOptional({ description: 'Placeholder text', example: 'Enter amount' }) + @IsString() + @IsOptional() + placeholder?: string; + + @ApiPropertyOptional({ description: 'Help text / instructions', example: 'Allowed compensation amount' }) + @IsString() + @IsOptional() + helpText?: string; + + @ApiPropertyOptional({ description: 'Grid column width (full, half, third, two_thirds)', example: 'half', default: 'full' }) + @IsString() + @IsOptional() + width?: string; + + @ApiPropertyOptional({ description: 'Form section header title', example: 'Financial Details' }) + @IsString() + @IsOptional() + section?: string; + + @ApiPropertyOptional({ description: 'Sorting display order', example: 1, default: 0 }) + @IsInt() + @IsOptional() + displayOrder?: number; + + @ApiPropertyOptional({ description: 'Active status flag', example: true, default: true }) + @IsBoolean() + @IsOptional() + isActive?: boolean; + + @ApiPropertyOptional({ description: 'Validation rules JSON ({ min, max, regex })' }) + @IsObject() + @IsOptional() + validationJson?: Record; + + @ApiPropertyOptional({ description: 'Visibility condition JSON ({ field, operator, value })' }) + @IsObject() + @IsOptional() + visibilityConditionJson?: Record; +} diff --git a/src/modules/master-data/dto/update-action-category.dto.ts b/src/modules/master-data/dto/update-action-category.dto.ts new file mode 100644 index 0000000..cc356bb --- /dev/null +++ b/src/modules/master-data/dto/update-action-category.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/swagger'; +import { CreateActionCategoryDto } from './create-action-category.dto'; + +export class UpdateActionCategoryDto extends PartialType(CreateActionCategoryDto) {} diff --git a/src/modules/master-data/dto/update-action-type.dto.ts b/src/modules/master-data/dto/update-action-type.dto.ts new file mode 100644 index 0000000..50bc0a3 --- /dev/null +++ b/src/modules/master-data/dto/update-action-type.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/swagger'; +import { CreateActionTypeDto } from './create-action-type.dto'; + +export class UpdateActionTypeDto extends PartialType(CreateActionTypeDto) {} diff --git a/src/modules/master-data/dto/update-field-definition.dto.ts b/src/modules/master-data/dto/update-field-definition.dto.ts new file mode 100644 index 0000000..027a659 --- /dev/null +++ b/src/modules/master-data/dto/update-field-definition.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/swagger'; +import { CreateFieldDefinitionDto } from './create-field-definition.dto'; + +export class UpdateFieldDefinitionDto extends PartialType(CreateFieldDefinitionDto) {} diff --git a/src/modules/master-data/dto/update-rule-category-value.dto.ts b/src/modules/master-data/dto/update-rule-category-value.dto.ts deleted file mode 100644 index bb35bc2..0000000 --- a/src/modules/master-data/dto/update-rule-category-value.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PartialType } from '@nestjs/swagger'; -import { CreateRuleCategoryValueDto } from './create-rule-category-value.dto'; - -export class UpdateRuleCategoryValueDto extends PartialType(CreateRuleCategoryValueDto) {} diff --git a/src/modules/master-data/entities/action-category.entity.ts b/src/modules/master-data/entities/action-category.entity.ts new file mode 100644 index 0000000..d29de6d --- /dev/null +++ b/src/modules/master-data/entities/action-category.entity.ts @@ -0,0 +1,41 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + OneToMany, + Index, +} from 'typeorm'; +import { ActionType } from './action-type.entity'; + +@Entity({ name: 'tbl_action_categories', schema: 'masters' }) +@Index('UQ_action_category_code', ['code'], { unique: true }) +export class ActionCategory { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + code!: string; + + @Column() + name!: string; + + @Column({ type: 'text', nullable: true }) + description?: string; + + @Column({ default: 0 }) + displayOrder!: number; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; + + @OneToMany(() => ActionType, (actionType) => actionType.category) + actionTypes?: ActionType[]; +} diff --git a/src/modules/master-data/entities/action-submission.entity.ts b/src/modules/master-data/entities/action-submission.entity.ts new file mode 100644 index 0000000..0839f83 --- /dev/null +++ b/src/modules/master-data/entities/action-submission.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_action_submissions', schema: 'masters' }) +export class ActionSubmission { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column({ type: 'uuid' }) + categoryId!: string; + + @Column({ type: 'uuid' }) + actionTypeId!: string; + + @Column({ type: 'jsonb' }) + data!: Record; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/action-type.entity.ts b/src/modules/master-data/entities/action-type.entity.ts new file mode 100644 index 0000000..7843bc6 --- /dev/null +++ b/src/modules/master-data/entities/action-type.entity.ts @@ -0,0 +1,52 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + JoinColumn, + OneToMany, +} from 'typeorm'; +import { ActionCategory } from './action-category.entity'; +import { FieldDefinition } from './field-definition.entity'; + +@Entity({ name: 'tbl_action_types', schema: 'masters' }) +export class ActionType { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column({ type: 'uuid' }) + categoryId!: string; + + @ManyToOne(() => ActionCategory, (category) => category.actionTypes, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'categoryId' }) + category!: ActionCategory; + + @Column() + code!: string; + + @Column() + name!: string; + + @Column({ type: 'text', nullable: true }) + description?: string; + + @Column({ type: 'varchar', nullable: true }) + icon?: string; + + @Column({ default: 0 }) + displayOrder!: number; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; + + @OneToMany(() => FieldDefinition, (field) => field.actionType) + fieldDefinitions?: FieldDefinition[]; +} diff --git a/src/modules/master-data/entities/airline-responsibility.entity.ts b/src/modules/master-data/entities/airline-responsibility.entity.ts new file mode 100644 index 0000000..77d4a43 --- /dev/null +++ b/src/modules/master-data/entities/airline-responsibility.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_airline_responsibilities', schema: 'masters' }) +export class AirlineResponsibility { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/ancillary-purchase.entity.ts b/src/modules/master-data/entities/ancillary-purchase.entity.ts index d732061..bd04a1c 100644 --- a/src/modules/master-data/entities/ancillary-purchase.entity.ts +++ b/src/modules/master-data/entities/ancillary-purchase.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_ancillary_purchases', schema: 'masters' }) -export class AncillaryPurchase extends TenantOwnedEntity { +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 new file mode 100644 index 0000000..85a888f --- /dev/null +++ b/src/modules/master-data/entities/atc-restriction.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_atc_restrictions', schema: 'masters' }) +export class AtcRestriction { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/booking-channel.entity.ts b/src/modules/master-data/entities/booking-channel.entity.ts new file mode 100644 index 0000000..124b9a6 --- /dev/null +++ b/src/modules/master-data/entities/booking-channel.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_booking_channels', schema: 'masters' }) +export class BookingChannel { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/cabin-class.entity.ts b/src/modules/master-data/entities/cabin-class.entity.ts index 80e0f38..3fa2a9a 100644 --- a/src/modules/master-data/entities/cabin-class.entity.ts +++ b/src/modules/master-data/entities/cabin-class.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_cabin_classes', schema: 'masters' }) -export class CabinClass extends TenantOwnedEntity { +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 new file mode 100644 index 0000000..8dc7306 --- /dev/null +++ b/src/modules/master-data/entities/cancellation-reason.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_cancellation_reasons', schema: 'masters' }) +export class CancellationReason { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/carrier-type.entity.ts b/src/modules/master-data/entities/carrier-type.entity.ts new file mode 100644 index 0000000..387965e --- /dev/null +++ b/src/modules/master-data/entities/carrier-type.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_carrier_types', schema: 'masters' }) +export class CarrierType { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/compensation-eligibility.entity.ts b/src/modules/master-data/entities/compensation-eligibility.entity.ts new file mode 100644 index 0000000..8eed022 --- /dev/null +++ b/src/modules/master-data/entities/compensation-eligibility.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_compensation_eligibilities', schema: 'masters' }) +export class CompensationEligibility { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/compensation-type.entity.ts b/src/modules/master-data/entities/compensation-type.entity.ts new file mode 100644 index 0000000..c682478 --- /dev/null +++ b/src/modules/master-data/entities/compensation-type.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_compensation_types', schema: 'masters' }) +export class CompensationType { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/currency.entity.ts b/src/modules/master-data/entities/currency.entity.ts new file mode 100644 index 0000000..843a2ca --- /dev/null +++ b/src/modules/master-data/entities/currency.entity.ts @@ -0,0 +1,31 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_currencies', schema: 'masters' }) +export class Currency { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ nullable: true }) + symbol?: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/customer-value.entity.ts b/src/modules/master-data/entities/customer-value.entity.ts index fbf0572..e1b1c3d 100644 --- a/src/modules/master-data/entities/customer-value.entity.ts +++ b/src/modules/master-data/entities/customer-value.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_customer_values', schema: 'masters' }) -export class CustomerValue extends TenantOwnedEntity { +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 new file mode 100644 index 0000000..fac6874 --- /dev/null +++ b/src/modules/master-data/entities/delay-duration.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_delay_durations', schema: 'masters' }) +export class DelayDuration { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/delay-reason.entity.ts b/src/modules/master-data/entities/delay-reason.entity.ts new file mode 100644 index 0000000..e9e37e2 --- /dev/null +++ b/src/modules/master-data/entities/delay-reason.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_delay_reasons', schema: 'masters' }) +export class DelayReason { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/diversion-reason.entity.ts b/src/modules/master-data/entities/diversion-reason.entity.ts new file mode 100644 index 0000000..48a6084 --- /dev/null +++ b/src/modules/master-data/entities/diversion-reason.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_diversion_reasons', schema: 'masters' }) +export class DiversionReason { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/extraordinary-circumstance.entity.ts b/src/modules/master-data/entities/extraordinary-circumstance.entity.ts new file mode 100644 index 0000000..92b2cc3 --- /dev/null +++ b/src/modules/master-data/entities/extraordinary-circumstance.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_extraordinary_circumstances', schema: 'masters' }) +export class ExtraordinaryCircumstance { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/fare-flexibility.entity.ts b/src/modules/master-data/entities/fare-flexibility.entity.ts new file mode 100644 index 0000000..d608447 --- /dev/null +++ b/src/modules/master-data/entities/fare-flexibility.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_fare_flexibilities', schema: 'masters' }) +export class FareFlexibility { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/field-definition.entity.ts b/src/modules/master-data/entities/field-definition.entity.ts new file mode 100644 index 0000000..40eabc6 --- /dev/null +++ b/src/modules/master-data/entities/field-definition.entity.ts @@ -0,0 +1,73 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + JoinColumn, + Index, +} from 'typeorm'; +import { ActionType } from './action-type.entity'; + +@Entity({ name: 'tbl_field_definitions', schema: 'masters' }) +@Index('UQ_field_definition_action_type_code', ['actionTypeId', 'fieldCode'], { unique: true }) +export class FieldDefinition { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column({ type: 'uuid' }) + actionTypeId!: string; + + @ManyToOne(() => ActionType, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'actionTypeId' }) + actionType?: ActionType; + + @Column() + fieldCode!: string; + + @Column() + fieldName!: string; + + @Column() + fieldType!: string; + + @Column({ type: 'varchar', nullable: true }) + lookupSource?: string; + + @Column({ default: false }) + isRequired!: boolean; + + @Column({ type: 'text', nullable: true }) + defaultValue?: string; + + @Column({ type: 'varchar', nullable: true }) + placeholder?: string; + + @Column({ type: 'text', nullable: true }) + helpText?: string; + + @Column({ default: 'full' }) + width!: string; + + @Column({ type: 'varchar', nullable: true }) + section?: string; + + @Column({ default: 0 }) + displayOrder!: number; + + @Column({ default: true }) + isActive!: boolean; + + @Column({ type: 'jsonb', nullable: true }) + validationJson?: Record; + + @Column({ type: 'jsonb', nullable: true }) + visibilityConditionJson?: Record; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/flight-disruption-type.entity.ts b/src/modules/master-data/entities/flight-disruption-type.entity.ts new file mode 100644 index 0000000..d7224a7 --- /dev/null +++ b/src/modules/master-data/entities/flight-disruption-type.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_flight_disruption_types', schema: 'masters' }) +export class FlightDisruptionType { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/flight-type.entity.ts b/src/modules/master-data/entities/flight-type.entity.ts new file mode 100644 index 0000000..441a0e2 --- /dev/null +++ b/src/modules/master-data/entities/flight-type.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_flight_types', schema: 'masters' }) +export class FlightType { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/journey-type.entity.ts b/src/modules/master-data/entities/journey-type.entity.ts new file mode 100644 index 0000000..41103eb --- /dev/null +++ b/src/modules/master-data/entities/journey-type.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_journey_types', schema: 'masters' }) +export class JourneyType { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/jurisdiction.entity.ts b/src/modules/master-data/entities/jurisdiction.entity.ts index ce7da49..5b0317a 100644 --- a/src/modules/master-data/entities/jurisdiction.entity.ts +++ b/src/modules/master-data/entities/jurisdiction.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_jurisdictions', schema: 'masters' }) -export class Jurisdiction extends TenantOwnedEntity { +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 bb73d36..94fa8d4 100644 --- a/src/modules/master-data/entities/membership-tier.entity.ts +++ b/src/modules/master-data/entities/membership-tier.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_membership_tiers', schema: 'masters' }) -export class MembershipTier extends TenantOwnedEntity { +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 new file mode 100644 index 0000000..a73726a --- /dev/null +++ b/src/modules/master-data/entities/missed-connection-reason.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_missed_connection_reasons', schema: 'masters' }) +export class MissedConnectionReason { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/operator.entity.ts b/src/modules/master-data/entities/operator.entity.ts index ebca134..87bad4f 100644 --- a/src/modules/master-data/entities/operator.entity.ts +++ b/src/modules/master-data/entities/operator.entity.ts @@ -6,11 +6,10 @@ import { Index, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_operators', schema: 'masters' }) -@Index('UQ_operator_tenant_code', ['tenantId', 'code'], { unique: true }) -export class Operator extends TenantOwnedEntity { +@Index('UQ_operator_code', ['code'], { unique: true }) +export class Operator { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/passenger-type.entity.ts b/src/modules/master-data/entities/passenger-type.entity.ts index 2120724..7233289 100644 --- a/src/modules/master-data/entities/passenger-type.entity.ts +++ b/src/modules/master-data/entities/passenger-type.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_passenger_types', schema: 'masters' }) -export class PassengerType extends TenantOwnedEntity { +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 new file mode 100644 index 0000000..332a7e9 --- /dev/null +++ b/src/modules/master-data/entities/refund-basis.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_refund_bases', schema: 'masters' }) +export class RefundBasis { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/refund-method.entity.ts b/src/modules/master-data/entities/refund-method.entity.ts new file mode 100644 index 0000000..6bcc642 --- /dev/null +++ b/src/modules/master-data/entities/refund-method.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_refund_methods', schema: 'masters' }) +export class RefundMethod { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/refund-type.entity.ts b/src/modules/master-data/entities/refund-type.entity.ts new file mode 100644 index 0000000..2d1d3ea --- /dev/null +++ b/src/modules/master-data/entities/refund-type.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_refund_types', schema: 'masters' }) +export class RefundType { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/region.entity.ts b/src/modules/master-data/entities/region.entity.ts index dc4e4f9..2a494a3 100644 --- a/src/modules/master-data/entities/region.entity.ts +++ b/src/modules/master-data/entities/region.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_regions', schema: 'masters' }) -export class Region extends TenantOwnedEntity { +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 0288dd2..ddb3420 100644 --- a/src/modules/master-data/entities/revenue-segment.entity.ts +++ b/src/modules/master-data/entities/revenue-segment.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_revenue_segments', schema: 'masters' }) -export class RevenueSegment extends TenantOwnedEntity { +export class RevenueSegment { @PrimaryGeneratedColumn('uuid') id!: string; diff --git a/src/modules/master-data/entities/rule-category-value.entity.ts b/src/modules/master-data/entities/rule-category-value.entity.ts deleted file mode 100644 index c4c8653..0000000 --- a/src/modules/master-data/entities/rule-category-value.entity.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { - Entity, - PrimaryGeneratedColumn, - Column, - CreateDateColumn, - UpdateDateColumn, - ManyToOne, - JoinColumn, -} from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; -import { RuleCategory } from './rule-category.entity'; - -@Entity({ name: 'tbl_rule_categories_values', schema: 'masters' }) -export class RuleCategoryValue extends TenantOwnedEntity { - @PrimaryGeneratedColumn('uuid') - id!: string; - - @Column({ type: 'uuid' }) - categoryId!: string; - - @ManyToOne(() => RuleCategory, { onDelete: 'CASCADE' }) - @JoinColumn({ name: 'categoryId' }) - category!: RuleCategory; - - @Column({ nullable: true }) - code?: string; - - @Column() - value!: string; - - @Column({ default: 0 }) - displayOrder!: number; - - @Column({ default: true }) - isActive!: boolean; - - @CreateDateColumn() - createdAt!: Date; - - @UpdateDateColumn() - updatedAt!: Date; -} diff --git a/src/modules/master-data/entities/rule-category.entity.ts b/src/modules/master-data/entities/rule-category.entity.ts index 63965f3..42ffd31 100644 --- a/src/modules/master-data/entities/rule-category.entity.ts +++ b/src/modules/master-data/entities/rule-category.entity.ts @@ -1,37 +1,39 @@ import { - Entity, - PrimaryGeneratedColumn, - Column, - CreateDateColumn, - Index, - UpdateDateColumn, + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + Index, + UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_rules_categories', schema: 'masters' }) -@Index('UQ_rule_category_tenant_code', ['tenantId', 'code'], { unique: true }) -export class RuleCategory extends TenantOwnedEntity { - @PrimaryGeneratedColumn('uuid') - id!: string; +@Index('UQ_rule_category_code', ['code'], { unique: true }) +export class RuleCategory { + @PrimaryGeneratedColumn('uuid') + id!: string; - @Column() - code!: string; + @Column() + code!: string; - @Column() - name!: string; + @Column() + name!: string; - @Column({ type: 'text', nullable: true }) - description?: string; + @Column({ type: 'varchar', nullable: true }) + tableName?: string; - @Column({ default: 0 }) - displayOrder!: number; + @Column({ type: 'text', nullable: true }) + description?: string; - @Column({ default: true }) - isActive!: boolean; + @Column({ default: 0 }) + displayOrder!: number; - @CreateDateColumn() - createdAt!: Date; - - @UpdateDateColumn() - updatedAt!: Date; + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; } diff --git a/src/modules/master-data/entities/special-assistance-type.entity.ts b/src/modules/master-data/entities/special-assistance-type.entity.ts new file mode 100644 index 0000000..f30ebe2 --- /dev/null +++ b/src/modules/master-data/entities/special-assistance-type.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_special_assistance_types', schema: 'masters' }) +export class SpecialAssistanceType { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/technical-fault-category.entity.ts b/src/modules/master-data/entities/technical-fault-category.entity.ts new file mode 100644 index 0000000..0ac314c --- /dev/null +++ b/src/modules/master-data/entities/technical-fault-category.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_technical_fault_categories', schema: 'masters' }) +export class TechnicalFaultCategory { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/entities/trip-purpose.entity.ts b/src/modules/master-data/entities/trip-purpose.entity.ts index 8f80760..16a1d4a 100644 --- a/src/modules/master-data/entities/trip-purpose.entity.ts +++ b/src/modules/master-data/entities/trip-purpose.entity.ts @@ -5,10 +5,9 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; -import { TenantOwnedEntity } from '../../../common/entities/tenant-owned.entity'; @Entity({ name: 'tbl_trip_purposes', schema: 'masters' }) -export class TripPurpose extends TenantOwnedEntity { +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 new file mode 100644 index 0000000..4276da4 --- /dev/null +++ b/src/modules/master-data/entities/weather-condition.entity.ts @@ -0,0 +1,28 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity({ name: 'tbl_weather_conditions', schema: 'masters' }) +export class WeatherCondition { + @PrimaryGeneratedColumn('uuid') + id!: string; + + @Column() + label!: string; + + @Column() + value!: string; + + @Column({ default: true }) + isActive!: boolean; + + @CreateDateColumn() + createdAt!: Date; + + @UpdateDateColumn() + updatedAt!: Date; +} diff --git a/src/modules/master-data/master-data.controller.ts b/src/modules/master-data/master-data.controller.ts index 79e3ba4..d9f54a9 100644 --- a/src/modules/master-data/master-data.controller.ts +++ b/src/modules/master-data/master-data.controller.ts @@ -1,75 +1,59 @@ -import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common'; -import { ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger'; +import { Controller, Get, Post, Put, Patch, Delete, Param, Body, Query } from '@nestjs/common'; +import { ApiBody, ApiOperation, ApiParam, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger'; import { MasterDataService } from './master-data.service'; import { CreateMasterDataDto } from './dto/create-master-data.dto'; import { UpdateMasterDataDto } from './dto/update-master-data.dto'; import { CreateRuleCategoryDto } from './dto/create-rule-category.dto'; import { UpdateRuleCategoryDto } from './dto/update-rule-category.dto'; -import { CreateRuleCategoryValueDto } from './dto/create-rule-category-value.dto'; -import { UpdateRuleCategoryValueDto } from './dto/update-rule-category-value.dto'; import { CreateOperatorDto } from './dto/create-operator.dto'; import { UpdateOperatorDto } from './dto/update-operator.dto'; +import { CreateActionCategoryDto } from './dto/create-action-category.dto'; +import { UpdateActionCategoryDto } from './dto/update-action-category.dto'; +import { CreateActionTypeDto } from './dto/create-action-type.dto'; +import { UpdateActionTypeDto } from './dto/update-action-type.dto'; +import { CreateFieldDefinitionDto } from './dto/create-field-definition.dto'; +import { UpdateFieldDefinitionDto } from './dto/update-field-definition.dto'; +import { ActionSubmissionDto } from './dto/action-submission.dto'; @ApiTags('master-data') @Controller('master-data') export class MasterDataController { - constructor(private readonly masterDataService: MasterDataService) {} + constructor(private readonly masterDataService: MasterDataService) { } - @Get('rule-categories') - @ApiOperation({ summary: 'Get all rule categories' }) - @ApiResponse({ status: 200, description: 'List of rule categories' }) + @Get('categories') + @ApiOperation({ summary: 'Get all masters table list as categories' }) + @ApiResponse({ status: 200, description: 'List of masters table categories' }) async findAllRuleCategories() { return this.masterDataService.findAllRuleCategories(); } - @Get('rule-categories/:id') - @ApiOperation({ summary: 'Get one rule category' }) - @ApiParam({ name: 'id', type: String, description: 'Rule category id' }) - @ApiResponse({ status: 200, description: 'Rule category found' }) + @Get('categories/:id') + @ApiOperation({ summary: 'Get one category' }) + @ApiParam({ name: 'id', type: String, description: 'category id' }) + @ApiResponse({ status: 200, description: 'category found' }) async findOneRuleCategory(@Param('id') id: string) { return this.masterDataService.findOneRuleCategory(id); } - @Post('rule-categories') - @ApiOperation({ summary: 'Create a rule category' }) + @Post('categories') + @ApiOperation({ summary: 'Create a category' }) @ApiBody({ type: CreateRuleCategoryDto, description: 'Rule category payload', - examples: { - default: { - value: { - code: 'fare-type', - name: 'Fare Type', - description: 'Fare-related rule categories', - displayOrder: 1, - isActive: true, - }, - }, - }, }) @ApiResponse({ status: 201, description: 'Rule category created' }) async createRuleCategory(@Body() createDto: CreateRuleCategoryDto) { return this.masterDataService.createRuleCategory(createDto); } - @Put('rule-categories/:id') - @ApiOperation({ summary: 'Update a rule category' }) - @ApiParam({ name: 'id', type: String, description: 'Rule category id' }) + @Put('categories/:id') + @ApiOperation({ summary: 'Update a category' }) + @ApiParam({ name: 'id', type: String, description: 'category id' }) @ApiBody({ type: UpdateRuleCategoryDto, - description: 'Rule category update payload', - examples: { - default: { - value: { - name: 'Fare Type', - description: 'Updated fare rule category', - displayOrder: 2, - isActive: true, - }, - }, - }, + description: 'category update payload', }) - @ApiResponse({ status: 200, description: 'Rule category updated' }) + @ApiResponse({ status: 200, description: 'category updated' }) async updateRuleCategory( @Param('id') id: string, @Body() updateDto: UpdateRuleCategoryDto, @@ -77,91 +61,22 @@ export class MasterDataController { return this.masterDataService.updateRuleCategory(id, updateDto); } - @Delete('rule-categories/:id') - @ApiOperation({ summary: 'Delete a rule category' }) - @ApiParam({ name: 'id', type: String, description: 'Rule category id' }) - @ApiResponse({ status: 200, description: 'Rule category deleted' }) + @Delete('categories/:id') + @ApiOperation({ summary: 'Delete a category' }) + @ApiParam({ name: 'id', type: String, description: 'category id' }) + @ApiResponse({ status: 200, description: 'category deleted' }) async removeRuleCategory(@Param('id') id: string) { return this.masterDataService.removeRuleCategory(id); } - @Get('rule-category-values') - @ApiOperation({ summary: 'Get all rule category values' }) - @ApiResponse({ status: 200, description: 'List of rule category values' }) - async findAllRuleCategoryValues() { - return this.masterDataService.findAllRuleCategoryValues(); - } - - @Get('rule-category-values/:code') - @ApiOperation({ summary: 'Get rule category values by category code' }) - @ApiParam({ name: 'code', type: String, description: 'Rule category code' }) - @ApiResponse({ status: 200, description: 'Rule category values for the requested code' }) + @Get('category-values/:code') + @ApiOperation({ summary: 'Get category values by category code' }) + @ApiParam({ name: 'code', type: String, description: 'category code' }) + @ApiResponse({ status: 200, description: 'category values for the requested code' }) async findRuleCategoryValuesByCode(@Param('code') code: string) { return this.masterDataService.findRuleCategoryValuesByCode(code); } - @Get('rule-category-values/:id') - @ApiOperation({ summary: 'Get one rule category value' }) - @ApiParam({ name: 'id', type: String, description: 'Rule category value id' }) - @ApiResponse({ status: 200, description: 'Rule category value found' }) - async findOneRuleCategoryValue(@Param('id') id: string) { - return this.masterDataService.findOneRuleCategoryValue(id); - } - - @Post('rule-category-values') - @ApiOperation({ summary: 'Create a rule category value' }) - @ApiBody({ - type: CreateRuleCategoryValueDto, - description: 'Rule category value payload', - examples: { - default: { - value: { - categoryId: '00000000-0000-0000-0000-000000000000', - code: 'economy', - value: 'Economy', - displayOrder: 1, - isActive: true, - }, - }, - }, - }) - @ApiResponse({ status: 201, description: 'Rule category value created' }) - async createRuleCategoryValue(@Body() createDto: CreateRuleCategoryValueDto) { - return this.masterDataService.createRuleCategoryValue(createDto); - } - - @Put('rule-category-values/:id') - @ApiOperation({ summary: 'Update a rule category value' }) - @ApiParam({ name: 'id', type: String, description: 'Rule category value id' }) - @ApiBody({ - type: UpdateRuleCategoryValueDto, - description: 'Rule category value update payload', - examples: { - default: { - value: { - value: 'Premium Economy', - displayOrder: 2, - isActive: true, - }, - }, - }, - }) - @ApiResponse({ status: 200, description: 'Rule category value updated' }) - async updateRuleCategoryValue( - @Param('id') id: string, - @Body() updateDto: UpdateRuleCategoryValueDto, - ) { - return this.masterDataService.updateRuleCategoryValue(id, updateDto); - } - - @Delete('rule-category-values/:id') - @ApiOperation({ summary: 'Delete a rule category value' }) - @ApiParam({ name: 'id', type: String, description: 'Rule category value id' }) - @ApiResponse({ status: 200, description: 'Rule category value deleted' }) - async removeRuleCategoryValue(@Param('id') id: string) { - return this.masterDataService.removeRuleCategoryValue(id); - } - @Get('operators') @ApiOperation({ summary: 'Get all operators' }) @ApiResponse({ status: 200, description: 'List of operators' }) @@ -182,17 +97,6 @@ export class MasterDataController { @ApiBody({ type: CreateOperatorDto, description: 'Operator payload', - examples: { - default: { - value: { - code: 'EQ', - name: 'Equals', - symbol: '=', - displayOrder: 1, - isActive: true, - }, - }, - }, }) @ApiResponse({ status: 201, description: 'Operator created' }) async createOperator(@Body() createDto: CreateOperatorDto) { @@ -205,19 +109,12 @@ export class MasterDataController { @ApiBody({ type: UpdateOperatorDto, description: 'Operator update payload', - examples: { - default: { - value: { - name: 'Equals', - symbol: '=', - displayOrder: 1, - isActive: true, - }, - }, - }, }) @ApiResponse({ status: 200, description: 'Operator updated' }) - async updateOperator(@Param('id') id: string, @Body() updateDto: UpdateOperatorDto) { + async updateOperator( + @Param('id') id: string, + @Body() updateDto: UpdateOperatorDto, + ) { return this.masterDataService.updateOperator(id, updateDto); } @@ -229,22 +126,212 @@ export class MasterDataController { return this.masterDataService.removeOperator(id); } - @Get('jurisdictions') - @ApiOperation({ summary: 'Get all jurisdictions' }) - @ApiResponse({ status: 200, description: 'List of jurisdictions' }) - async findAllJurisdictions() { - return this.masterDataService.findAll('JURISDICTION'); + // --- Action Categories Endpoints --- + + @Get('action-categories') + @ApiOperation({ summary: 'Get all action categories' }) + @ApiQuery({ name: 'page', required: false, type: Number }) + @ApiQuery({ name: 'limit', required: false, type: Number }) + @ApiResponse({ status: 200, description: 'List of action categories' }) + async findAllActionCategories( + @Query('page') page?: number, + @Query('limit') limit?: number, + ) { + return this.masterDataService.findAllActionCategories( + page ? Number(page) : undefined, + limit ? Number(limit) : undefined, + ); } - @Get('jurisdictions/:id') - @ApiOperation({ summary: 'Get one jurisdiction' }) - @ApiParam({ name: 'id', type: String, description: 'Jurisdiction id' }) - @ApiResponse({ status: 200, description: 'Jurisdiction found' }) - async findOneJurisdiction(@Param('id') id: string) { - return this.masterDataService.findOne('JURISDICTION', id); + @Get('action-categories/:id') + @ApiOperation({ summary: 'Get one action category' }) + @ApiParam({ name: 'id', type: String, description: 'Action category id' }) + @ApiResponse({ status: 200, description: 'Action category found' }) + async findOneActionCategory(@Param('id') id: string) { + return this.masterDataService.findOneActionCategory(id); } - // Example: POST /master-data/REGION + @Post('action-categories') + @ApiOperation({ summary: 'Create an action category' }) + @ApiBody({ type: CreateActionCategoryDto, description: 'Action category payload' }) + @ApiResponse({ status: 201, description: 'Action category created' }) + async createActionCategory(@Body() createDto: CreateActionCategoryDto) { + return this.masterDataService.createActionCategory(createDto); + } + + @Put('action-categories/:id') + @ApiOperation({ summary: 'Update an action category' }) + @ApiParam({ name: 'id', type: String, description: 'Action category id' }) + @ApiBody({ type: UpdateActionCategoryDto, description: 'Action category update payload' }) + @ApiResponse({ status: 200, description: 'Action category updated' }) + async updateActionCategory( + @Param('id') id: string, + @Body() updateDto: UpdateActionCategoryDto, + ) { + return this.masterDataService.updateActionCategory(id, updateDto); + } + + @Delete('action-categories/:id') + @ApiOperation({ summary: 'Delete an action category' }) + @ApiParam({ name: 'id', type: String, description: 'Action category id' }) + @ApiResponse({ status: 200, description: 'Action category deleted' }) + async removeActionCategory(@Param('id') id: string) { + return this.masterDataService.removeActionCategory(id); + } + + // --- Action Types Endpoints --- + + @Get('action-types') + @ApiOperation({ summary: 'Get all action types' }) + @ApiQuery({ name: 'page', required: false, type: Number }) + @ApiQuery({ name: 'limit', required: false, type: Number }) + @ApiResponse({ status: 200, description: 'List of action types' }) + async findAllActionTypes( + @Query('page') page?: number, + @Query('limit') limit?: number, + ) { + return this.masterDataService.findAllActionTypes( + page ? Number(page) : undefined, + limit ? Number(limit) : undefined, + ); + } + + @Get('action-types/category/:categoryCode') + @ApiOperation({ summary: 'Get action types by action category code' }) + @ApiParam({ name: 'categoryCode', type: String, description: 'Action category code' }) + @ApiResponse({ status: 200, description: 'List of action types for the requested category' }) + async findActionTypesByCategory(@Param('categoryCode') categoryCode: string) { + return this.masterDataService.findActionTypesByCategory(categoryCode); + } + + @Get('action-types/category-id/:categoryId') + @ApiOperation({ summary: 'Get action types by action category ID' }) + @ApiParam({ name: 'categoryId', type: String, description: 'Action category ID' }) + @ApiResponse({ status: 200, description: 'List of action types for the requested category ID' }) + async findActionTypesByCategoryId(@Param('categoryId') categoryId: string) { + return this.masterDataService.findActionTypesByCategoryId(categoryId); + } + + @Get('action-types/:id') + @ApiOperation({ summary: 'Get one action type' }) + @ApiParam({ name: 'id', type: String, description: 'Action type id' }) + @ApiResponse({ status: 200, description: 'Action type found' }) + async findOneActionType(@Param('id') id: string) { + return this.masterDataService.findOneActionType(id); + } + + @Post('action-types') + @ApiOperation({ summary: 'Create an action type' }) + @ApiBody({ type: CreateActionTypeDto, description: 'Action type payload' }) + @ApiResponse({ status: 201, description: 'Action type created' }) + async createActionType(@Body() createDto: CreateActionTypeDto) { + return this.masterDataService.createActionType(createDto); + } + + @Put('action-types/:id') + @ApiOperation({ summary: 'Update an action type' }) + @ApiParam({ name: 'id', type: String, description: 'Action type id' }) + @ApiBody({ type: UpdateActionTypeDto, description: 'Action type update payload' }) + @ApiResponse({ status: 200, description: 'Action type updated' }) + async updateActionType( + @Param('id') id: string, + @Body() updateDto: UpdateActionTypeDto, + ) { + return this.masterDataService.updateActionType(id, updateDto); + } + + @Delete('action-types/:id') + @ApiOperation({ summary: 'Delete an action type' }) + @ApiParam({ name: 'id', type: String, description: 'Action type id' }) + @ApiResponse({ status: 200, description: 'Action type deleted' }) + async removeActionType(@Param('id') id: string) { + return this.masterDataService.removeActionType(id); + } + + // --- Field Definitions Endpoints --- + + @Get('action-types/:actionTypeId/fields') + @ApiOperation({ summary: 'Get all field definitions for an Action Type' }) + @ApiParam({ name: 'actionTypeId', type: String, description: 'Action type id' }) + async findFieldsByActionType(@Param('actionTypeId') actionTypeId: string) { + return this.masterDataService.findFieldsByActionType(actionTypeId); + } + + @Post('action-types/:actionTypeId/fields') + @ApiOperation({ summary: 'Create a field definition for an Action Type' }) + @ApiParam({ name: 'actionTypeId', type: String, description: 'Action type id' }) + async createFieldDefinition( + @Param('actionTypeId') actionTypeId: string, + @Body() dto: CreateFieldDefinitionDto, + ) { + return this.masterDataService.createFieldDefinition(actionTypeId, dto); + } + + @Patch('fields/:fieldId') + @ApiOperation({ summary: 'Update a field definition (PATCH)' }) + @ApiParam({ name: 'fieldId', type: String, description: 'Field definition id' }) + async patchFieldDefinition( + @Param('fieldId') fieldId: string, + @Body() dto: UpdateFieldDefinitionDto, + ) { + return this.masterDataService.updateFieldDefinition(fieldId, dto); + } + + @Put('fields/:fieldId') + @ApiOperation({ summary: 'Update a field definition (PUT)' }) + @ApiParam({ name: 'fieldId', type: String, description: 'Field definition id' }) + async updateFieldDefinition( + @Param('fieldId') fieldId: string, + @Body() dto: UpdateFieldDefinitionDto, + ) { + return this.masterDataService.updateFieldDefinition(fieldId, dto); + } + + @Delete('fields/:fieldId') + @ApiOperation({ summary: 'Delete a field definition' }) + @ApiParam({ name: 'fieldId', type: String, description: 'Field definition id' }) + async removeFieldDefinition(@Param('fieldId') fieldId: string) { + return this.masterDataService.removeFieldDefinition(fieldId); + } + + @Post('action-types/:actionTypeId/fields/reorder') + @ApiOperation({ summary: 'Reorder field definitions for an Action Type' }) + @ApiParam({ name: 'actionTypeId', type: String, description: 'Action type id' }) + async reorderFieldDefinitions( + @Param('actionTypeId') actionTypeId: string, + @Body('fieldIds') fieldIds: string[], + ) { + return this.masterDataService.reorderFieldDefinitions(actionTypeId, fieldIds || []); + } + + // --- Dynamic Action Submission --- + + @Post('actions') + @ApiOperation({ summary: 'Submit an action payload with dynamic field revalidation' }) + async submitAction(@Body() payload: ActionSubmissionDto) { + return this.masterDataService.validateAndSubmitAction(payload); + } + + @Get('refund-bases') + @ApiOperation({ summary: 'Get all refund bases' }) + async findAllRefundBases() { + return this.masterDataService.findAll('REFUND_BASIS'); + } + + @Get('currencies') + @ApiOperation({ summary: 'Get all currencies' }) + async findAllCurrencies() { + return this.masterDataService.findAll('CURRENCY'); + } + + @Get('refund-methods') + @ApiOperation({ summary: 'Get all refund methods' }) + async findAllRefundMethods() { + return this.masterDataService.findAll('REFUND_METHOD'); + } + + // --- Generic Master Data Endpoints --- + @Post(':category') async create( @Param('category') category: string, @@ -253,13 +340,11 @@ export class MasterDataController { return this.masterDataService.create(category, createDto); } - // Example: GET /master-data/REGION @Get(':category') async findAll(@Param('category') category: string) { return this.masterDataService.findAll(category); } - // Example: GET /master-data/REGION/uuid @Get(':category/:id') async findOne( @Param('category') category: string, @@ -268,7 +353,6 @@ export class MasterDataController { return this.masterDataService.findOne(category, id); } - // Example: PUT /master-data/REGION/uuid @Put(':category/:id') async update( @Param('category') category: string, @@ -278,7 +362,6 @@ export class MasterDataController { return this.masterDataService.update(category, id, updateDto); } - // Example: DELETE /master-data/REGION/uuid @Delete(':category/:id') async remove( @Param('category') category: string, diff --git a/src/modules/master-data/master-data.module.ts b/src/modules/master-data/master-data.module.ts index c6b3b6b..e4049a5 100644 --- a/src/modules/master-data/master-data.module.ts +++ b/src/modules/master-data/master-data.module.ts @@ -13,8 +13,36 @@ import { AncillaryPurchase } from './entities/ancillary-purchase.entity'; import { RevenueSegment } from './entities/revenue-segment.entity'; import { Jurisdiction } from './entities/jurisdiction.entity'; import { RuleCategory } from './entities/rule-category.entity'; -import { RuleCategoryValue } from './entities/rule-category-value.entity'; import { Operator } from './entities/operator.entity'; +import { ActionCategory } from './entities/action-category.entity'; +import { ActionType } from './entities/action-type.entity'; +import { FieldDefinition } from './entities/field-definition.entity'; +import { ActionSubmission } from './entities/action-submission.entity'; + +import { BookingChannel } from './entities/booking-channel.entity'; +import { FlightType } from './entities/flight-type.entity'; +import { JourneyType } from './entities/journey-type.entity'; +import { FareFlexibility } from './entities/fare-flexibility.entity'; +import { CarrierType } from './entities/carrier-type.entity'; +import { SpecialAssistanceType } from './entities/special-assistance-type.entity'; +import { DelayReason } from './entities/delay-reason.entity'; +import { DelayDuration } from './entities/delay-duration.entity'; +import { ExtraordinaryCircumstance } from './entities/extraordinary-circumstance.entity'; +import { CancellationReason } from './entities/cancellation-reason.entity'; +import { DiversionReason } from './entities/diversion-reason.entity'; +import { MissedConnectionReason } from './entities/missed-connection-reason.entity'; +import { CompensationEligibility } from './entities/compensation-eligibility.entity'; +import { CompensationType } from './entities/compensation-type.entity'; +import { RefundType } from './entities/refund-type.entity'; +import { FlightDisruptionType } from './entities/flight-disruption-type.entity'; +import { AirlineResponsibility } from './entities/airline-responsibility.entity'; +import { WeatherCondition } from './entities/weather-condition.entity'; +import { AtcRestriction } from './entities/atc-restriction.entity'; +import { TechnicalFaultCategory } from './entities/technical-fault-category.entity'; +import { RefundBasis } from './entities/refund-basis.entity'; +import { Currency } from './entities/currency.entity'; +import { RefundMethod } from './entities/refund-method.entity'; + @Module({ imports: [ TypeOrmModule.forFeature([ @@ -28,8 +56,34 @@ import { Operator } from './entities/operator.entity'; RevenueSegment, Jurisdiction, RuleCategory, - RuleCategoryValue, Operator, + ActionCategory, + ActionType, + FieldDefinition, + ActionSubmission, + BookingChannel, + FlightType, + JourneyType, + FareFlexibility, + CarrierType, + SpecialAssistanceType, + DelayReason, + DelayDuration, + ExtraordinaryCircumstance, + CancellationReason, + DiversionReason, + MissedConnectionReason, + CompensationEligibility, + CompensationType, + RefundType, + FlightDisruptionType, + AirlineResponsibility, + WeatherCondition, + AtcRestriction, + TechnicalFaultCategory, + RefundBasis, + Currency, + RefundMethod, ]), ], controllers: [MasterDataController], diff --git a/src/modules/master-data/master-data.service.ts b/src/modules/master-data/master-data.service.ts index c8e5e13..81e6681 100644 --- a/src/modules/master-data/master-data.service.ts +++ b/src/modules/master-data/master-data.service.ts @@ -1,7 +1,8 @@ -import { Injectable, Logger, BadRequestException } from '@nestjs/common'; +import * as fs from 'fs'; +import * as path from 'path'; +import { Injectable, Logger, BadRequestException, OnModuleInit } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; -import { getTenantId } from '../../common/tenant/tenant.context'; +import { Repository, DataSource } from 'typeorm'; import { MembershipTier } from './entities/membership-tier.entity'; import { CustomerValue } from './entities/customer-value.entity'; @@ -13,14 +14,50 @@ import { AncillaryPurchase } from './entities/ancillary-purchase.entity'; import { RevenueSegment } from './entities/revenue-segment.entity'; import { Jurisdiction } from './entities/jurisdiction.entity'; import { RuleCategory } from './entities/rule-category.entity'; -import { RuleCategoryValue } from './entities/rule-category-value.entity'; import { Operator } from './entities/operator.entity'; +import { ActionCategory } from './entities/action-category.entity'; +import { ActionType } from './entities/action-type.entity'; +import { FieldDefinition } from './entities/field-definition.entity'; +import { ActionSubmission } from './entities/action-submission.entity'; + +import { BookingChannel } from './entities/booking-channel.entity'; +import { FlightType } from './entities/flight-type.entity'; +import { JourneyType } from './entities/journey-type.entity'; +import { FareFlexibility } from './entities/fare-flexibility.entity'; +import { CarrierType } from './entities/carrier-type.entity'; +import { SpecialAssistanceType } from './entities/special-assistance-type.entity'; +import { DelayReason } from './entities/delay-reason.entity'; +import { DelayDuration } from './entities/delay-duration.entity'; +import { ExtraordinaryCircumstance } from './entities/extraordinary-circumstance.entity'; +import { CancellationReason } from './entities/cancellation-reason.entity'; +import { DiversionReason } from './entities/diversion-reason.entity'; +import { MissedConnectionReason } from './entities/missed-connection-reason.entity'; +import { CompensationEligibility } from './entities/compensation-eligibility.entity'; +import { CompensationType } from './entities/compensation-type.entity'; +import { RefundType } from './entities/refund-type.entity'; +import { FlightDisruptionType } from './entities/flight-disruption-type.entity'; +import { AirlineResponsibility } from './entities/airline-responsibility.entity'; +import { WeatherCondition } from './entities/weather-condition.entity'; +import { AtcRestriction } from './entities/atc-restriction.entity'; +import { TechnicalFaultCategory } from './entities/technical-fault-category.entity'; +import { RefundBasis } from './entities/refund-basis.entity'; +import { Currency } from './entities/currency.entity'; +import { RefundMethod } from './entities/refund-method.entity'; + +import { CreateActionCategoryDto } from './dto/create-action-category.dto'; +import { UpdateActionCategoryDto } from './dto/update-action-category.dto'; +import { CreateActionTypeDto } from './dto/create-action-type.dto'; +import { UpdateActionTypeDto } from './dto/update-action-type.dto'; +import { CreateFieldDefinitionDto } from './dto/create-field-definition.dto'; +import { UpdateFieldDefinitionDto } from './dto/update-field-definition.dto'; +import { ActionSubmissionDto } from './dto/action-submission.dto'; @Injectable() -export class MasterDataService { +export class MasterDataService implements OnModuleInit { private readonly logger = new Logger(MasterDataService.name); constructor( + private dataSource: DataSource, @InjectRepository(MembershipTier) private membershipTierRepo: Repository, @InjectRepository(CustomerValue) private customerValueRepo: Repository, @InjectRepository(Region) private regionRepo: Repository, @@ -31,28 +68,180 @@ export class MasterDataService { @InjectRepository(RevenueSegment) private revenueSegmentRepo: Repository, @InjectRepository(Jurisdiction) private jurisdictionRepo: Repository, @InjectRepository(RuleCategory) private ruleCategoryRepo: Repository, - @InjectRepository(RuleCategoryValue) private ruleCategoryValueRepo: Repository, @InjectRepository(Operator) private operatorRepo: Repository, + @InjectRepository(ActionCategory) private actionCategoryRepo: Repository, + @InjectRepository(ActionType) private actionTypeRepo: Repository, + @InjectRepository(FieldDefinition) private fieldDefinitionRepo: Repository, + @InjectRepository(ActionSubmission) private actionSubmissionRepo: Repository, + + @InjectRepository(BookingChannel) private bookingChannelRepo: Repository, + @InjectRepository(FlightType) private flightTypeRepo: Repository, + @InjectRepository(JourneyType) private journeyTypeRepo: Repository, + @InjectRepository(FareFlexibility) private fareFlexibilityRepo: Repository, + @InjectRepository(CarrierType) private carrierTypeRepo: Repository, + @InjectRepository(SpecialAssistanceType) private specialAssistanceTypeRepo: Repository, + @InjectRepository(DelayReason) private delayReasonRepo: Repository, + @InjectRepository(DelayDuration) private delayDurationRepo: Repository, + @InjectRepository(ExtraordinaryCircumstance) private extraordinaryCircumstanceRepo: Repository, + @InjectRepository(CancellationReason) private cancellationReasonRepo: Repository, + @InjectRepository(DiversionReason) private diversionReasonRepo: Repository, + @InjectRepository(MissedConnectionReason) private missedConnectionReasonRepo: Repository, + @InjectRepository(CompensationEligibility) private compensationEligibilityRepo: Repository, + @InjectRepository(CompensationType) private compensationTypeRepo: Repository, + @InjectRepository(RefundType) private refundTypeRepo: Repository, + @InjectRepository(FlightDisruptionType) private flightDisruptionTypeRepo: Repository, + @InjectRepository(AirlineResponsibility) private airlineResponsibilityRepo: Repository, + @InjectRepository(WeatherCondition) private weatherConditionRepo: Repository, + @InjectRepository(AtcRestriction) private atcRestrictionRepo: Repository, + @InjectRepository(TechnicalFaultCategory) private technicalFaultCategoryRepo: Repository, + @InjectRepository(RefundBasis) private refundBasisRepo: Repository, + @InjectRepository(Currency) private currencyRepo: Repository, + @InjectRepository(RefundMethod) private refundMethodRepo: Repository, ) {} - private resolveTenantId(tenantId?: string): string { - return tenantId ?? getTenantId(); - } - private getRepositoryByCategory(category: string): Repository { - switch (category?.toUpperCase()) { - case 'MEMBERSHIP_TIER': return this.membershipTierRepo; - case 'CUSTOMER_VALUE': return this.customerValueRepo; - case 'REGION': return this.regionRepo; - case 'TRIP_PURPOSE': return this.tripPurposeRepo; - case 'CABIN_CLASS': return this.cabinClassRepo; - case 'PASSENGER_TYPE': return this.passengerTypeRepo; - case 'ANCILLARY_PURCHASE': return this.ancillaryPurchaseRepo; - case 'REVENUE_SEGMENT': return this.revenueSegmentRepo; - case 'JURISDICTION': return this.jurisdictionRepo; - case 'RULE_CATEGORY': return this.ruleCategoryRepo; - case 'RULE_CATEGORY_VALUE': return this.ruleCategoryValueRepo; - case 'OPERATORS': return this.operatorRepo; + const key = category?.toUpperCase().replace(/-/g, '_'); + switch (key) { + case 'MEMBERSHIP_TIER': + case 'LOYALTY_TIER': + case 'TBL_MEMBERSHIP_TIERS': + return this.membershipTierRepo; + + case 'CUSTOMER_VALUE': + case 'TBL_CUSTOMER_VALUES': + return this.customerValueRepo; + + case 'REGION': + case 'TBL_REGIONS': + return this.regionRepo; + + case 'TRIP_PURPOSE': + case 'TBL_TRIP_PURPOSES': + return this.tripPurposeRepo; + + case 'CABIN_CLASS': + case 'TBL_CABIN_CLASSES': + return this.cabinClassRepo; + + case 'PASSENGER_TYPE': + case 'TBL_PASSENGER_TYPES': + return this.passengerTypeRepo; + + case 'ANCILLARY_PURCHASE': + case 'TBL_ANCILLARY_PURCHASES': + return this.ancillaryPurchaseRepo; + + case 'REVENUE_SEGMENT': + case 'TBL_REVENUE_SEGMENTS': + return this.revenueSegmentRepo; + + case 'JURISDICTION': + case 'TBL_JURISDICTIONS': + return this.jurisdictionRepo; + + case 'RULE_CATEGORY': + case 'TBL_RULES_CATEGORIES': + return this.ruleCategoryRepo; + + case 'OPERATORS': + case 'TBL_OPERATORS': + return this.operatorRepo; + + case 'BOOKING_CHANNEL': + case 'TBL_BOOKING_CHANNELS': + return this.bookingChannelRepo; + + case 'FLIGHT_TYPE': + case 'TBL_FLIGHT_TYPES': + return this.flightTypeRepo; + + case 'JOURNEY_TYPE': + case 'TBL_JOURNEY_TYPES': + return this.journeyTypeRepo; + + case 'FARE_FLEXIBILITY': + case 'TBL_FARE_FLEXIBILITIES': + return this.fareFlexibilityRepo; + + case 'CARRIER_TYPE': + case 'TBL_CARRIER_TYPES': + return this.carrierTypeRepo; + + case 'SPECIAL_ASSISTANCE_TYPE': + case 'TBL_SPECIAL_ASSISTANCE_TYPES': + return this.specialAssistanceTypeRepo; + + case 'DELAY_REASON': + case 'TBL_DELAY_REASONS': + return this.delayReasonRepo; + + case 'DELAY_DURATION': + case 'TBL_DELAY_DURATIONS': + return this.delayDurationRepo; + + case 'EXTRAORDINARY_CIRCUMSTANCES': + case 'TBL_EXTRAORDINARY_CIRCUMSTANCES': + return this.extraordinaryCircumstanceRepo; + + case 'CANCELLATION_REASON': + case 'TBL_CANCELLATION_REASONS': + return this.cancellationReasonRepo; + + case 'DIVERSION_REASON': + case 'TBL_DIVERSION_REASONS': + return this.diversionReasonRepo; + + case 'MISSED_CONNECTION_REASON': + case 'TBL_MISSED_CONNECTION_REASONS': + return this.missedConnectionReasonRepo; + + case 'COMPENSATION_ELIGIBILITY': + case 'TBL_COMPENSATION_ELIGIBILITIES': + return this.compensationEligibilityRepo; + + case 'COMPENSATION_TYPE': + case 'TBL_COMPENSATION_TYPES': + return this.compensationTypeRepo; + + case 'REFUND_TYPE': + case 'TBL_REFUND_TYPES': + return this.refundTypeRepo; + + case 'FLIGHT_DISRUPTION_TYPE': + case 'TBL_FLIGHT_DISRUPTION_TYPES': + return this.flightDisruptionTypeRepo; + + case 'AIRLINE_RESPONSIBILITY': + case 'TBL_AIRLINE_RESPONSIBILITIES': + return this.airlineResponsibilityRepo; + + case 'WEATHER_CONDITION': + case 'TBL_WEATHER_CONDITIONS': + return this.weatherConditionRepo; + + case 'ATC_RESTRICTION': + case 'TBL_ATC_RESTRICTIONS': + return this.atcRestrictionRepo; + + case 'TECHNICAL_FAULT_CATEGORY': + case 'TBL_TECHNICAL_FAULT_CATEGORIES': + return this.technicalFaultCategoryRepo; + + case 'REFUND_BASIS': + case 'REFUND_BASES': + case 'TBL_REFUND_BASES': + return this.refundBasisRepo; + + case 'CURRENCY': + case 'CURRENCIES': + case 'TBL_CURRENCIES': + return this.currencyRepo; + + case 'REFUND_METHOD': + case 'REFUND_METHODS': + case 'TBL_REFUND_METHODS': + return this.refundMethodRepo; + default: throw new BadRequestException(`Invalid category: ${category}`); } @@ -65,13 +254,13 @@ export class MasterDataService { const repo = this.getRepositoryByCategory(category); return repo.find({ - where: { isActive: true, tenantId: getTenantId() }, + where: { isActive: true }, }); } async findOne(category: string, id: string): Promise { const repo = this.getRepositoryByCategory(category); - const item = await repo.findOne({ where: { id, tenantId: getTenantId() } }); + const item = await repo.findOne({ where: { id } }); if (!item) { throw new BadRequestException(`${category} with id ${id} not found`); } @@ -80,7 +269,7 @@ export class MasterDataService { async create(category: string, data: any): Promise { const repo = this.getRepositoryByCategory(category); - const newItem = repo.create({ ...data, tenantId: getTenantId() }); + const newItem = repo.create(data); return repo.save(newItem); } @@ -99,13 +288,13 @@ export class MasterDataService { async findAllRuleCategories(): Promise { return this.ruleCategoryRepo.find({ - where: { isActive: true, tenantId: getTenantId() }, + where: { isActive: true }, order: { displayOrder: 'ASC', name: 'ASC' }, }); } async findOneRuleCategory(id: string): Promise { - const item = await this.ruleCategoryRepo.findOne({ where: { id, tenantId: getTenantId() } }); + const item = await this.ruleCategoryRepo.findOne({ where: { id } }); if (!item) { throw new BadRequestException(`Rule category with id ${id} not found`); } @@ -113,7 +302,7 @@ export class MasterDataService { } async createRuleCategory(data: Partial): Promise { - const newItem = this.ruleCategoryRepo.create({ ...data, tenantId: getTenantId() }); + const newItem = this.ruleCategoryRepo.create(data); return this.ruleCategoryRepo.save(newItem); } @@ -128,61 +317,40 @@ export class MasterDataService { await this.ruleCategoryRepo.remove(item); } - async findAllRuleCategoryValues(): Promise { - return this.ruleCategoryValueRepo.find({ - where: { isActive: true, tenantId: getTenantId() }, - order: { displayOrder: 'ASC', value: 'ASC' }, - }); - } - - async findRuleCategoryValuesByCode(code: string): Promise { + async findRuleCategoryValuesByCode(code: string): Promise { const category = await this.ruleCategoryRepo.findOne({ - where: { code, tenantId: getTenantId() }, + where: { code }, }); if (!category) { throw new BadRequestException(`Rule category with code ${code} not found`); } - return this.ruleCategoryValueRepo.find({ - where: { categoryId: category.id, isActive: true, tenantId: getTenantId() }, - order: { displayOrder: 'ASC', value: 'ASC' }, + const targetKey = category.tableName || category.code; + const repo = this.getRepositoryByCategory(targetKey); + const items = await repo.find({ + where: { isActive: true }, }); - } - async findOneRuleCategoryValue(id: string): Promise { - const item = await this.ruleCategoryValueRepo.findOne({ where: { id, tenantId: getTenantId() } }); - if (!item) { - throw new BadRequestException(`Rule category value with id ${id} not found`); - } - return item; - } - - async createRuleCategoryValue(data: Partial): Promise { - const newItem = this.ruleCategoryValueRepo.create({ ...data, tenantId: getTenantId() }); - return this.ruleCategoryValueRepo.save(newItem); - } - - async updateRuleCategoryValue(id: string, data: Partial): Promise { - const item = await this.findOneRuleCategoryValue(id); - Object.assign(item, data); - return this.ruleCategoryValueRepo.save(item); - } - - async removeRuleCategoryValue(id: string): Promise { - const item = await this.findOneRuleCategoryValue(id); - await this.ruleCategoryValueRepo.remove(item); + return items.map((item) => ({ + id: item.id, + code: item.value || item.code, + value: item.label || item.name || item.value, + label: item.label || item.name || item.value, + displayOrder: item.displayOrder ?? 0, + isActive: item.isActive, + })); } async findAllOperators(): Promise { return this.operatorRepo.find({ - where: { isActive: true, tenantId: getTenantId() }, + where: { isActive: true }, order: { displayOrder: 'ASC', name: 'ASC' }, }); } async findOneOperator(id: string): Promise { - const item = await this.operatorRepo.findOne({ where: { id, tenantId: getTenantId() } }); + const item = await this.operatorRepo.findOne({ where: { id } }); if (!item) { throw new BadRequestException(`Operator with id ${id} not found`); } @@ -190,7 +358,7 @@ export class MasterDataService { } async createOperator(data: Partial): Promise { - const newItem = this.operatorRepo.create({ ...data, tenantId: getTenantId() }); + const newItem = this.operatorRepo.create(data); return this.operatorRepo.save(newItem); } @@ -205,438 +373,225 @@ export class MasterDataService { await this.operatorRepo.remove(item); } - public async seedData(tenantId?: string) { - const resolvedTenantId = this.resolveTenantId(tenantId); - this.logger.log(`Checking if master data needs seeding for tenant ${resolvedTenantId}...`); + // --- Action Categories --- + async findAllActionCategories(page?: number, limit?: number): Promise { + if (page !== undefined && limit !== undefined) { + const skip = (page - 1) * limit; + const [data, total] = await this.actionCategoryRepo.findAndCount({ + where: { isActive: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + skip, + take: limit, + }); + return { + data, + total, + page, + limit, + totalPages: Math.ceil(total / limit), + }; + } + return this.actionCategoryRepo.find({ + where: { isActive: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + }); + } - if (await this.membershipTierRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'Platinum', value: 'platinum', tenantId: resolvedTenantId }, - { label: 'Gold', value: 'gold', tenantId: resolvedTenantId }, - { label: 'Silver', value: 'silver', tenantId: resolvedTenantId }, - { label: 'Bronze', value: 'bronze', tenantId: resolvedTenantId }, - { label: 'Basic', value: 'basic', tenantId: resolvedTenantId }, - { label: 'Non-Member', value: 'non-member', tenantId: resolvedTenantId }, - ]; - await this.membershipTierRepo.save(this.membershipTierRepo.create(data)); + async findOneActionCategory(id: string): Promise { + const item = await this.actionCategoryRepo.findOne({ where: { id } }); + if (!item) { + throw new BadRequestException(`Action category with id ${id} not found`); + } + return item; + } + + async createActionCategory(data: CreateActionCategoryDto): Promise { + const newItem = this.actionCategoryRepo.create(data); + return this.actionCategoryRepo.save(newItem); + } + + async updateActionCategory(id: string, data: UpdateActionCategoryDto): Promise { + const item = await this.findOneActionCategory(id); + Object.assign(item, data); + return this.actionCategoryRepo.save(item); + } + + async removeActionCategory(id: string): Promise { + const item = await this.findOneActionCategory(id); + await this.actionCategoryRepo.remove(item); + } + + // --- Action Types --- + async findAllActionTypes(page?: number, limit?: number): Promise { + if (page !== undefined && limit !== undefined) { + const skip = (page - 1) * limit; + const [data, total] = await this.actionTypeRepo.findAndCount({ + where: { isActive: true }, + relations: { category: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + skip, + take: limit, + }); + return { + data, + total, + page, + limit, + totalPages: Math.ceil(total / limit), + }; + } + return this.actionTypeRepo.find({ + where: { isActive: true }, + relations: { category: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + }); + } + + async findActionTypesByCategory(categoryCode: string): Promise { + const category = await this.actionCategoryRepo.findOne({ where: { code: categoryCode } }); + if (!category) { + // Fallback: check if categoryCode is actually an ID + return this.findActionTypesByCategoryId(categoryCode); + } + return this.actionTypeRepo.find({ + where: { categoryId: category.id, isActive: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + }); + } + + async findActionTypesByCategoryId(categoryId: string): Promise { + return this.actionTypeRepo.find({ + where: { categoryId, isActive: true }, + order: { displayOrder: 'ASC', name: 'ASC' }, + }); + } + + async findOneActionType(id: string): Promise { + const item = await this.actionTypeRepo.findOne({ where: { id }, relations: { category: true } }); + if (!item) { + throw new BadRequestException(`Action type with id ${id} not found`); + } + return item; + } + + async createActionType(data: CreateActionTypeDto): Promise { + const newItem = this.actionTypeRepo.create(data); + return this.actionTypeRepo.save(newItem); + } + + async updateActionType(id: string, data: UpdateActionTypeDto): Promise { + const item = await this.findOneActionType(id); + Object.assign(item, data); + return this.actionTypeRepo.save(item); + } + + async removeActionType(id: string): Promise { + const item = await this.findOneActionType(id); + await this.actionTypeRepo.remove(item); + } + + // --- Dynamic Action Configuration & Submission --- + async getActionConfig(actionTypeCode: string): Promise<{ actionType: ActionType; fields: FieldDefinition[] }> { + const actionType = await this.actionTypeRepo.findOne({ + where: { code: actionTypeCode, isActive: true }, + relations: { category: true }, + }); + + if (!actionType) { + throw new BadRequestException(`Action type with code '${actionTypeCode}' not found or inactive`); } - if (await this.customerValueRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'High Value', value: 'high', tenantId: resolvedTenantId }, - { label: 'Medium Value', value: 'medium', tenantId: resolvedTenantId }, - { label: 'Low Value', value: 'low', tenantId: resolvedTenantId }, - ]; - await this.customerValueRepo.save(this.customerValueRepo.create(data)); + const fields = await this.fieldDefinitionRepo.find({ + where: { actionTypeId: actionType.id, isActive: true }, + order: { displayOrder: 'ASC' }, + }); + + return { actionType, fields }; + } + + async submitAction(submissionDto: ActionSubmissionDto): Promise { + const submission = this.actionSubmissionRepo.create({ + categoryId: submissionDto.category_id, + actionTypeId: submissionDto.action_type_id, + data: submissionDto.data, + }); + + return this.actionSubmissionRepo.save(submission); + } + + async validateAndSubmitAction(submissionDto: ActionSubmissionDto): Promise { + return this.submitAction(submissionDto); + } + + // --- Field Definitions Management --- + async findAllFieldDefinitions(): Promise { + return this.fieldDefinitionRepo.find({ + where: { isActive: true }, + relations: { actionType: true }, + order: { displayOrder: 'ASC' }, + }); + } + + async findFieldsByActionType(actionTypeId: string): Promise { + return this.fieldDefinitionRepo.find({ + where: { actionTypeId, isActive: true }, + order: { displayOrder: 'ASC' }, + }); + } + + async createFieldDefinition(actionTypeIdOrData: string | Partial, data?: CreateFieldDefinitionDto): Promise { + if (typeof actionTypeIdOrData === 'string') { + const payload: Partial = { + ...(data as Partial), + actionTypeId: actionTypeIdOrData, + }; + const newItem = this.fieldDefinitionRepo.create(payload); + return this.fieldDefinitionRepo.save(newItem); } + const newItem = this.fieldDefinitionRepo.create(actionTypeIdOrData as Partial); + return this.fieldDefinitionRepo.save(newItem); + } - if (await this.regionRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'Global', value: 'global', tenantId: resolvedTenantId }, - { label: 'Americas', value: 'americas', tenantId: resolvedTenantId }, - { label: 'Europe', value: 'europe', tenantId: resolvedTenantId }, - { label: 'Middle East', value: 'middle-east', tenantId: resolvedTenantId }, - { label: 'Asia Pacific', value: 'asia-pacific', tenantId: resolvedTenantId }, - { label: 'Africa', value: 'africa', tenantId: resolvedTenantId }, - ]; - await this.regionRepo.save(this.regionRepo.create(data)); + async reorderFieldDefinitions(actionTypeId: string, fieldIds: string[]): Promise { + for (let i = 0; i < fieldIds.length; i++) { + await this.fieldDefinitionRepo.update({ id: fieldIds[i], actionTypeId }, { displayOrder: i + 1 }); } + } - if (await this.tripPurposeRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'Business', value: 'business', tenantId: resolvedTenantId }, - { label: 'Leisure', value: 'leisure', tenantId: resolvedTenantId }, - { label: 'Corporate', value: 'corporate', tenantId: resolvedTenantId }, - { label: 'Government', value: 'government', tenantId: resolvedTenantId }, - ]; - await this.tripPurposeRepo.save(this.tripPurposeRepo.create(data)); + async updateFieldDefinition(id: string, data: UpdateFieldDefinitionDto): Promise { + const item = await this.fieldDefinitionRepo.findOne({ where: { id } }); + if (!item) { + throw new BadRequestException(`Field definition with id ${id} not found`); } + Object.assign(item, data); + return this.fieldDefinitionRepo.save(item); + } - if (await this.cabinClassRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'First Class', value: 'first-class', tenantId: resolvedTenantId }, - { label: 'Business Class', value: 'business-class', tenantId: resolvedTenantId }, - { label: 'Premium Economy', value: 'premium-economy', tenantId: resolvedTenantId }, - { label: 'Economy', value: 'economy', tenantId: resolvedTenantId }, - ]; - await this.cabinClassRepo.save(this.cabinClassRepo.create(data)); + async removeFieldDefinition(id: string): Promise { + const item = await this.fieldDefinitionRepo.findOne({ where: { id } }); + if (!item) { + throw new BadRequestException(`Field definition with id ${id} not found`); } + await this.fieldDefinitionRepo.remove(item); + } - if (await this.passengerTypeRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'Adult', value: 'adult', tenantId: resolvedTenantId }, - { label: 'Child', value: 'child', tenantId: resolvedTenantId }, - { label: 'Infant', value: 'infant', tenantId: resolvedTenantId }, - { label: 'Senior Citizen', value: 'senior', tenantId: resolvedTenantId }, - ]; - await this.passengerTypeRepo.save(this.passengerTypeRepo.create(data)); + // --- Database Seeding --- + async onModuleInit() { + await this.seedData(); + } + + async seedData(): Promise { + try { + const sqlPath = path.join(process.cwd(), 'database', 'seed-master-data.sql'); + if (!fs.existsSync(sqlPath)) { + this.logger.warn(`Seed SQL file not found at ${sqlPath}`); + return; + } + const sql = fs.readFileSync(sqlPath, 'utf8'); + await this.dataSource.query(sql); + this.logger.log('Master data seeded successfully from database/seed-master-data.sql'); + } catch (error) { + this.logger.error('Failed to seed master data from SQL file:', error); } - - if (await this.ancillaryPurchaseRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'Preferred Seat', value: 'preferred-seat', tenantId: resolvedTenantId }, - { label: 'Extra Legroom', value: 'extra-legroom', tenantId: resolvedTenantId }, - { label: 'Wi-Fi', value: 'wi-fi', tenantId: resolvedTenantId }, - { label: 'Lounge Access', value: 'lounge-access', tenantId: resolvedTenantId }, - { label: 'Priority Boarding', value: 'priority-boarding', tenantId: resolvedTenantId }, - { label: 'Fast Track', value: 'fast-track', tenantId: resolvedTenantId }, - { label: 'Paid Meal', value: 'paid-meal', tenantId: resolvedTenantId }, - { label: 'Special Meal', value: 'special-meal', tenantId: resolvedTenantId }, - { label: 'Extra Baggage', value: 'extra-baggage', tenantId: resolvedTenantId }, - { label: 'Upgrade Purchase', value: 'upgrade-purchase', tenantId: resolvedTenantId }, - { label: 'Airport Transfer', value: 'airport-transfer', tenantId: resolvedTenantId }, - { label: 'Chauffeur Service', value: 'chauffeur-service', tenantId: resolvedTenantId }, - { label: 'Sports Equipment', value: 'sports-equipment', tenantId: resolvedTenantId }, - { label: 'Musical Instrument', value: 'musical-instrument', tenantId: resolvedTenantId }, - { label: 'In-flight Entertainment', value: 'in-flight-entertainment', tenantId: resolvedTenantId }, - { label: 'Power Outlet', value: 'power-outlet', tenantId: resolvedTenantId }, - { label: 'Carbon Offset', value: 'carbon-offset', tenantId: resolvedTenantId }, - ]; - await this.ancillaryPurchaseRepo.save(this.ancillaryPurchaseRepo.create(data)); - } - - if (await this.revenueSegmentRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'High Value', value: 'high', tenantId: resolvedTenantId }, - { label: 'Medium Value', value: 'medium', tenantId: resolvedTenantId }, - { label: 'Low Value', value: 'low', tenantId: resolvedTenantId }, - ]; - await this.revenueSegmentRepo.save(this.revenueSegmentRepo.create(data)); - } - - if (await this.jurisdictionRepo.count({ where: { tenantId: resolvedTenantId } }) === 0) { - const data = [ - { label: 'United Arab Emirates', value: 'uae', tenantId: resolvedTenantId }, - { label: 'European Union', value: 'eu', tenantId: resolvedTenantId }, - { label: 'United States', value: 'us', tenantId: resolvedTenantId }, - { label: 'United Kingdom', value: 'uk', tenantId: resolvedTenantId }, - { label: 'India', value: 'india', tenantId: resolvedTenantId }, - { label: 'Asia Pacific', value: 'apac', tenantId: resolvedTenantId }, - { label: 'Global', value: 'global', tenantId: resolvedTenantId }, - ]; - await this.jurisdictionRepo.save(this.jurisdictionRepo.create(data)); - } - - if ( - (await this.ruleCategoryRepo.count({ - where: { tenantId: resolvedTenantId }, - })) === 0 -) { - const categories = [ - { code: 'passenger-type', name: 'Passenger Type', displayOrder: 1 }, - { code: 'cabin-class', name: 'Cabin Class', displayOrder: 2 }, - { code: 'booking-channel', name: 'Booking Channel', displayOrder: 3 }, - { code: 'loyalty-tier', name: 'Loyalty Tier', displayOrder: 4 }, - { code: 'flight-type', name: 'Flight Type', displayOrder: 5 }, - { code: 'journey-type', name: 'Journey Type', displayOrder: 6 }, - { code: 'fare-flexibility', name: 'Fare Flexibility', displayOrder: 7 }, - { code: 'trip-purpose', name: 'Trip Purpose', displayOrder: 8 }, - { code: 'carrier-type', name: 'Carrier Type', displayOrder: 9 }, - { code: 'special-assistance-type', name: 'Special Assistance Type', displayOrder: 10 }, - { code: 'delay-reason', name: 'Delay Reason', displayOrder: 11 }, - { code: 'delay-duration', name: 'Delay Duration', displayOrder: 12 }, - { code: 'extraordinary-circumstances', name: 'Extraordinary Circumstances', displayOrder: 13 }, - { code: 'cancellation-reason', name: 'Cancellation Reason', displayOrder: 14 }, - { code: 'diversion-reason', name: 'Diversion Reason', displayOrder: 15 }, - { code: 'missed-connection-reason', name: 'Missed Connection Reason', displayOrder: 16 }, - { code: 'compensation-eligibility', name: 'Compensation Eligibility', displayOrder: 17 }, - { code: 'compensation-type', name: 'Compensation Type', displayOrder: 18 }, - { code: 'refund-type', name: 'Refund Type', displayOrder: 19 }, - { code: 'flight-disruption-type', name: 'Flight Disruption Type', displayOrder: 20 }, - { code: 'airline-responsibility', name: 'Airline Responsibility', displayOrder: 21 }, - { code: 'weather-condition', name: 'Weather Condition', displayOrder: 22 }, - { code: 'atc-restriction', name: 'ATC Restriction', displayOrder: 23 }, - { code: 'technical-fault-category', name: 'Technical Fault Category', displayOrder: 24 }, - ].map((item) => ({ - ...item, - description: `${item.name} master`, - tenantId: resolvedTenantId, - })); - - await this.ruleCategoryRepo.save(this.ruleCategoryRepo.create(categories)); -} - -if ( - (await this.ruleCategoryValueRepo.count({ - where: { tenantId: resolvedTenantId }, - })) === 0 -) { - const categories = await this.ruleCategoryRepo.find({ - where: { tenantId: resolvedTenantId }, - }); - - const categoryMap = new Map( - categories.map((c) => [c.code, c.id]), - ); - - const masterData = { - 'passenger-type': [ - 'Adult', - 'Child', - 'Infant', - ], - - 'cabin-class': [ - 'Economy', - 'Premium Economy', - 'Business', - 'First', - ], - - 'booking-channel': [ - 'Airline Website', - 'Airline Mobile App', - 'Airport Ticket Counter', - 'Call Center', - 'Corporate Booking Tool', - 'Global Distribution System', - 'Online Travel Agency', - 'Travel Agent', - ], - - 'loyalty-tier': [ - 'Basic', - 'Silver', - 'Gold', - 'Platinum', - 'Diamond', - 'Elite', - 'Lifetime', - ], - - 'flight-type': [ - 'Domestic', - 'International', - ], - - 'journey-type': [ - 'One Way', - 'Round Trip', - 'Multi City', - ], - - 'fare-flexibility': [ - 'Non Refundable', - 'Partially Refundable', - 'Refundable', - 'Exchangeable', - 'Non Changeable', - ], - - 'trip-purpose': [ - 'Business', - 'Leisure', - 'Medical', - 'Education', - 'Government', - 'Military', - 'Religious', - 'Transit', - ], - - 'carrier-type': [ - 'Operating Carrier', - 'Marketing Carrier', - 'Partner Carrier', - 'Regional Carrier', - 'Low Cost Carrier', - 'Full Service Carrier', - 'Charter Carrier', - ], - - 'special-assistance-type': [ - 'Wheelchair Assistance', - 'Wheelchair Ramp', - 'Wheelchair Steps', - 'Wheelchair Cabin', - 'Blind Passenger', - 'Deaf Passenger', - 'Medical Assistance', - 'Oxygen Required', - 'Stretcher', - 'Unaccompanied Minor', - 'Service Animal', - 'Pregnant Passenger', - 'Elderly Passenger', - 'Other', - ], - - 'delay-reason': [ - 'Air Traffic Control Restriction', - 'Aircraft Rotation', - 'Airport Congestion', - 'Crew Availability', - 'Customs Delay', - 'Fueling Delay', - 'Late Arrival of Aircraft', - 'Operational Decision', - 'Passenger Handling', - 'Runway Closure', - 'Security', - 'Severe Weather', - 'Technical Fault', - 'Other', - ], - - 'delay-duration': [ - 'Less than 1 Hour', - '1-2 Hours', - '2-3 Hours', - '3-4 Hours', - 'More than 4 Hours', - ], - - 'extraordinary-circumstances': [ - 'Air Traffic Management Decision', - 'Airport Closure', - 'Bird Strike', - 'Civil Unrest', - 'Medical Emergency', - 'Political Instability', - 'Security Threat', - 'Severe Weather', - 'Strike (External)', - 'War', - 'Other', - ], - - 'cancellation-reason': [ - 'Air Traffic Control Restriction', - 'Airport Closure', - 'Commercial Decision', - 'Crew Availability', - 'Operational Decision', - 'Overbooking', - 'Security', - 'Severe Weather', - 'Strike', - 'Technical Fault', - ], - - 'diversion-reason': [ - 'Airport Closure', - 'Destination Weather', - 'Fuel Emergency', - 'Medical Emergency', - 'Runway Obstruction', - 'Security Threat', - 'Technical Fault', - ], - - 'missed-connection-reason': [ - 'Customs Delay', - 'Flight Delay', - 'Immigration Delay', - 'Passenger Delay', - 'Security Screening Delay', - ], - - 'compensation-eligibility': [ - 'Eligible', - 'Not Eligible', - 'Requires Manual Review', - ], - - 'compensation-type': [ - 'Cash', - 'Cheque', - 'Flight Voucher', - 'Loyalty Miles', - 'Meal Voucher', - 'Hotel Accommodation', - 'Ground Transport', - ], - - 'refund-type': [ - 'Full Refund', - 'Partial Refund', - 'Future Travel Credit', - 'Travel Voucher', - 'Tax Refund Only', - 'Telephone Reimbursement', - ], - - 'flight-disruption-type': [ - 'Cancellation', - 'Delay', - 'Denied Boarding', - 'Diversion', - 'Missed Connection', - ], - - 'airline-responsibility': [ - 'Airline Responsible', - 'Airport Responsible', - 'ATC Responsible', - 'Passenger Responsible', - 'Shared Responsibility', - 'Third Party Responsible', - 'Snow', - ], - - 'weather-condition': [ - 'Fog', - 'Heavy Rain', - 'Hurricane', - 'Ice', - 'Lightning', - 'Sandstorm', - 'Thunderstorm', - ], - - 'atc-restriction': [ - 'Airspace Closure', - 'Flow Control', - 'Ground Stop', - 'Slot Restriction', - 'Traffic Congestion', - 'Navigation System', - ], - - 'technical-fault-category': [ - 'Aircraft Damage', - 'Avionics', - 'Cabin Systems', - 'Engine', - 'Hydraulic System', - 'Landing Gear', - 'Volcanic Ash', - 'Wind Shear', - ], - }; - - const values = Object.entries(masterData).flatMap(([categoryCode, items]) => - items.map((value, index) => ({ - categoryId: categoryMap.get(categoryCode), - code: value.toLowerCase().replace(/[^a-z0-9]+/g, '-'), - value, - tenantId: resolvedTenantId, - displayOrder: index + 1, - })), - ); - - await this.ruleCategoryValueRepo.save( - this.ruleCategoryValueRepo.create(values), - ); -} - - if ((await this.operatorRepo.count({ where: { tenantId: resolvedTenantId } })) === 0) { - const operators = [ - { code: 'EQ', name: 'Equals', symbol: '=', displayOrder: 1 }, - { code: 'NE', name: 'Not Equals', symbol: '!=', displayOrder: 2 }, - { code: 'GT', name: 'Greater Than', symbol: '>', displayOrder: 3 }, - { code: 'GTE', name: 'Greater Than or Equal', symbol: '>=', displayOrder: 4 }, - { code: 'LT', name: 'Less Than', symbol: '<', displayOrder: 5 }, - { code: 'LTE', name: 'Less Than or Equal', symbol: '<=', displayOrder: 6 }, - { code: 'BETWEEN', name: 'Between', symbol: 'BETWEEN', displayOrder: 7 }, - { code: 'CONTAINS', name: 'Contains', symbol: 'CONTAINS', displayOrder: 8 }, - { code: 'IN', name: 'In', symbol: 'IN', displayOrder: 9 }, - { code: 'IS_EMPTY', name: 'Is Empty', symbol: 'IS EMPTY', displayOrder: 10 }, - ].map((item) => ({ ...item, tenantId: resolvedTenantId })); - - await this.operatorRepo.save(this.operatorRepo.create(operators)); - } - - this.logger.log(`Master data seeded for tenant ${resolvedTenantId}`); } }