608 lines
22 KiB
PL/PgSQL
608 lines
22 KiB
PL/PgSQL
-- Shared booking facts + Finance processing persistence schema v1.1
|
|
-- PostgreSQL 15+
|
|
-- Target database: booking_test (connect to that database before running).
|
|
-- REVIEW DRAFT ONLY: this file has not been executed against any database.
|
|
|
|
BEGIN;
|
|
|
|
CREATE SCHEMA booking;
|
|
CREATE SCHEMA finance;
|
|
|
|
COMMENT ON SCHEMA booking IS
|
|
'Shared simulated booking attachment inputs, Agent parse versions, and current booking facts.';
|
|
|
|
COMMENT ON SCHEMA finance IS
|
|
'Finance-owned Opera daily facts and report-version lineage derived from shared booking facts.';
|
|
|
|
CREATE TABLE booking.file_objects (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
file_kind text NOT NULL CHECK (file_kind IN (
|
|
'booking_excel',
|
|
'opera_xml',
|
|
'daily_xlsx',
|
|
'monthly_xlsx',
|
|
'company_ten_day_xlsx',
|
|
'exception_xlsx',
|
|
'result_json'
|
|
)),
|
|
original_filename text NOT NULL CHECK (btrim(original_filename) <> ''),
|
|
storage_key text NOT NULL UNIQUE,
|
|
sha256 character(64) NOT NULL CHECK (sha256 ~ '^[0-9a-f]{64}$'),
|
|
byte_size bigint NOT NULL CHECK (byte_size >= 0),
|
|
mime_type text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
CONSTRAINT file_objects_storage_key_is_relative CHECK (
|
|
storage_key !~ '^/'
|
|
AND storage_key !~ '(^|/)\.\.(/|$)'
|
|
),
|
|
CONSTRAINT file_objects_kind_hash_unique UNIQUE (file_kind, sha256)
|
|
);
|
|
|
|
CREATE TABLE booking.booking_imports (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
source_file_id bigint NOT NULL UNIQUE
|
|
REFERENCES booking.file_objects(id),
|
|
source_sheet_name text NOT NULL CHECK (btrim(source_sheet_name) <> ''),
|
|
import_status text NOT NULL CHECK (import_status IN (
|
|
'processing', 'accepted', 'failed'
|
|
)),
|
|
source_rows integer NOT NULL DEFAULT 0 CHECK (source_rows >= 0),
|
|
accepted_rows integer NOT NULL DEFAULT 0 CHECK (accepted_rows >= 0),
|
|
failed_rows integer NOT NULL DEFAULT 0 CHECK (failed_rows >= 0),
|
|
failure_code text,
|
|
failure_message text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
finished_at timestamptz,
|
|
CONSTRAINT booking_import_counts_valid CHECK (
|
|
accepted_rows + failed_rows <= source_rows
|
|
),
|
|
CONSTRAINT booking_import_failure_shape CHECK (
|
|
(import_status = 'failed' AND failure_code IS NOT NULL)
|
|
OR (import_status <> 'failed')
|
|
)
|
|
);
|
|
|
|
CREATE TABLE booking.booking_source_rows (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
import_id bigint NOT NULL
|
|
REFERENCES booking.booking_imports(id),
|
|
source_row_no integer NOT NULL CHECK (source_row_no > 0),
|
|
tour_code_raw text NOT NULL CHECK (btrim(tour_code_raw) <> ''),
|
|
group_code_key text GENERATED ALWAYS AS (upper(btrim(tour_code_raw))) STORED,
|
|
hotel_raw text NOT NULL CHECK (btrim(hotel_raw) <> ''),
|
|
row_sha256 character(64) NOT NULL CHECK (row_sha256 ~ '^[0-9a-f]{64}$'),
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
CONSTRAINT booking_source_rows_position_unique
|
|
UNIQUE (import_id, source_row_no),
|
|
CONSTRAINT booking_source_rows_group_unique
|
|
UNIQUE (import_id, group_code_key),
|
|
CONSTRAINT booking_source_rows_hash_unique
|
|
UNIQUE (import_id, row_sha256),
|
|
CONSTRAINT booking_source_rows_id_group_unique
|
|
UNIQUE (id, group_code_key)
|
|
);
|
|
|
|
CREATE INDEX booking_source_rows_group_idx
|
|
ON booking.booking_source_rows (group_code_key);
|
|
|
|
CREATE TABLE booking.booking_parse_versions (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
source_row_id bigint NOT NULL,
|
|
group_code_key text NOT NULL CHECK (
|
|
group_code_key = upper(btrim(group_code_key))
|
|
AND group_code_key <> ''
|
|
),
|
|
version_no integer NOT NULL CHECK (version_no > 0),
|
|
parse_status text NOT NULL CHECK (parse_status IN (
|
|
'accepted', 'needs_review', 'failed'
|
|
)),
|
|
booking_state text NOT NULL DEFAULT 'active' CHECK (booking_state IN (
|
|
'active', 'cancelled'
|
|
)),
|
|
agent_name text NOT NULL CHECK (btrim(agent_name) <> ''),
|
|
agent_version text NOT NULL CHECK (btrim(agent_version) <> ''),
|
|
result_sha256 character(64) CHECK (
|
|
result_sha256 IS NULL OR result_sha256 ~ '^[0-9a-f]{64}$'
|
|
),
|
|
result_json jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
failure_code text,
|
|
failure_message text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
validated_at timestamptz,
|
|
CONSTRAINT booking_parse_version_unique
|
|
UNIQUE (group_code_key, version_no),
|
|
CONSTRAINT booking_parse_id_group_unique
|
|
UNIQUE (id, group_code_key),
|
|
CONSTRAINT booking_parse_source_group_fk
|
|
FOREIGN KEY (source_row_id, group_code_key)
|
|
REFERENCES booking.booking_source_rows(id, group_code_key),
|
|
CONSTRAINT booking_parse_status_shape CHECK (
|
|
(parse_status = 'accepted'
|
|
AND result_sha256 IS NOT NULL
|
|
AND validated_at IS NOT NULL
|
|
AND failure_code IS NULL)
|
|
OR (parse_status = 'needs_review')
|
|
OR (parse_status = 'failed' AND failure_code IS NOT NULL)
|
|
)
|
|
);
|
|
|
|
CREATE INDEX booking_parse_versions_source_row_idx
|
|
ON booking.booking_parse_versions (source_row_id);
|
|
|
|
CREATE TABLE booking.booking_stays (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
parse_version_id bigint NOT NULL
|
|
REFERENCES booking.booking_parse_versions(id),
|
|
segment_no integer NOT NULL CHECK (segment_no > 0),
|
|
arrival_date date NOT NULL,
|
|
departure_date date NOT NULL,
|
|
nights integer GENERATED ALWAYS AS (departure_date - arrival_date) STORED,
|
|
source_fragment text,
|
|
CONSTRAINT booking_stays_dates_valid CHECK (departure_date > arrival_date),
|
|
CONSTRAINT booking_stays_segment_unique
|
|
UNIQUE (parse_version_id, segment_no)
|
|
);
|
|
|
|
CREATE INDEX booking_stays_dates_idx
|
|
ON booking.booking_stays (arrival_date, departure_date);
|
|
|
|
CREATE TABLE booking.booking_room_items (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
stay_id bigint NOT NULL
|
|
REFERENCES booking.booking_stays(id),
|
|
item_no integer NOT NULL CHECK (item_no > 0),
|
|
room_type_raw text NOT NULL CHECK (btrim(room_type_raw) <> ''),
|
|
room_type_code text NOT NULL CHECK (btrim(room_type_code) <> ''),
|
|
quantity integer NOT NULL CHECK (quantity > 0),
|
|
unit_price numeric(18,2) CHECK (unit_price IS NULL OR unit_price >= 0),
|
|
price_token_raw text,
|
|
source_fragment text,
|
|
CONSTRAINT booking_room_items_position_unique
|
|
UNIQUE (stay_id, item_no)
|
|
);
|
|
|
|
CREATE INDEX booking_room_items_type_idx
|
|
ON booking.booking_room_items (room_type_code);
|
|
|
|
CREATE TABLE booking.current_group_bookings (
|
|
group_code_key text PRIMARY KEY CHECK (
|
|
group_code_key = upper(btrim(group_code_key))
|
|
AND group_code_key <> ''
|
|
),
|
|
parse_version_id bigint NOT NULL,
|
|
activated_at timestamptz NOT NULL DEFAULT now(),
|
|
CONSTRAINT current_group_booking_parse_fk
|
|
FOREIGN KEY (parse_version_id, group_code_key)
|
|
REFERENCES booking.booking_parse_versions(id, group_code_key)
|
|
);
|
|
|
|
CREATE OR REPLACE FUNCTION booking.validate_current_group_booking()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1
|
|
FROM booking.booking_parse_versions AS parsed
|
|
WHERE parsed.id = NEW.parse_version_id
|
|
AND parsed.group_code_key = NEW.group_code_key
|
|
AND parsed.parse_status = 'accepted'
|
|
) THEN
|
|
RAISE EXCEPTION
|
|
'current Group Code must reference an accepted parse version';
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
CREATE TRIGGER current_group_booking_acceptance_guard
|
|
BEFORE INSERT OR UPDATE ON booking.current_group_bookings
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION booking.validate_current_group_booking();
|
|
|
|
CREATE TABLE finance.daily_versions (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
business_date date,
|
|
version_no integer,
|
|
source_file_id bigint NOT NULL
|
|
REFERENCES booking.file_objects(id),
|
|
version_status text NOT NULL CHECK (version_status IN (
|
|
'processing', 'failed', 'validated', 'active', 'superseded'
|
|
)),
|
|
processor_version text NOT NULL CHECK (btrim(processor_version) <> ''),
|
|
rule_set_sha256 character(64) CHECK (
|
|
rule_set_sha256 IS NULL OR rule_set_sha256 ~ '^[0-9a-f]{64}$'
|
|
),
|
|
result_schema_version text NOT NULL DEFAULT '1.0',
|
|
source_rows integer NOT NULL DEFAULT 0 CHECK (source_rows >= 0),
|
|
removed_by_rate_code integer NOT NULL DEFAULT 0
|
|
CHECK (removed_by_rate_code >= 0),
|
|
removed_as_duplicates integer NOT NULL DEFAULT 0
|
|
CHECK (removed_as_duplicates >= 0),
|
|
output_rows integer NOT NULL DEFAULT 0 CHECK (output_rows >= 0),
|
|
daily_report_file_id bigint REFERENCES booking.file_objects(id),
|
|
result_json_file_id bigint REFERENCES booking.file_objects(id),
|
|
exception_report_file_id bigint REFERENCES booking.file_objects(id),
|
|
failure_code text,
|
|
failure_message text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
validated_at timestamptz,
|
|
activated_at timestamptz,
|
|
superseded_at timestamptz,
|
|
CONSTRAINT daily_version_date_number_shape CHECK (
|
|
(business_date IS NULL AND version_no IS NULL)
|
|
OR (business_date IS NOT NULL AND version_no > 0)
|
|
),
|
|
CONSTRAINT daily_version_business_version_unique
|
|
UNIQUE (business_date, version_no),
|
|
CONSTRAINT daily_version_id_date_unique
|
|
UNIQUE (id, business_date),
|
|
CONSTRAINT daily_version_success_counts CHECK (
|
|
version_status NOT IN ('validated', 'active', 'superseded')
|
|
OR source_rows = removed_by_rate_code + removed_as_duplicates + output_rows
|
|
),
|
|
CONSTRAINT daily_version_active_shape CHECK (
|
|
version_status <> 'active'
|
|
OR (
|
|
business_date IS NOT NULL
|
|
AND validated_at IS NOT NULL
|
|
AND activated_at IS NOT NULL
|
|
AND daily_report_file_id IS NOT NULL
|
|
AND result_json_file_id IS NOT NULL
|
|
AND failure_code IS NULL
|
|
)
|
|
),
|
|
CONSTRAINT daily_version_failed_shape CHECK (
|
|
version_status <> 'failed' OR failure_code IS NOT NULL
|
|
)
|
|
);
|
|
|
|
CREATE INDEX daily_versions_business_date_idx
|
|
ON finance.daily_versions (business_date, version_no DESC);
|
|
|
|
CREATE TABLE finance.daily_records (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
daily_version_id bigint NOT NULL
|
|
REFERENCES finance.daily_versions(id),
|
|
source_sequence integer NOT NULL CHECK (source_sequence > 0),
|
|
source_location text,
|
|
outcome text NOT NULL CHECK (outcome IN (
|
|
'retained',
|
|
'excluded_rate_code',
|
|
'duplicate',
|
|
'validation_failed',
|
|
'price_unmatched'
|
|
)),
|
|
decision_codes text[] NOT NULL DEFAULT ARRAY[]::text[],
|
|
duplicate_of_record_id bigint,
|
|
|
|
block_code text,
|
|
group_code_key text CHECK (
|
|
group_code_key IS NULL
|
|
OR (
|
|
group_code_key = upper(btrim(group_code_key))
|
|
AND group_code_key <> ''
|
|
)
|
|
),
|
|
adults integer,
|
|
children integer,
|
|
company_name text,
|
|
company_key text,
|
|
confirmation_no text,
|
|
disp_room_no text,
|
|
effective_rate_amount numeric(18,2),
|
|
full_name text,
|
|
res_comment text,
|
|
trace_text text,
|
|
no_of_rooms integer,
|
|
products text,
|
|
rate_code text,
|
|
normalized_rate_code text,
|
|
room_category_label text,
|
|
arrival date,
|
|
departure date,
|
|
nights integer,
|
|
real_price numeric(18,2),
|
|
total_price numeric(18,2),
|
|
kb_amount numeric(18,2),
|
|
channel_key text,
|
|
pricing_method text,
|
|
|
|
booking_parse_version_id bigint,
|
|
booking_match_status text NOT NULL DEFAULT 'not_required'
|
|
CHECK (booking_match_status IN (
|
|
'matched',
|
|
'unmatched',
|
|
'parse_failed',
|
|
'missing_group_code',
|
|
'not_required'
|
|
)),
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
|
|
CONSTRAINT daily_records_source_unique
|
|
UNIQUE (daily_version_id, source_sequence),
|
|
CONSTRAINT daily_records_id_version_unique
|
|
UNIQUE (id, daily_version_id),
|
|
CONSTRAINT daily_records_duplicate_version_fk
|
|
FOREIGN KEY (duplicate_of_record_id, daily_version_id)
|
|
REFERENCES finance.daily_records(id, daily_version_id),
|
|
CONSTRAINT daily_records_booking_group_fk
|
|
FOREIGN KEY (booking_parse_version_id, group_code_key)
|
|
REFERENCES booking.booking_parse_versions(id, group_code_key),
|
|
CONSTRAINT daily_records_people_valid CHECK (
|
|
(adults IS NULL OR adults >= 0)
|
|
AND (children IS NULL OR children >= 0)
|
|
),
|
|
CONSTRAINT daily_records_room_count_valid CHECK (
|
|
no_of_rooms IS NULL OR no_of_rooms > 0
|
|
),
|
|
CONSTRAINT daily_records_retained_shape CHECK (
|
|
outcome <> 'retained'
|
|
OR (
|
|
rate_code IS NOT NULL
|
|
AND btrim(rate_code) <> ''
|
|
AND normalized_rate_code IS NOT NULL
|
|
AND btrim(normalized_rate_code) <> ''
|
|
AND company_name IS NOT NULL
|
|
AND btrim(company_name) <> ''
|
|
AND company_key IS NOT NULL
|
|
AND btrim(company_key) <> ''
|
|
AND confirmation_no IS NOT NULL
|
|
AND btrim(confirmation_no) <> ''
|
|
AND disp_room_no IS NOT NULL
|
|
AND btrim(disp_room_no) <> ''
|
|
AND effective_rate_amount IS NOT NULL
|
|
AND effective_rate_amount >= 0
|
|
AND full_name IS NOT NULL
|
|
AND btrim(full_name) <> ''
|
|
AND adults IS NOT NULL
|
|
AND children IS NOT NULL
|
|
AND no_of_rooms IS NOT NULL
|
|
AND arrival IS NOT NULL
|
|
AND departure IS NOT NULL
|
|
AND nights IS NOT NULL
|
|
AND real_price IS NOT NULL
|
|
AND real_price >= 0
|
|
AND total_price IS NOT NULL
|
|
AND total_price >= 0
|
|
AND channel_key IS NOT NULL
|
|
AND btrim(channel_key) <> ''
|
|
AND pricing_method IS NOT NULL
|
|
AND btrim(pricing_method) <> ''
|
|
)
|
|
),
|
|
CONSTRAINT daily_records_dates_and_nights_valid CHECK (
|
|
arrival IS NULL
|
|
OR departure IS NULL
|
|
OR nights IS NULL
|
|
OR (
|
|
departure > arrival
|
|
AND nights = departure - arrival
|
|
)
|
|
),
|
|
CONSTRAINT daily_records_total_valid CHECK (
|
|
real_price IS NULL
|
|
OR no_of_rooms IS NULL
|
|
OR nights IS NULL
|
|
OR total_price IS NULL
|
|
OR total_price = real_price * no_of_rooms * nights
|
|
),
|
|
CONSTRAINT daily_records_kb_valid CHECK (
|
|
kb_amount IS NULL
|
|
OR no_of_rooms IS NULL
|
|
OR kb_amount = no_of_rooms * 100
|
|
),
|
|
CONSTRAINT daily_records_duplicate_shape CHECK (
|
|
(outcome = 'duplicate' AND duplicate_of_record_id IS NOT NULL)
|
|
OR (outcome <> 'duplicate' AND duplicate_of_record_id IS NULL)
|
|
),
|
|
CONSTRAINT daily_records_booking_match_shape CHECK (
|
|
(booking_match_status = 'matched'
|
|
AND group_code_key IS NOT NULL
|
|
AND booking_parse_version_id IS NOT NULL)
|
|
OR (booking_match_status = 'unmatched'
|
|
AND group_code_key IS NOT NULL
|
|
AND booking_parse_version_id IS NULL)
|
|
OR (booking_match_status = 'parse_failed'
|
|
AND group_code_key IS NOT NULL)
|
|
OR (booking_match_status = 'missing_group_code'
|
|
AND group_code_key IS NULL
|
|
AND booking_parse_version_id IS NULL)
|
|
OR (booking_match_status = 'not_required'
|
|
AND booking_parse_version_id IS NULL)
|
|
)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX daily_records_retained_dedupe_key
|
|
ON finance.daily_records (daily_version_id, disp_room_no, arrival)
|
|
WHERE outcome = 'retained';
|
|
|
|
CREATE INDEX daily_records_group_code_idx
|
|
ON finance.daily_records (group_code_key);
|
|
|
|
CREATE INDEX daily_records_company_date_idx
|
|
ON finance.daily_records (company_key, arrival);
|
|
|
|
CREATE INDEX daily_records_version_outcome_idx
|
|
ON finance.daily_records (daily_version_id, outcome);
|
|
|
|
CREATE TABLE finance.daily_channel_metrics (
|
|
daily_version_id bigint NOT NULL
|
|
REFERENCES finance.daily_versions(id),
|
|
worksheet text NOT NULL CHECK (btrim(worksheet) <> ''),
|
|
row_count integer NOT NULL CHECK (row_count >= 0),
|
|
PRIMARY KEY (daily_version_id, worksheet)
|
|
);
|
|
|
|
CREATE TABLE finance.current_daily_versions (
|
|
business_date date PRIMARY KEY,
|
|
daily_version_id bigint NOT NULL,
|
|
activated_at timestamptz NOT NULL DEFAULT now(),
|
|
CONSTRAINT current_daily_version_fk
|
|
FOREIGN KEY (daily_version_id, business_date)
|
|
REFERENCES finance.daily_versions(id, business_date)
|
|
);
|
|
|
|
CREATE OR REPLACE FUNCTION finance.validate_current_daily_version()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1
|
|
FROM finance.daily_versions AS version
|
|
WHERE version.id = NEW.daily_version_id
|
|
AND version.business_date = NEW.business_date
|
|
AND version.version_status = 'active'
|
|
) THEN
|
|
RAISE EXCEPTION
|
|
'current business date must reference an active daily version';
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
CREATE TRIGGER current_daily_version_active_guard
|
|
BEFORE INSERT OR UPDATE ON finance.current_daily_versions
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION finance.validate_current_daily_version();
|
|
|
|
CREATE TABLE finance.report_versions (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
report_kind text NOT NULL CHECK (report_kind IN (
|
|
'monthly_channel', 'company_ten_day'
|
|
)),
|
|
period_start date NOT NULL,
|
|
period_end date NOT NULL,
|
|
company_scope text NOT NULL DEFAULT '*',
|
|
version_no integer NOT NULL CHECK (version_no > 0),
|
|
report_status text NOT NULL CHECK (report_status IN (
|
|
'generating', 'failed', 'validated', 'active', 'superseded'
|
|
)),
|
|
artifact_file_id bigint REFERENCES booking.file_objects(id),
|
|
result_json_file_id bigint REFERENCES booking.file_objects(id),
|
|
is_current boolean NOT NULL DEFAULT false,
|
|
failure_code text,
|
|
failure_message text,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
validated_at timestamptz,
|
|
activated_at timestamptz,
|
|
superseded_at timestamptz,
|
|
CONSTRAINT report_period_valid CHECK (period_end >= period_start),
|
|
CONSTRAINT report_version_scope_unique UNIQUE (
|
|
report_kind, period_start, period_end, company_scope, version_no
|
|
),
|
|
CONSTRAINT report_current_shape CHECK (
|
|
NOT is_current
|
|
OR (
|
|
report_status = 'active'
|
|
AND artifact_file_id IS NOT NULL
|
|
AND validated_at IS NOT NULL
|
|
AND activated_at IS NOT NULL
|
|
AND failure_code IS NULL
|
|
)
|
|
),
|
|
CONSTRAINT report_failed_shape CHECK (
|
|
report_status <> 'failed' OR failure_code IS NOT NULL
|
|
)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX report_versions_one_current_scope
|
|
ON finance.report_versions (
|
|
report_kind, period_start, period_end, company_scope
|
|
)
|
|
WHERE is_current;
|
|
|
|
CREATE TABLE finance.report_daily_versions (
|
|
report_version_id bigint NOT NULL
|
|
REFERENCES finance.report_versions(id),
|
|
business_date date NOT NULL,
|
|
daily_version_id bigint NOT NULL,
|
|
PRIMARY KEY (report_version_id, business_date),
|
|
CONSTRAINT report_daily_version_fk
|
|
FOREIGN KEY (daily_version_id, business_date)
|
|
REFERENCES finance.daily_versions(id, business_date)
|
|
);
|
|
|
|
CREATE TABLE finance.report_booking_versions (
|
|
report_version_id bigint NOT NULL
|
|
REFERENCES finance.report_versions(id),
|
|
group_code_key text NOT NULL,
|
|
booking_parse_version_id bigint NOT NULL,
|
|
PRIMARY KEY (report_version_id, group_code_key),
|
|
CONSTRAINT report_booking_version_fk
|
|
FOREIGN KEY (booking_parse_version_id, group_code_key)
|
|
REFERENCES booking.booking_parse_versions(id, group_code_key)
|
|
);
|
|
|
|
CREATE VIEW booking.v_current_group_room_items AS
|
|
SELECT
|
|
current_booking.group_code_key,
|
|
source_row.tour_code_raw,
|
|
parsed.id AS parse_version_id,
|
|
parsed.version_no AS parse_version_no,
|
|
parsed.booking_state,
|
|
source_row.import_id,
|
|
source_row.source_row_no,
|
|
stay.segment_no,
|
|
stay.arrival_date,
|
|
stay.departure_date,
|
|
stay.nights,
|
|
room.item_no,
|
|
room.room_type_raw,
|
|
room.room_type_code,
|
|
room.quantity,
|
|
room.unit_price,
|
|
room.price_token_raw
|
|
FROM booking.current_group_bookings AS current_booking
|
|
JOIN booking.booking_parse_versions AS parsed
|
|
ON parsed.id = current_booking.parse_version_id
|
|
JOIN booking.booking_source_rows AS source_row
|
|
ON source_row.id = parsed.source_row_id
|
|
JOIN booking.booking_stays AS stay
|
|
ON stay.parse_version_id = parsed.id
|
|
JOIN booking.booking_room_items AS room
|
|
ON room.stay_id = stay.id;
|
|
|
|
CREATE VIEW finance.v_active_daily_facts AS
|
|
SELECT records.*
|
|
FROM finance.current_daily_versions AS current_version
|
|
JOIN finance.daily_records AS records
|
|
ON records.daily_version_id = current_version.daily_version_id
|
|
WHERE records.outcome = 'retained';
|
|
|
|
CREATE VIEW finance.v_company_report_source AS
|
|
SELECT
|
|
current_version.business_date,
|
|
records.id AS daily_record_id,
|
|
records.channel_key,
|
|
records.company_key,
|
|
records.company_name,
|
|
records.block_code,
|
|
records.group_code_key,
|
|
records.res_comment,
|
|
records.room_category_label AS type_of_room,
|
|
records.no_of_rooms AS actual_room_quantity,
|
|
records.arrival,
|
|
records.departure,
|
|
records.nights,
|
|
records.real_price,
|
|
records.total_price,
|
|
records.booking_parse_version_id,
|
|
records.booking_match_status
|
|
FROM finance.current_daily_versions AS current_version
|
|
JOIN finance.daily_records AS records
|
|
ON records.daily_version_id = current_version.daily_version_id
|
|
WHERE records.outcome = 'retained';
|
|
|
|
COMMENT ON VIEW booking.v_current_group_room_items IS
|
|
'Exact Group Code lookup source for Agent-formatted original room information.';
|
|
|
|
COMMENT ON VIEW finance.v_active_daily_facts IS
|
|
'Only retained rows from each business date current active daily version.';
|
|
|
|
COMMENT ON VIEW finance.v_company_report_source IS
|
|
'Privacy-minimized daily facts used to build company ten-day room reports.';
|
|
|
|
COMMIT;
|