feat: add daily manual price review workflow
This commit is contained in:
172
database/017_daily_price_review.down.sql
Normal file
172
database/017_daily_price_review.down.sql
Normal file
@@ -0,0 +1,172 @@
|
||||
-- Protected rollback for migration 017. It deliberately refuses to discard any
|
||||
-- review/audit/manual-price fact; use a forward corrective migration instead.
|
||||
|
||||
BEGIN;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF current_database() <> 'booking_test' THEN
|
||||
RAISE EXCEPTION 'ARR daily price review rollback is allowed only in booking_test';
|
||||
END IF;
|
||||
IF to_regclass('ingestion.daily_review_cases') IS NULL THEN
|
||||
RAISE EXCEPTION 'ARR daily price review migration is not applied';
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM ingestion.daily_review_cases)
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM finance.daily_versions
|
||||
WHERE review_case_id IS NOT NULL
|
||||
OR manual_override_sha256 IS NOT NULL
|
||||
OR manually_priced_rows <> 0
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM ingestion.processing_runs WHERE run_status = 'awaiting_review'
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM ingestion.processing_attempts WHERE attempt_status = 'review_required'
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM ingestion.processing_deliveries
|
||||
WHERE delivery_status = 'recorded_review' OR result_status = 'review_required'
|
||||
) THEN
|
||||
RAISE EXCEPTION
|
||||
'refusing destructive rollback: daily review or manual-pricing facts exist';
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regrole('arr_app') IS NOT NULL THEN
|
||||
EXECUTE 'REVOKE SELECT, INSERT, UPDATE ON ingestion.daily_review_cases, ingestion.daily_review_items, ingestion.daily_review_events FROM arr_app';
|
||||
EXECUTE 'REVOKE USAGE, SELECT ON SEQUENCE ingestion.daily_review_cases_id_seq, ingestion.daily_review_items_id_seq, ingestion.daily_review_events_id_seq FROM arr_app';
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
ALTER TABLE finance.daily_versions
|
||||
DROP CONSTRAINT IF EXISTS daily_versions_review_lineage_shape;
|
||||
DROP INDEX IF EXISTS finance.daily_versions_review_case_unique;
|
||||
DROP INDEX IF EXISTS finance.daily_versions_source_rule_override_unique;
|
||||
ALTER TABLE finance.daily_versions
|
||||
DROP COLUMN manually_priced_rows,
|
||||
DROP COLUMN manual_override_sha256,
|
||||
DROP COLUMN review_case_id;
|
||||
|
||||
CREATE UNIQUE INDEX daily_versions_source_rule_unique
|
||||
ON finance.daily_versions (
|
||||
source_artifact_id,
|
||||
business_date,
|
||||
processor_version,
|
||||
rule_set_sha256
|
||||
)
|
||||
WHERE business_date IS NOT NULL;
|
||||
|
||||
ALTER TABLE finance.daily_records
|
||||
DROP CONSTRAINT IF EXISTS daily_records_retained_values;
|
||||
ALTER TABLE finance.daily_records
|
||||
ADD CONSTRAINT daily_records_retained_values CHECK (
|
||||
outcome <> 'retained'
|
||||
OR (
|
||||
block_code IS NOT NULL
|
||||
AND adults IS NOT NULL AND adults >= 0
|
||||
AND children IS NOT NULL AND children >= 0
|
||||
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 no_of_rooms IS NOT NULL AND no_of_rooms > 0
|
||||
AND rate_code IS NOT NULL
|
||||
AND normalized_rate_code IS NOT NULL
|
||||
AND arrival IS NOT NULL
|
||||
AND departure IS NOT NULL
|
||||
AND nights IS NOT NULL AND nights >= 0
|
||||
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 IN ('price_reference_exact', 'zero_price_exception')
|
||||
)
|
||||
);
|
||||
|
||||
ALTER TABLE ingestion.processing_deliveries
|
||||
DROP CONSTRAINT IF EXISTS processing_deliveries_review_case_fk,
|
||||
DROP COLUMN review_case_id,
|
||||
DROP COLUMN manual_override_artifact_id;
|
||||
|
||||
DROP TRIGGER IF EXISTS daily_review_items_mutability_guard ON ingestion.daily_review_items;
|
||||
DROP TRIGGER IF EXISTS daily_review_cases_immutability_guard ON ingestion.daily_review_cases;
|
||||
DROP TRIGGER IF EXISTS daily_review_events_immutability_guard ON ingestion.daily_review_events;
|
||||
DROP FUNCTION IF EXISTS ingestion.enforce_daily_review_item_mutability();
|
||||
DROP FUNCTION IF EXISTS ingestion.enforce_daily_review_case_immutability();
|
||||
DROP FUNCTION IF EXISTS ingestion.enforce_daily_review_event_immutability();
|
||||
DROP TABLE ingestion.daily_review_events;
|
||||
DROP TABLE ingestion.daily_review_items;
|
||||
DROP TABLE ingestion.daily_review_cases;
|
||||
|
||||
ALTER TABLE ingestion.processing_deliveries
|
||||
DROP CONSTRAINT IF EXISTS processing_deliveries_delivery_status_check,
|
||||
DROP CONSTRAINT IF EXISTS processing_deliveries_result_status_check;
|
||||
ALTER TABLE ingestion.processing_deliveries
|
||||
ADD CONSTRAINT processing_deliveries_delivery_status_check CHECK (delivery_status IN (
|
||||
'received', 'validating', 'committed', 'recorded_failure', 'rejected'
|
||||
)),
|
||||
ADD CONSTRAINT processing_deliveries_result_status_check CHECK (result_status IN (
|
||||
'success', 'failed'
|
||||
));
|
||||
|
||||
ALTER TABLE ingestion.processing_attempts
|
||||
DROP CONSTRAINT IF EXISTS processing_attempts_attempt_status_check,
|
||||
DROP CONSTRAINT IF EXISTS processing_attempts_terminal_shape;
|
||||
ALTER TABLE ingestion.processing_attempts
|
||||
ADD CONSTRAINT processing_attempts_attempt_status_check CHECK (attempt_status IN (
|
||||
'queued', 'dispatched', 'running', 'delivered', 'succeeded', 'failed', 'cancelled'
|
||||
)),
|
||||
ADD CONSTRAINT processing_attempts_terminal_shape CHECK (
|
||||
(attempt_status = 'succeeded' AND failure_code IS NULL AND finished_at IS NOT NULL)
|
||||
OR (attempt_status = 'failed' AND failure_code IS NOT NULL AND finished_at IS NOT NULL)
|
||||
OR (attempt_status = 'cancelled' AND finished_at IS NOT NULL)
|
||||
OR attempt_status IN ('queued', 'dispatched', 'running', 'delivered')
|
||||
);
|
||||
|
||||
ALTER TABLE ingestion.processing_runs
|
||||
DROP CONSTRAINT IF EXISTS processing_runs_run_status_check,
|
||||
DROP CONSTRAINT IF EXISTS processing_runs_terminal_shape;
|
||||
ALTER TABLE ingestion.processing_runs
|
||||
ADD CONSTRAINT processing_runs_run_status_check CHECK (run_status IN (
|
||||
'received', 'queued', 'running', 'validating', 'accepted', 'rejected', 'failed', 'cancelled'
|
||||
)),
|
||||
ADD CONSTRAINT processing_runs_terminal_shape CHECK (
|
||||
(
|
||||
run_status = 'accepted'
|
||||
AND failure_code IS NULL
|
||||
AND validated_at IS NOT NULL
|
||||
AND finished_at IS NOT NULL
|
||||
AND (
|
||||
pipeline_type <> 'opera_daily'
|
||||
OR (
|
||||
business_date IS NOT NULL
|
||||
AND delivered_processor_version IS NOT NULL
|
||||
AND delivered_rule_set_sha256 IS NOT NULL
|
||||
AND result_schema_version IS NOT NULL
|
||||
AND delivery_sha256 IS NOT NULL
|
||||
AND (
|
||||
(
|
||||
result_delivery_mode = 'artifact_callback'
|
||||
AND result_artifact_id IS NOT NULL
|
||||
)
|
||||
OR (
|
||||
result_delivery_mode = 'direct_mcp'
|
||||
AND result_artifact_id IS NULL
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
OR (run_status IN ('rejected', 'failed') AND failure_code IS NOT NULL AND finished_at IS NOT NULL)
|
||||
OR (run_status = 'cancelled' AND finished_at IS NOT NULL)
|
||||
OR run_status IN ('received', 'queued', 'running', 'validating')
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user