261 lines
10 KiB
PL/PgSQL
261 lines
10 KiB
PL/PgSQL
-- =============================================================================
|
|
-- IT Service Request Module
|
|
-- =============================================================================
|
|
|
|
-- 1. Main table
|
|
CREATE TABLE IF NOT EXISTS it_service_requests (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
request_number text UNIQUE,
|
|
|
|
-- Services (checkboxes from the form)
|
|
services text[] NOT NULL DEFAULT '{}',
|
|
services_other text,
|
|
|
|
-- Event/Activity Details (Quill Delta JSON)
|
|
event_name text NOT NULL,
|
|
event_details text, -- Quill delta JSON
|
|
|
|
-- Scheduling
|
|
event_date timestamptz,
|
|
event_end_date timestamptz,
|
|
dry_run_date timestamptz,
|
|
dry_run_end_date timestamptz,
|
|
|
|
-- Contact
|
|
contact_person text,
|
|
contact_number text,
|
|
|
|
-- Remarks (Quill Delta JSON)
|
|
remarks text,
|
|
|
|
-- Office (Department in the form)
|
|
office_id uuid REFERENCES offices(id) ON DELETE SET NULL,
|
|
|
|
-- Signatories
|
|
requested_by text, -- Name of requester (default: standard user who created)
|
|
requested_by_user_id uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
|
approved_by text, -- Name of approver (admin only)
|
|
approved_by_user_id uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
|
approved_at timestamptz,
|
|
|
|
-- Status lifecycle: draft → pending_approval → scheduled → in_progress_dry_run → in_progress → completed → cancelled
|
|
status text NOT NULL DEFAULT 'draft' CHECK (
|
|
status IN ('draft', 'pending_approval', 'scheduled', 'in_progress_dry_run', 'in_progress', 'completed', 'cancelled')
|
|
),
|
|
|
|
-- Geofence override: allow IT staff to check in/out outside CRMC premise
|
|
outside_premise_allowed boolean NOT NULL DEFAULT false,
|
|
|
|
-- Cancellation
|
|
cancellation_reason text,
|
|
cancelled_at timestamptz,
|
|
|
|
-- Metadata
|
|
creator_id uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
completed_at timestamptz,
|
|
|
|
-- Date/Time Received/Checked from the form
|
|
date_time_received timestamptz,
|
|
date_time_checked timestamptz
|
|
);
|
|
|
|
-- Auto-update updated_at
|
|
CREATE OR REPLACE FUNCTION update_it_service_requests_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = now();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER it_service_requests_updated_at_trigger
|
|
BEFORE UPDATE ON it_service_requests
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_it_service_requests_updated_at();
|
|
|
|
-- 2. IT Service Request Assignments (IT Staff assigned to the request)
|
|
CREATE TABLE IF NOT EXISTS it_service_request_assignments (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
request_id uuid NOT NULL REFERENCES it_service_requests(id) ON DELETE CASCADE,
|
|
user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
UNIQUE(request_id, user_id)
|
|
);
|
|
|
|
-- 3. Activity Logs for audit trail
|
|
CREATE TABLE IF NOT EXISTS it_service_request_activity_logs (
|
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
request_id uuid NOT NULL REFERENCES it_service_requests(id) ON DELETE CASCADE,
|
|
actor_id uuid REFERENCES auth.users(id) ON DELETE SET NULL,
|
|
action_type text NOT NULL,
|
|
meta jsonb,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- 4. Action Taken (separate table with evidence attachments)
|
|
CREATE TABLE IF NOT EXISTS it_service_request_actions (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
request_id uuid NOT NULL REFERENCES it_service_requests(id) ON DELETE CASCADE,
|
|
user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
action_taken text, -- Quill Delta JSON
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Auto-update updated_at for actions
|
|
CREATE TRIGGER it_service_request_actions_updated_at_trigger
|
|
BEFORE UPDATE ON it_service_request_actions
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_it_service_requests_updated_at();
|
|
|
|
-- 5. Evidence Attachments (images only, for action taken)
|
|
CREATE TABLE IF NOT EXISTS it_service_request_evidence (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
request_id uuid NOT NULL REFERENCES it_service_requests(id) ON DELETE CASCADE,
|
|
action_id uuid REFERENCES it_service_request_actions(id) ON DELETE CASCADE,
|
|
user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
file_path text NOT NULL,
|
|
file_name text NOT NULL,
|
|
taken_at timestamptz, -- Extracted from image EXIF metadata
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- 6. Request Number Generation RPC
|
|
CREATE OR REPLACE FUNCTION insert_it_service_request_with_number(
|
|
p_event_name text,
|
|
p_services text[],
|
|
p_creator_id uuid,
|
|
p_office_id uuid DEFAULT NULL,
|
|
p_requested_by text DEFAULT NULL,
|
|
p_requested_by_user_id uuid DEFAULT NULL,
|
|
p_status text DEFAULT 'draft'
|
|
)
|
|
RETURNS TABLE(id uuid, request_number text) AS $$
|
|
DECLARE
|
|
v_seq int;
|
|
v_id uuid;
|
|
v_number text;
|
|
BEGIN
|
|
-- Get next sequence number for the current year
|
|
SELECT COALESCE(MAX(
|
|
CAST(NULLIF(regexp_replace(r.request_number, '^ISR-\d{4}-', ''), '') AS int)
|
|
), 0) + 1
|
|
INTO v_seq
|
|
FROM it_service_requests r
|
|
WHERE r.request_number LIKE 'ISR-' || EXTRACT(YEAR FROM now())::text || '-%';
|
|
|
|
v_number := 'ISR-' || EXTRACT(YEAR FROM now())::text || '-' || LPAD(v_seq::text, 4, '0');
|
|
v_id := gen_random_uuid();
|
|
|
|
INSERT INTO it_service_requests (id, request_number, event_name, services, creator_id, office_id, requested_by, requested_by_user_id, status)
|
|
VALUES (v_id, v_number, p_event_name, p_services, p_creator_id, p_office_id, p_requested_by, p_requested_by_user_id, p_status);
|
|
|
|
RETURN QUERY SELECT v_id, v_number;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- 7. Indexes
|
|
CREATE INDEX idx_it_service_requests_status ON it_service_requests(status);
|
|
CREATE INDEX idx_it_service_requests_office_id ON it_service_requests(office_id);
|
|
CREATE INDEX idx_it_service_requests_creator_id ON it_service_requests(creator_id);
|
|
CREATE INDEX idx_it_service_requests_event_date ON it_service_requests(event_date);
|
|
CREATE INDEX idx_it_service_request_assignments_request_id ON it_service_request_assignments(request_id);
|
|
CREATE INDEX idx_it_service_request_assignments_user_id ON it_service_request_assignments(user_id);
|
|
CREATE INDEX idx_it_service_request_activity_logs_request_id ON it_service_request_activity_logs(request_id);
|
|
CREATE INDEX idx_it_service_request_actions_request_id ON it_service_request_actions(request_id);
|
|
CREATE INDEX idx_it_service_request_evidence_request_id ON it_service_request_evidence(request_id);
|
|
|
|
-- 8. Enable RLS
|
|
ALTER TABLE it_service_requests ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE it_service_request_assignments ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE it_service_request_activity_logs ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE it_service_request_actions ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE it_service_request_evidence ENABLE ROW LEVEL SECURITY;
|
|
|
|
-- 9. RLS Policies
|
|
|
|
-- IT Service Requests: authenticated can read all, insert own, update depending on role
|
|
CREATE POLICY "Authenticated users can read it_service_requests"
|
|
ON it_service_requests FOR SELECT TO authenticated USING (true);
|
|
|
|
CREATE POLICY "Authenticated users can insert it_service_requests"
|
|
ON it_service_requests FOR INSERT TO authenticated
|
|
WITH CHECK (auth.uid() = creator_id);
|
|
|
|
CREATE POLICY "Authenticated users can update it_service_requests"
|
|
ON it_service_requests FOR UPDATE TO authenticated
|
|
USING (true);
|
|
|
|
-- Assignments
|
|
CREATE POLICY "Authenticated users can read it_service_request_assignments"
|
|
ON it_service_request_assignments FOR SELECT TO authenticated USING (true);
|
|
|
|
CREATE POLICY "Authenticated users can insert it_service_request_assignments"
|
|
ON it_service_request_assignments FOR INSERT TO authenticated
|
|
WITH CHECK (true);
|
|
|
|
CREATE POLICY "Authenticated users can delete it_service_request_assignments"
|
|
ON it_service_request_assignments FOR DELETE TO authenticated
|
|
USING (true);
|
|
|
|
-- Activity Logs
|
|
CREATE POLICY "Authenticated users can read it_service_request_activity_logs"
|
|
ON it_service_request_activity_logs FOR SELECT TO authenticated USING (true);
|
|
|
|
CREATE POLICY "Authenticated users can insert it_service_request_activity_logs"
|
|
ON it_service_request_activity_logs FOR INSERT TO authenticated
|
|
WITH CHECK (true);
|
|
|
|
-- Actions
|
|
CREATE POLICY "Authenticated users can read it_service_request_actions"
|
|
ON it_service_request_actions FOR SELECT TO authenticated USING (true);
|
|
|
|
CREATE POLICY "Authenticated users can insert it_service_request_actions"
|
|
ON it_service_request_actions FOR INSERT TO authenticated
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
CREATE POLICY "Authenticated users can update it_service_request_actions"
|
|
ON it_service_request_actions FOR UPDATE TO authenticated
|
|
USING (auth.uid() = user_id);
|
|
|
|
-- Evidence
|
|
CREATE POLICY "Authenticated users can read it_service_request_evidence"
|
|
ON it_service_request_evidence FOR SELECT TO authenticated USING (true);
|
|
|
|
CREATE POLICY "Authenticated users can insert it_service_request_evidence"
|
|
ON it_service_request_evidence FOR INSERT TO authenticated
|
|
WITH CHECK (auth.uid() = user_id);
|
|
|
|
CREATE POLICY "Authenticated users can delete it_service_request_evidence"
|
|
ON it_service_request_evidence FOR DELETE TO authenticated
|
|
USING (auth.uid() = user_id);
|
|
|
|
-- 10. Add it_service_request_id to notifications table
|
|
ALTER TABLE notifications ADD COLUMN IF NOT EXISTS it_service_request_id uuid REFERENCES it_service_requests(id) ON DELETE CASCADE;
|
|
|
|
-- 11. Storage bucket for IT service request files
|
|
INSERT INTO storage.buckets (id, name, public, file_size_limit)
|
|
VALUES ('it_service_attachments', 'it_service_attachments', true, 26214400)
|
|
ON CONFLICT (id) DO NOTHING;
|
|
|
|
-- Storage policies
|
|
CREATE POLICY "Authenticated users can upload it_service_attachments"
|
|
ON storage.objects FOR INSERT TO authenticated
|
|
WITH CHECK (bucket_id = 'it_service_attachments');
|
|
|
|
CREATE POLICY "Authenticated users can read it_service_attachments"
|
|
ON storage.objects FOR SELECT TO authenticated
|
|
USING (bucket_id = 'it_service_attachments');
|
|
|
|
CREATE POLICY "Authenticated users can delete it_service_attachments"
|
|
ON storage.objects FOR DELETE TO authenticated
|
|
USING (bucket_id = 'it_service_attachments');
|
|
|
|
-- 12. Realtime publication
|
|
ALTER PUBLICATION supabase_realtime ADD TABLE it_service_requests;
|
|
ALTER PUBLICATION supabase_realtime ADD TABLE it_service_request_assignments;
|
|
ALTER PUBLICATION supabase_realtime ADD TABLE it_service_request_activity_logs;
|
|
ALTER PUBLICATION supabase_realtime ADD TABLE it_service_request_actions;
|