Files
medical-mall/mall_sql/migrations/20260605_homecare_migration_fixed.sql

917 lines
37 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================
-- Homecare Migration SQL - Phase 1 (Location & Checkin)
-- Date: 2026-06-05
-- Purpose: Formal migration for homecare location distance phase 1
-- Scope: Create/alter tables, indexes, foreign keys, seed data
-- ID Type: All user/org/team/elder IDs unified to uuid
-- Checkin Radius: 50 meters (phase 1)
-- ============================================================
BEGIN;
-- Needed for gen_random_uuid() defaults used by UUID primary keys.
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- ============================================================
-- Part 1: Create/Alter Foundation Tables
-- ============================================================
-- Table: public.hc_work_order_events
-- Source: 20260518_homecare_foundation.sql
CREATE TABLE IF NOT EXISTS public.hc_work_order_events (
id text primary key,
work_order_id uuid not null,
org_id uuid not null,
team_id uuid,
worker_id uuid,
action text not null,
from_status text not null,
to_status text not null,
operator_id uuid not null,
reason text,
payload jsonb,
created_at timestamptz not null default now()
);
-- Table: public.hc_work_order_exceptions
-- Source: 20260518_homecare_foundation.sql
CREATE TABLE IF NOT EXISTS public.hc_work_order_exceptions (
id text primary key,
work_order_id uuid not null,
org_id uuid not null,
team_id uuid,
worker_id uuid,
exception_type text not null,
description text not null,
status text not null default 'PENDING' check (status in ('PENDING', 'HANDLED')),
decision text,
reason text,
created_by uuid not null,
handled_by uuid,
evidence_urls jsonb not null default '[]'::jsonb,
created_at timestamptz not null default now(),
handled_at timestamptz
);
-- Table: public.hc_evidence_files
-- Source: 20260518_homecare_foundation.sql
-- Phase 1 Update: Add fields for checkin evidence support
CREATE TABLE IF NOT EXISTS public.hc_evidence_files (
id text primary key,
work_order_id uuid not null,
org_id uuid not null,
owner_id uuid,
uploader_id uuid not null,
file_url text not null,
mime_type text,
evidence_type text,
-- Phase 1新增字段
file_size_bytes bigint not null default 0,
upload_status text not null default 'TEMP' check (upload_status in ('TEMP', 'READY', 'BOUND', 'LOCKED', 'DELETED')),
storage_bucket text,
storage_path text,
file_hash text,
bound_action text check (bound_action in ('CHECKIN', 'CHECKOUT', 'EXCEPTION')),
bound_record_id text,
is_locked boolean not null default false,
locked_at timestamptz,
expires_at timestamptz,
updated_at timestamptz not null default now(),
created_at timestamptz not null default now()
);
-- Table: public.hc_worker_qualifications
-- Source: 20260518_homecare_foundation.sql
CREATE TABLE IF NOT EXISTS public.hc_worker_qualifications (
id text primary key,
org_id uuid not null,
worker_id uuid not null,
qualification_type text not null,
qualification_no text,
issue_org text,
valid_from date,
valid_to date,
review_status text not null default 'PENDING' check (review_status in ('PENDING', 'APPROVED', 'REJECTED', 'EXPIRED')),
reviewed_by uuid,
reviewed_at timestamptz,
file_urls jsonb not null default '[]'::jsonb,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.hc_settlements
-- Source: 20260518_homecare_foundation.sql
CREATE TABLE IF NOT EXISTS public.hc_settlements (
id uuid primary key default gen_random_uuid(),
work_order_id uuid not null unique,
org_id uuid not null,
finance_owner_id uuid,
status text not null default 'PENDING' check (status in ('PENDING', 'READY', 'CONFIRMED')),
amount numeric(12, 2) not null default 0,
currency text not null default 'CNY',
settled_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- ============================================================
-- Part 2: Business Closure Extension Tables
-- ============================================================
-- Table: public.hc_acceptances
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_acceptances (
id text primary key,
work_order_id uuid not null,
org_id uuid not null,
team_id uuid,
worker_id uuid,
status text not null default 'PENDING' check (status in ('PENDING', 'ACCEPTED', 'REJECTED', 'CLOSED')),
result text check (result in ('PASS', 'REJECT')),
rating smallint check (rating between 1 and 5),
tags jsonb not null default '[]'::jsonb,
comment text,
rejected_reason text,
accepted_by uuid,
accepted_at timestamptz,
created_by uuid,
updated_by uuid,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.hc_acceptance_issues
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_acceptance_issues (
id text primary key,
acceptance_id text not null,
work_order_id uuid not null,
org_id uuid not null,
team_id uuid,
worker_id uuid,
issue_type text not null,
priority text,
description text not null,
evidence_urls jsonb not null default '[]'::jsonb,
status text not null default 'OPEN' check (status in ('OPEN', 'PROCESSING', 'RESOLVED', 'CLOSED')),
reporter_id uuid not null,
handler_id uuid,
resolution text,
resolved_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.hc_complaints
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_complaints (
id text primary key,
work_order_id uuid,
acceptance_issue_id text,
org_id uuid not null,
team_id uuid,
worker_id uuid,
complainant_id uuid not null,
complaint_type text not null,
description text not null,
evidence_urls jsonb not null default '[]'::jsonb,
status text not null default 'PENDING' check (status in ('PENDING', 'PROCESSING', 'RESOLVED', 'CLOSED')),
handler_id uuid,
resolution text,
resolved_at timestamptz,
created_by uuid,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.hc_exception_actions
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_exception_actions (
id text primary key,
exception_id text not null,
work_order_id uuid not null,
org_id uuid not null,
team_id uuid,
worker_id uuid,
action_type text not null,
description text,
payload jsonb not null default '{}'::jsonb,
operator_id uuid not null,
created_at timestamptz not null default now()
);
-- Table: public.hc_settlement_items
CREATE TABLE IF NOT EXISTS public.hc_settlement_items (
id uuid primary key default gen_random_uuid(),
settlement_id uuid not null,
work_order_id uuid not null,
execution_record_id uuid,
item_name text not null,
unit_price numeric(12, 2) not null default 0,
quantity numeric(10, 2) not null default 1,
actual_amount numeric(12, 2) not null default 0,
deduction_amount numeric(12, 2) not null default 0,
self_pay_amount numeric(12, 2) not null default 0,
status text not null default 'PENDING' check (status in ('PENDING', 'APPROVED', 'REJECTED', 'WAIVED')),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.hc_payments
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_payments (
id uuid primary key default gen_random_uuid(),
settlement_id uuid not null,
org_id uuid not null,
payer_id uuid,
payment_channel text not null,
transaction_id text,
amount numeric(12, 2) not null,
status text not null default 'PENDING' check (status in ('PENDING', 'PAID', 'FAILED', 'CANCELLED', 'REFUNDING', 'REFUNDED')),
callback_payload jsonb not null default '{}'::jsonb,
paid_at timestamptz,
failed_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.hc_refunds
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_refunds (
id uuid primary key default gen_random_uuid(),
payment_id uuid not null,
settlement_id uuid not null,
org_id uuid not null,
amount numeric(12, 2) not null,
reason text not null,
status text not null default 'PENDING' check (status in ('PENDING', 'PROCESSING', 'REFUNDED', 'FAILED', 'CLOSED')),
refund_transaction_id text,
created_by uuid,
refunded_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.hc_ledgers
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_ledgers (
id uuid primary key default gen_random_uuid(),
settlement_id uuid not null,
org_id uuid not null,
archive_period text not null,
ledger_type text not null default 'SETTLEMENT',
content jsonb not null default '{}'::jsonb,
archived_at timestamptz,
created_by uuid,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.hc_archive_files
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_archive_files (
id uuid primary key default gen_random_uuid(),
ledger_id uuid not null,
org_id uuid not null,
file_url text not null,
file_name text,
file_size bigint,
mime_type text,
created_by uuid,
created_at timestamptz not null default now()
);
-- Table: public.hc_consent_records
-- Source: 20260527_homecare_business_closure_extensions.sql
CREATE TABLE IF NOT EXISTS public.hc_consent_records (
id text primary key,
org_id uuid not null,
elder_id uuid not null,
consent_type text not null,
consent_status text not null default 'GRANTED' check (consent_status in ('GRANTED', 'REVOKED', 'EXPIRED')),
consent_version text,
granted_by uuid,
granted_at timestamptz,
revoked_at timestamptz,
expires_at timestamptz,
evidence_urls jsonb not null default '[]'::jsonb,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- ============================================================
-- Part 3: Location Distance Phase 1 Tables
-- ============================================================
-- Table: public.hc_dispatch_assignments
-- Source: 20260602_homecare_location_distance_phase1_tables.sql
CREATE TABLE IF NOT EXISTS public.hc_dispatch_assignments (
id text primary key,
work_order_id uuid not null,
org_id uuid not null,
team_id uuid,
assign_version integer not null default 1 check (assign_version > 0),
worker_id uuid,
service_latitude numeric(10,7) not null,
service_longitude numeric(10,7) not null,
service_coordinate_type text not null default 'gcj02',
dispatch_status text not null default 'PENDING'
check (dispatch_status in ('PENDING', 'ACCEPTED', 'REJECTED', 'TIMEOUT', 'REASSIGNED', 'CANCELLED')),
dispatch_reason text,
is_current boolean not null default true,
dispatched_at timestamptz not null default now(),
accepted_at timestamptz,
rejected_at timestamptz,
timeout_at timestamptz,
reassigned_at timestamptz,
cancelled_at timestamptz,
created_by uuid,
updated_by uuid,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint chk_hc_dispatch_assignments_lat_range check (service_latitude between -90 and 90),
constraint chk_hc_dispatch_assignments_lng_range check (service_longitude between -180 and 180),
constraint uq_hc_dispatch_assignments_version unique (work_order_id, assign_version)
);
-- Table: public.hc_worker_locations
-- Source: 20260602_homecare_location_distance_phase1_tables.sql
CREATE TABLE IF NOT EXISTS public.hc_worker_locations (
id text primary key,
work_order_id uuid not null,
worker_id uuid not null,
latitude numeric(10,7) not null,
longitude numeric(10,7) not null,
coordinate_type text not null default 'gcj02',
accuracy numeric(10,2),
location_scene text not null
check (location_scene in ('ON_THE_WAY', 'CHECKIN_PRECHECK', 'CHECKIN', 'CHECKOUT')),
reported_at timestamptz not null,
distance_meters numeric(10,2),
formatted_address text,
province text,
city text,
district text,
street text,
poi_title text,
geocode_provider text,
geocode_status text,
address_updated_at timestamptz,
created_at timestamptz not null default now(),
constraint chk_hc_worker_locations_lat_range check (latitude between -90 and 90),
constraint chk_hc_worker_locations_lng_range check (longitude between -180 and 180)
);
-- Table: public.hc_work_order_confirmations
-- Source: 20260602_homecare_location_distance_phase1_tables.sql
CREATE TABLE IF NOT EXISTS public.hc_work_order_confirmations (
id text primary key,
work_order_id uuid not null,
confirmation_type text not null default 'ARRIVAL',
status text not null default 'PENDING'
check (status in ('PENDING', 'CONFIRMED', 'REJECTED')),
confirmed_by uuid,
confirmed_at timestamptz,
reason text,
payload jsonb not null default '{}'::jsonb,
-- Phase 1预留二期电子签名扩展字段
signature_url text,
signature_hash text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- Table: public.sys_sla_config
-- Source: 20260602_homecare_location_distance_phase1_tables.sql
CREATE TABLE IF NOT EXISTS public.sys_sla_config (
id text primary key,
config_key text not null,
config_value text not null,
value_type text not null default 'string',
scope_type text not null default 'GLOBAL'
check (scope_type in ('WORK_ORDER', 'ORG', 'TEAM', 'GLOBAL')),
scope_id text,
is_active boolean not null default true,
description text,
updated_by uuid,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint chk_sys_sla_config_scope check (
(scope_type = 'GLOBAL' and scope_id is null)
or (scope_type <> 'GLOBAL')
)
);
-- ============================================================
-- Part 4: Audit Extension Tables (if not exist)
-- ============================================================
-- Table: public.hc_state_transitions
CREATE TABLE IF NOT EXISTS public.hc_state_transitions (
id text primary key,
work_order_id uuid not null,
from_status text not null,
to_status text not null,
triggered_by uuid not null,
reason text,
payload jsonb,
created_at timestamptz not null default now()
);
-- Table: public.hc_audit_logs
CREATE TABLE IF NOT EXISTS public.hc_audit_logs (
id text primary key,
work_order_id uuid,
org_id uuid,
actor_id uuid not null,
actor_role text not null,
action text not null,
resource_type text not null,
resource_id text not null,
details jsonb,
ip_address inet,
user_agent text,
created_at timestamptz not null default now()
);
-- Table: public.hc_sensitive_access_logs
CREATE TABLE IF NOT EXISTS public.hc_sensitive_access_logs (
id text primary key,
accessor_id uuid not null,
accessed_resource_type text not null,
accessed_resource_id text not null,
access_purpose text not null,
approved_by uuid,
created_at timestamptz not null default now()
);
-- ============================================================
-- Part 4.5: Legacy Compatibility Fixes
-- ============================================================
-- These fixes make reruns safe when older hc_* tables already exist.
-- CREATE TABLE IF NOT EXISTS does not upgrade existing table definitions,
-- so referenced columns and FK columns are normalized before indexes/FKs.
-- Existing settlements table may already have id uuid in current database.
-- If settlement-related child tables already exist with text FK columns,
-- convert them to uuid before FK creation. This succeeds only when existing
-- values are empty or valid UUID strings.
DO $$
BEGIN
IF to_regclass('public.hc_settlement_items') IS NOT NULL
AND EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema='public'
AND table_name='hc_settlement_items'
AND column_name='settlement_id'
AND udt_name <> 'uuid'
)
THEN
ALTER TABLE public.hc_settlement_items
ALTER COLUMN settlement_id TYPE uuid USING NULLIF(settlement_id, '')::uuid;
END IF;
IF to_regclass('public.hc_payments') IS NOT NULL
AND EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema='public'
AND table_name='hc_payments'
AND column_name='settlement_id'
AND udt_name <> 'uuid'
)
THEN
ALTER TABLE public.hc_payments
ALTER COLUMN settlement_id TYPE uuid USING NULLIF(settlement_id, '')::uuid;
END IF;
IF to_regclass('public.hc_refunds') IS NOT NULL
AND EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema='public'
AND table_name='hc_refunds'
AND column_name='settlement_id'
AND udt_name <> 'uuid'
)
THEN
ALTER TABLE public.hc_refunds
ALTER COLUMN settlement_id TYPE uuid USING NULLIF(settlement_id, '')::uuid;
END IF;
IF to_regclass('public.hc_refunds') IS NOT NULL
AND EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema='public'
AND table_name='hc_refunds'
AND column_name='payment_id'
AND udt_name <> 'uuid'
)
THEN
ALTER TABLE public.hc_refunds
ALTER COLUMN payment_id TYPE uuid USING NULLIF(payment_id, '')::uuid;
END IF;
IF to_regclass('public.hc_ledgers') IS NOT NULL
AND EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema='public'
AND table_name='hc_ledgers'
AND column_name='settlement_id'
AND udt_name <> 'uuid'
)
THEN
ALTER TABLE public.hc_ledgers
ALTER COLUMN settlement_id TYPE uuid USING NULLIF(settlement_id, '')::uuid;
END IF;
IF to_regclass('public.hc_archive_files') IS NOT NULL
AND EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema='public'
AND table_name='hc_archive_files'
AND column_name='ledger_id'
AND udt_name <> 'uuid'
)
THEN
ALTER TABLE public.hc_archive_files
ALTER COLUMN ledger_id TYPE uuid USING NULLIF(ledger_id, '')::uuid;
END IF;
END $$;
-- ============================================================
-- Part 5: Indexes
-- ============================================================
-- hc_dispatch_assignments indexes
CREATE INDEX IF NOT EXISTS idx_hc_dispatch_assignments_wo_created
ON public.hc_dispatch_assignments (work_order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_dispatch_assignments_current
ON public.hc_dispatch_assignments (work_order_id) WHERE is_current = true;
-- Ensure each work order has at most one current assignment for distance/checkin RPC lookup.
CREATE UNIQUE INDEX IF NOT EXISTS uq_hc_dispatch_assignments_one_current
ON public.hc_dispatch_assignments (work_order_id) WHERE is_current = true;
CREATE INDEX IF NOT EXISTS idx_hc_dispatch_assignments_worker_status
ON public.hc_dispatch_assignments (worker_id, dispatch_status, created_at DESC);
-- hc_worker_locations indexes
CREATE INDEX IF NOT EXISTS idx_hc_worker_locations_wo_reported
ON public.hc_worker_locations (work_order_id, reported_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_worker_locations_worker_reported
ON public.hc_worker_locations (worker_id, reported_at DESC);
-- hc_work_order_confirmations indexes
CREATE INDEX IF NOT EXISTS idx_hc_work_order_confirmations_wo_created
ON public.hc_work_order_confirmations (work_order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_work_order_confirmations_status
ON public.hc_work_order_confirmations (status, updated_at DESC);
-- hc_evidence_files indexes
CREATE INDEX IF NOT EXISTS idx_hc_evidence_files_wo_created
ON public.hc_evidence_files (work_order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_evidence_files_upload_status
ON public.hc_evidence_files (upload_status) WHERE upload_status != 'DELETED';
-- sys_sla_config indexes
CREATE INDEX IF NOT EXISTS idx_sys_sla_config_key_scope
ON public.sys_sla_config (config_key, scope_type, scope_id, is_active) WHERE is_active = true;
-- hc_work_order_exceptions indexes
CREATE INDEX IF NOT EXISTS idx_hc_work_order_exceptions_wo_created
ON public.hc_work_order_exceptions (work_order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hc_work_order_exceptions_status
ON public.hc_work_order_exceptions (status, created_at DESC);
-- hc_work_order_events indexes
CREATE INDEX IF NOT EXISTS idx_hc_work_order_events_wo_created
ON public.hc_work_order_events (work_order_id, created_at DESC);
-- hc_settlements indexes
CREATE INDEX IF NOT EXISTS idx_hc_settlements_wo
ON public.hc_settlements (work_order_id);
-- ============================================================
-- Part 6: Foreign Keys
-- ============================================================
-- Make foreign key creation idempotent for reruns
ALTER TABLE public.hc_work_order_events
DROP CONSTRAINT IF EXISTS fk_hc_work_order_events_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_work_order_events_worker,
DROP CONSTRAINT IF EXISTS fk_hc_work_order_events_operator;
ALTER TABLE public.hc_work_order_exceptions
DROP CONSTRAINT IF EXISTS fk_hc_work_order_exceptions_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_work_order_exceptions_worker,
DROP CONSTRAINT IF EXISTS fk_hc_work_order_exceptions_created_by,
DROP CONSTRAINT IF EXISTS fk_hc_work_order_exceptions_handled_by;
ALTER TABLE public.hc_evidence_files
DROP CONSTRAINT IF EXISTS fk_hc_evidence_files_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_evidence_files_uploader;
ALTER TABLE public.hc_worker_qualifications
DROP CONSTRAINT IF EXISTS fk_hc_worker_qualifications_worker,
DROP CONSTRAINT IF EXISTS fk_hc_worker_qualifications_reviewed_by;
ALTER TABLE public.hc_settlements
DROP CONSTRAINT IF EXISTS fk_hc_settlements_work_order;
ALTER TABLE public.hc_acceptances
DROP CONSTRAINT IF EXISTS fk_hc_acceptances_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_acceptances_worker,
DROP CONSTRAINT IF EXISTS fk_hc_acceptances_accepted_by;
ALTER TABLE public.hc_acceptance_issues
DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_acceptance,
DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_worker,
DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_reporter,
DROP CONSTRAINT IF EXISTS fk_hc_acceptance_issues_handler;
ALTER TABLE public.hc_complaints
DROP CONSTRAINT IF EXISTS fk_hc_complaints_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_complaints_acceptance_issue,
DROP CONSTRAINT IF EXISTS fk_hc_complaints_worker,
DROP CONSTRAINT IF EXISTS fk_hc_complaints_complainant,
DROP CONSTRAINT IF EXISTS fk_hc_complaints_handler;
ALTER TABLE public.hc_exception_actions
DROP CONSTRAINT IF EXISTS fk_hc_exception_actions_exception,
DROP CONSTRAINT IF EXISTS fk_hc_exception_actions_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_exception_actions_worker,
DROP CONSTRAINT IF EXISTS fk_hc_exception_actions_operator;
ALTER TABLE public.hc_settlement_items
DROP CONSTRAINT IF EXISTS fk_hc_settlement_items_settlement,
DROP CONSTRAINT IF EXISTS fk_hc_settlement_items_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_settlement_items_execution_record;
ALTER TABLE public.hc_payments
DROP CONSTRAINT IF EXISTS fk_hc_payments_settlement,
DROP CONSTRAINT IF EXISTS fk_hc_payments_payer;
ALTER TABLE public.hc_refunds
DROP CONSTRAINT IF EXISTS fk_hc_refunds_payment,
DROP CONSTRAINT IF EXISTS fk_hc_refunds_settlement,
DROP CONSTRAINT IF EXISTS fk_hc_refunds_created_by;
ALTER TABLE public.hc_ledgers
DROP CONSTRAINT IF EXISTS fk_hc_ledgers_settlement,
DROP CONSTRAINT IF EXISTS fk_hc_ledgers_created_by;
ALTER TABLE public.hc_archive_files
DROP CONSTRAINT IF EXISTS fk_hc_archive_files_ledger,
DROP CONSTRAINT IF EXISTS fk_hc_archive_files_created_by;
ALTER TABLE public.hc_consent_records
DROP CONSTRAINT IF EXISTS fk_hc_consent_records_elder,
DROP CONSTRAINT IF EXISTS fk_hc_consent_records_granted_by;
ALTER TABLE public.hc_dispatch_assignments
DROP CONSTRAINT IF EXISTS fk_hc_dispatch_assignments_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_dispatch_assignments_worker,
DROP CONSTRAINT IF EXISTS fk_hc_dispatch_assignments_created_by,
DROP CONSTRAINT IF EXISTS fk_hc_dispatch_assignments_updated_by;
ALTER TABLE public.hc_worker_locations
DROP CONSTRAINT IF EXISTS fk_hc_worker_locations_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_worker_locations_worker;
ALTER TABLE public.hc_work_order_confirmations
DROP CONSTRAINT IF EXISTS fk_hc_work_order_confirmations_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_work_order_confirmations_confirmed_by;
ALTER TABLE public.hc_state_transitions
DROP CONSTRAINT IF EXISTS fk_hc_state_transitions_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_state_transitions_triggered_by;
ALTER TABLE public.hc_audit_logs
DROP CONSTRAINT IF EXISTS fk_hc_audit_logs_work_order,
DROP CONSTRAINT IF EXISTS fk_hc_audit_logs_actor;
ALTER TABLE public.hc_sensitive_access_logs
DROP CONSTRAINT IF EXISTS fk_hc_sensitive_access_logs_accessor;
-- hc_work_order_events foreign keys
ALTER TABLE public.hc_work_order_events
ADD CONSTRAINT fk_hc_work_order_events_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_work_order_events_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_work_order_events_operator
FOREIGN KEY (operator_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;
-- hc_work_order_exceptions foreign keys
ALTER TABLE public.hc_work_order_exceptions
ADD CONSTRAINT fk_hc_work_order_exceptions_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_work_order_exceptions_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_work_order_exceptions_created_by
FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_work_order_exceptions_handled_by
FOREIGN KEY (handled_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_evidence_files foreign keys
ALTER TABLE public.hc_evidence_files
ADD CONSTRAINT fk_hc_evidence_files_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_evidence_files_uploader
FOREIGN KEY (uploader_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;
-- hc_worker_qualifications foreign keys
ALTER TABLE public.hc_worker_qualifications
ADD CONSTRAINT fk_hc_worker_qualifications_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_worker_qualifications_reviewed_by
FOREIGN KEY (reviewed_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_settlements foreign keys
ALTER TABLE public.hc_settlements
ADD CONSTRAINT fk_hc_settlements_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT;
-- hc_acceptances foreign keys
ALTER TABLE public.hc_acceptances
ADD CONSTRAINT fk_hc_acceptances_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_acceptances_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_acceptances_accepted_by
FOREIGN KEY (accepted_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_acceptance_issues foreign keys
ALTER TABLE public.hc_acceptance_issues
ADD CONSTRAINT fk_hc_acceptance_issues_acceptance
FOREIGN KEY (acceptance_id) REFERENCES public.hc_acceptances(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_acceptance_issues_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_acceptance_issues_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_acceptance_issues_reporter
FOREIGN KEY (reporter_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_acceptance_issues_handler
FOREIGN KEY (handler_id) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_complaints foreign keys
ALTER TABLE public.hc_complaints
ADD CONSTRAINT fk_hc_complaints_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_complaints_acceptance_issue
FOREIGN KEY (acceptance_issue_id) REFERENCES public.hc_acceptance_issues(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_complaints_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_complaints_complainant
FOREIGN KEY (complainant_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_complaints_handler
FOREIGN KEY (handler_id) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_exception_actions foreign keys
ALTER TABLE public.hc_exception_actions
ADD CONSTRAINT fk_hc_exception_actions_exception
FOREIGN KEY (exception_id) REFERENCES public.hc_work_order_exceptions(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_exception_actions_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_exception_actions_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_exception_actions_operator
FOREIGN KEY (operator_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;
-- hc_settlement_items foreign keys
ALTER TABLE public.hc_settlement_items
ADD CONSTRAINT fk_hc_settlement_items_settlement
FOREIGN KEY (settlement_id) REFERENCES public.hc_settlements(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_settlement_items_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_settlement_items_execution_record
FOREIGN KEY (execution_record_id) REFERENCES public.ec_care_records(id) ON DELETE SET NULL;
-- hc_payments foreign keys
ALTER TABLE public.hc_payments
ADD CONSTRAINT fk_hc_payments_settlement
FOREIGN KEY (settlement_id) REFERENCES public.hc_settlements(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_payments_payer
FOREIGN KEY (payer_id) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_refunds foreign keys
ALTER TABLE public.hc_refunds
ADD CONSTRAINT fk_hc_refunds_payment
FOREIGN KEY (payment_id) REFERENCES public.hc_payments(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_refunds_settlement
FOREIGN KEY (settlement_id) REFERENCES public.hc_settlements(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_refunds_created_by
FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_ledgers foreign keys
ALTER TABLE public.hc_ledgers
ADD CONSTRAINT fk_hc_ledgers_settlement
FOREIGN KEY (settlement_id) REFERENCES public.hc_settlements(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_ledgers_created_by
FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_archive_files foreign keys
ALTER TABLE public.hc_archive_files
ADD CONSTRAINT fk_hc_archive_files_ledger
FOREIGN KEY (ledger_id) REFERENCES public.hc_ledgers(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_archive_files_created_by
FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- hc_consent_records foreign keys
ALTER TABLE public.hc_consent_records
ADD CONSTRAINT fk_hc_consent_records_elder
FOREIGN KEY (elder_id) REFERENCES public.ec_elders(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_consent_records_granted_by
FOREIGN KEY (granted_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- Location distance phase 1 foreign keys
ALTER TABLE public.hc_dispatch_assignments
ADD CONSTRAINT fk_hc_dispatch_assignments_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_dispatch_assignments_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_dispatch_assignments_created_by
FOREIGN KEY (created_by) REFERENCES public.ak_users(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_dispatch_assignments_updated_by
FOREIGN KEY (updated_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
ALTER TABLE public.hc_worker_locations
ADD CONSTRAINT fk_hc_worker_locations_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_worker_locations_worker
FOREIGN KEY (worker_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;
ALTER TABLE public.hc_work_order_confirmations
ADD CONSTRAINT fk_hc_work_order_confirmations_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_work_order_confirmations_confirmed_by
FOREIGN KEY (confirmed_by) REFERENCES public.ak_users(id) ON DELETE SET NULL;
-- Audit extension tables foreign keys
ALTER TABLE public.hc_state_transitions
ADD CONSTRAINT fk_hc_state_transitions_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE RESTRICT,
ADD CONSTRAINT fk_hc_state_transitions_triggered_by
FOREIGN KEY (triggered_by) REFERENCES public.ak_users(id) ON DELETE RESTRICT;
ALTER TABLE public.hc_audit_logs
ADD CONSTRAINT fk_hc_audit_logs_work_order
FOREIGN KEY (work_order_id) REFERENCES public.ec_care_tasks(id) ON DELETE SET NULL,
ADD CONSTRAINT fk_hc_audit_logs_actor
FOREIGN KEY (actor_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;
ALTER TABLE public.hc_sensitive_access_logs
ADD CONSTRAINT fk_hc_sensitive_access_logs_accessor
FOREIGN KEY (accessor_id) REFERENCES public.ak_users(id) ON DELETE RESTRICT;
-- ============================================================
-- Part 7: Seed Data - SLA Config
-- ============================================================
-- Phase 1 SLA configuration
-- Checkin radius: 50 meters (phase 1 final)
INSERT INTO public.sys_sla_config (id, config_key, config_value, value_type, scope_type, description)
VALUES
('sla_001', 'HOMECARE_CHECKIN_RADIUS_METERS', '50', 'integer', 'GLOBAL', '签到半径一期50米'),
('sla_002', 'HOMECARE_LOCATION_REFRESH_SECONDS', '30', 'integer', 'GLOBAL', '定位刷新间隔(秒)'),
('sla_003', 'HOMECARE_CHECKIN_MAX_PHOTO_COUNT', '3', 'integer', 'GLOBAL', '签到最大照片数'),
('sla_004', 'HOMECARE_CHECKIN_MAX_PHOTO_SIZE_MB', '5', 'integer', 'GLOBAL', '单张最大照片大小(MB)')
ON CONFLICT (id) DO NOTHING;
-- ============================================================
-- Part 8: Comments
-- ============================================================
COMMENT ON TABLE public.hc_work_order_events IS '居家服务工单事件表 - 业务时间线展示';
COMMENT ON TABLE public.hc_work_order_exceptions IS '居家服务工单异常表';
COMMENT ON TABLE public.hc_evidence_files IS '居家服务证据文件表 - 签到照片、异常图片等';
COMMENT ON TABLE public.hc_worker_qualifications IS '居家服务人员资质表';
COMMENT ON TABLE public.hc_settlements IS '居家服务结算表';
COMMENT ON TABLE public.hc_acceptances IS '居家服务确认表';
COMMENT ON TABLE public.hc_acceptance_issues IS '居家服务确认问题表';
COMMENT ON TABLE public.hc_complaints IS '居家服务投诉表';
COMMENT ON TABLE public.hc_exception_actions IS '居家服务异常操作表';
COMMENT ON TABLE public.hc_settlement_items IS '居家服务结算明细表';
COMMENT ON TABLE public.hc_payments IS '居家服务支付表';
COMMENT ON TABLE public.hc_refunds IS '居家服务退款表';
COMMENT ON TABLE public.hc_ledgers IS '居家服务账簿表';
COMMENT ON TABLE public.hc_archive_files IS '居家服务归档文件表';
COMMENT ON TABLE public.hc_consent_records IS '居家服务同意记录表';
COMMENT ON TABLE public.hc_dispatch_assignments IS '居家服务派单记录表 - 定位距离一期';
COMMENT ON TABLE public.hc_worker_locations IS '居家服务人员定位表 - 定位距离一期';
COMMENT ON TABLE public.hc_work_order_confirmations IS '居家服务工单确认表 - 定位距离一期';
COMMENT ON TABLE public.sys_sla_config IS '居家服务SLA配置表';
COMMENT ON TABLE public.hc_state_transitions IS '居家服务状态变迁表 - 审计';
COMMENT ON TABLE public.hc_audit_logs IS '居家服务操作审计表';
COMMENT ON TABLE public.hc_sensitive_access_logs IS '居家服务敏感访问日志表';
COMMENT ON COLUMN public.hc_evidence_files.upload_status IS '上传状态: TEMP/READY/BOUND/LOCKED/DELETED';
COMMENT ON COLUMN public.hc_evidence_files.bound_action IS '绑定动作: CHECKIN/CHECKOUT/EXCEPTION';
COMMENT ON COLUMN public.hc_worker_locations.location_scene IS '定位场景: ON_THE_WAY/CHECKIN_PRECHECK/CHECKIN/CHECKOUT';
COMMENT ON COLUMN public.hc_work_order_confirmations.confirmation_type IS '确认类型: ARRIVAL二期扩展CHECKOUT';
COMMENT ON COLUMN public.hc_work_order_confirmations.signature_url IS '二期电子签名图片URL预留';
COMMENT ON COLUMN public.hc_work_order_confirmations.signature_hash IS '二期电子签名哈希(预留)';
COMMIT;