93 lines
4.2 KiB
SQL
93 lines
4.2 KiB
SQL
-- 038_departments.sql
|
|
-- Departments as a managed entity (backend/department/models.py): name, short
|
|
-- code, subtitle (replaces the design's "Cost Center"), description, status,
|
|
-- head, parent department and region/location list. Plus the `department`
|
|
-- permission module (8 tags), a `department_management` bundle holding them,
|
|
-- and that bundle attached to the admin roles.
|
|
--
|
|
-- Idempotent, applied automatically at startup by alembic_setup.run_manual_sql()
|
|
-- and recorded in manual_migrations. Needed because prod boots with
|
|
-- DB_AUTOGENERATE=false and never autogenerates new tables. Index names match
|
|
-- the db_setup NAMING_CONVENTION so a dev DB that autogenerated first is a no-op.
|
|
-- Users must log in again afterwards — the frontend caches /users/me permissions.
|
|
|
|
-- =============================================================================
|
|
-- 1. Table
|
|
-- =============================================================================
|
|
CREATE TABLE IF NOT EXISTS app.departments (
|
|
id uuid PRIMARY KEY,
|
|
name varchar NOT NULL,
|
|
short_code varchar(10) NOT NULL,
|
|
subtitle varchar,
|
|
description varchar,
|
|
is_active boolean NOT NULL DEFAULT true,
|
|
parent_department_id uuid REFERENCES app.departments(id),
|
|
department_head_id uuid REFERENCES app.users(id),
|
|
location jsonb NOT NULL DEFAULT '[]'::jsonb,
|
|
created_at timestamptz NOT NULL DEFAULT NOW(),
|
|
updated_at timestamptz NOT NULL DEFAULT NOW(),
|
|
created_by uuid REFERENCES app.users(id),
|
|
updated_by uuid REFERENCES app.users(id)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS ix_departments_name
|
|
ON app.departments (name);
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS ix_departments_short_code
|
|
ON app.departments (short_code);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_departments_parent_department_id
|
|
ON app.departments (parent_department_id);
|
|
|
|
-- =============================================================================
|
|
-- 2. The 8 department.* permission tags
|
|
-- =============================================================================
|
|
INSERT INTO app.permission_tags
|
|
(tag_name, module, action, description, created_at, updated_at, is_active, is_deleted)
|
|
VALUES
|
|
('department.view', 'department', 'view', NULL, NOW(), NOW(), true, false),
|
|
('department.create', 'department', 'create', NULL, NOW(), NOW(), true, false),
|
|
('department.edit', 'department', 'edit', NULL, NOW(), NOW(), true, false),
|
|
('department.delete', 'department', 'delete', NULL, NOW(), NOW(), true, false),
|
|
('department.approve', 'department', 'approve', NULL, NOW(), NOW(), true, false),
|
|
('department.export', 'department', 'export', NULL, NOW(), NOW(), true, false),
|
|
('department.manage', 'department', 'manage', NULL, NOW(), NOW(), true, false),
|
|
('department.configure', 'department', 'configure', NULL, NOW(), NOW(), true, false)
|
|
ON CONFLICT (tag_name) DO NOTHING;
|
|
|
|
-- =============================================================================
|
|
-- 3. Bundle holding all eight department tags
|
|
-- =============================================================================
|
|
INSERT INTO app.permissions (name, description, permission_tags, is_system, created_at, updated_at, is_active, is_deleted)
|
|
SELECT
|
|
'department_management',
|
|
'Departments: view, create, edit and manage departments',
|
|
(
|
|
SELECT COALESCE(jsonb_agg(id ORDER BY id), '[]'::jsonb)
|
|
FROM app.permission_tags
|
|
WHERE is_deleted = false
|
|
AND module = 'department'
|
|
),
|
|
true,
|
|
NOW(),
|
|
NOW(),
|
|
true,
|
|
false
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM app.permissions WHERE name = 'department_management'
|
|
);
|
|
|
|
-- =============================================================================
|
|
-- 4. Attach the bundle to the admin roles (idempotent)
|
|
-- =============================================================================
|
|
UPDATE app.roles r
|
|
SET permissions = COALESCE(r.permissions, '[]'::jsonb) || jsonb_build_array(p.id),
|
|
updated_at = NOW()
|
|
FROM app.permissions p
|
|
WHERE p.name = 'department_management'
|
|
AND r.role_name IN (
|
|
'system_administrator',
|
|
'hr_administrator'
|
|
)
|
|
AND NOT (COALESCE(r.permissions, '[]'::jsonb) @> jsonb_build_array(p.id));
|