iloom/scripts/init-schemas.sql
Chever John 9c39c8cbd7
init: iloom WMS monorepo with K8s deployment manifests
Go workspace (go.work) with 5 microservices + shared library:
- gateway (8080), auth-service (8081), purchaser-service (8082)
- textile-service (8083), washing-service (8084)
- shared: proto definitions, common packages

Infrastructure: docker-compose for local dev, K8s manifests for
K3s cluster deployment (mysql/redis/etcd + traefik ingress).

Frontend (iloom-flatten) added as git submodule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-14 11:33:31 +08:00

640 lines
24 KiB
SQL
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.

-- iloom 微服务数据库初始化脚本
-- 创建 5 个 Schema迁移表结构建立跨 Schema 视图
-- =============================================
-- 1. 创建 Schema
-- =============================================
CREATE SCHEMA IF NOT EXISTS common;
CREATE SCHEMA IF NOT EXISTS purchaser;
CREATE SCHEMA IF NOT EXISTS textile;
CREATE SCHEMA IF NOT EXISTS washing;
CREATE SCHEMA IF NOT EXISTS audit;
-- =============================================
-- 2. 创建枚举类型(在 public schema所有 schema 共享)
-- =============================================
DO $$ BEGIN
CREATE TYPE app_role AS ENUM ('purchaser', 'textile', 'washing');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;
DO $$ BEGIN
CREATE TYPE factory_type AS ENUM ('textile', 'washing');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;
DO $$ BEGIN
CREATE TYPE plan_status AS ENUM ('pending', 'producing', 'completed');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;
DO $$ BEGIN
CREATE TYPE step_status AS ENUM ('pending', 'active', 'completed', 'rejected');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;
DO $$ BEGIN
CREATE TYPE step_type AS ENUM ('confirm', 'yarn_purchase', 'dyeing', 'machine_start', 'fabric_warehouse');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;
DO $$ BEGIN
CREATE TYPE warehouse_type AS ENUM ('raw_fabric', 'fabric', 'finished', 'yarn');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;
DO $$ BEGIN
CREATE TYPE payment_status AS ENUM ('pending', 'completed');
EXCEPTION WHEN duplicate_object THEN NULL;
END $$;
-- =============================================
-- 3. common Schema 表
-- =============================================
CREATE TABLE IF NOT EXISTS common.companies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
role app_role NOT NULL,
address TEXT,
contact_phone TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS common.profiles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
phone TEXT,
company_id UUID REFERENCES common.companies(id),
is_master BOOLEAN NOT NULL DEFAULT true,
master_id UUID REFERENCES common.profiles(id),
display_name TEXT,
image_url TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS common.company_members (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES common.companies(id),
user_id UUID NOT NULL REFERENCES common.profiles(id),
role TEXT NOT NULL DEFAULT 'member',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS common.company_relationships (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
purchaser_company_id UUID NOT NULL REFERENCES common.companies(id),
factory_company_id UUID NOT NULL REFERENCES common.companies(id),
factory_type factory_type NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS common.notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
recipient_id UUID NOT NULL,
sender_id UUID,
sender_company_id UUID REFERENCES common.companies(id),
title TEXT NOT NULL,
content TEXT NOT NULL,
type TEXT NOT NULL,
plan_id UUID,
is_read BOOLEAN DEFAULT false,
read_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE IF NOT EXISTS common.share_links (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL,
created_by UUID NOT NULL,
short_code TEXT NOT NULL UNIQUE,
factory_type TEXT NOT NULL,
hide_sensitive BOOLEAN DEFAULT false,
status TEXT NOT NULL DEFAULT 'pending',
expires_at TIMESTAMPTZ,
clicked_at TIMESTAMPTZ,
click_count INT DEFAULT 0,
used_at TIMESTAMPTZ,
response_result TEXT,
reject_reason TEXT,
responded_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS common.user_feedback (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
type TEXT NOT NULL,
content TEXT NOT NULL,
contact TEXT,
status TEXT NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS common.crash_reports (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
error_message TEXT NOT NULL,
error_stack TEXT,
component_stack TEXT,
url TEXT,
user_agent TEXT,
user_description TEXT,
status TEXT NOT NULL DEFAULT 'new',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- =============================================
-- 4. purchaser Schema 表
-- =============================================
CREATE TABLE IF NOT EXISTS purchaser.production_plans (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_code TEXT NOT NULL,
purchaser_id UUID NOT NULL REFERENCES common.companies(id),
product_name TEXT NOT NULL,
fabric_code TEXT NOT NULL,
color TEXT NOT NULL,
color_code TEXT NOT NULL DEFAULT '',
target_quantity NUMERIC NOT NULL DEFAULT 0,
completed_quantity NUMERIC NOT NULL DEFAULT 0,
production_price NUMERIC,
yarn_usage_per_meter NUMERIC,
status plan_status NOT NULL DEFAULT 'pending',
remark TEXT,
start_time TIMESTAMPTZ,
created_by UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.plan_factories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES purchaser.production_plans(id) ON DELETE CASCADE,
factory_id UUID NOT NULL REFERENCES common.companies(id),
factory_type factory_type NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.yarn_ratios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES purchaser.production_plans(id) ON DELETE CASCADE,
yarn_name TEXT NOT NULL,
yarn_type TEXT,
ratio NUMERIC NOT NULL DEFAULT 0,
amount_per_meter NUMERIC NOT NULL DEFAULT 0,
total_amount NUMERIC NOT NULL DEFAULT 0,
company_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES common.companies(id),
product_name TEXT NOT NULL,
fabric_code TEXT NOT NULL,
color TEXT NOT NULL,
color_code TEXT NOT NULL DEFAULT '',
weight NUMERIC NOT NULL DEFAULT 0,
warp_weight NUMERIC,
weft_weight NUMERIC,
total_weight NUMERIC,
yarn_usage_per_meter NUMERIC NOT NULL DEFAULT 0,
production_price NUMERIC,
total_stock NUMERIC NOT NULL DEFAULT 0,
raw_fabric_meters NUMERIC NOT NULL DEFAULT 0,
raw_fabric_rolls INT NOT NULL DEFAULT 0,
image_url TEXT,
yarn_types TEXT[],
yarn_ratios NUMERIC[],
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.product_inventory_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
product_id UUID NOT NULL REFERENCES purchaser.products(id) ON DELETE CASCADE,
batch_no TEXT NOT NULL,
rolls INT NOT NULL DEFAULT 0,
meters NUMERIC NOT NULL DEFAULT 0,
notes TEXT,
operator_id UUID,
company_id UUID,
warehouse_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.product_outbound_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
product_id UUID NOT NULL REFERENCES purchaser.products(id) ON DELETE CASCADE,
batch_no TEXT NOT NULL DEFAULT '',
rolls INT NOT NULL DEFAULT 0,
meters NUMERIC NOT NULL DEFAULT 0,
outbound_type TEXT NOT NULL DEFAULT 'normal',
notes TEXT,
operator_id UUID,
company_id UUID,
recipient_company_id UUID,
recipient_company_name TEXT,
source_batch_id UUID,
washing_plan_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.product_yarn_ratios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
product_id UUID NOT NULL REFERENCES purchaser.products(id) ON DELETE CASCADE,
yarn_name TEXT NOT NULL,
yarn_type TEXT,
ratio NUMERIC NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.product_price_history (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
product_id UUID NOT NULL REFERENCES purchaser.products(id) ON DELETE CASCADE,
company_id UUID NOT NULL,
old_price NUMERIC NOT NULL DEFAULT 0,
new_price NUMERIC NOT NULL DEFAULT 0,
change_amount NUMERIC NOT NULL DEFAULT 0,
change_reason TEXT,
operator_id UUID,
operator_name TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.production_price_history (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES purchaser.production_plans(id) ON DELETE CASCADE,
old_price NUMERIC NOT NULL DEFAULT 0,
new_price NUMERIC NOT NULL DEFAULT 0,
change_amount NUMERIC NOT NULL DEFAULT 0,
change_reason TEXT,
operator_id UUID,
operator_name TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.accounts_payable (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES purchaser.production_plans(id),
purchaser_id UUID NOT NULL REFERENCES common.companies(id),
textile_factory_id UUID NOT NULL REFERENCES common.companies(id),
price_per_meter NUMERIC NOT NULL DEFAULT 0,
total_quantity NUMERIC NOT NULL DEFAULT 0,
total_amount NUMERIC NOT NULL DEFAULT 0,
paid_quantity NUMERIC NOT NULL DEFAULT 0,
paid_amount NUMERIC NOT NULL DEFAULT 0,
unpaid_quantity NUMERIC NOT NULL DEFAULT 0,
unpaid_amount NUMERIC NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.accounts_payable_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
accounts_payable_id UUID NOT NULL REFERENCES purchaser.accounts_payable(id) ON DELETE CASCADE,
inventory_record_id UUID,
payment_id UUID,
quantity NUMERIC NOT NULL DEFAULT 0,
price_per_meter NUMERIC NOT NULL DEFAULT 0,
amount NUMERIC NOT NULL DEFAULT 0,
rolls INT,
status TEXT NOT NULL DEFAULT 'pending',
paid_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS purchaser.washing_plans (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_code TEXT NOT NULL,
company_id UUID NOT NULL REFERENCES common.companies(id),
product_id UUID NOT NULL REFERENCES purchaser.products(id),
washing_factory_id UUID REFERENCES common.companies(id),
planned_meters NUMERIC NOT NULL DEFAULT 0,
washing_price NUMERIC NOT NULL DEFAULT 0,
estimated_shrinkage_rate NUMERIC NOT NULL DEFAULT 0,
estimated_washed_meters NUMERIC,
estimated_total_cost NUMERIC,
actual_shrinkage_rate NUMERIC,
actual_washed_meters NUMERIC,
actual_total_cost NUMERIC,
washing_date TIMESTAMPTZ,
status TEXT NOT NULL DEFAULT 'pending',
notes TEXT,
created_by UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- =============================================
-- 5. textile Schema 表
-- =============================================
CREATE TABLE IF NOT EXISTS textile.plan_process_steps (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES purchaser.production_plans(id) ON DELETE CASCADE,
step_type step_type NOT NULL,
status step_status NOT NULL DEFAULT 'pending',
notes TEXT,
operator_id UUID,
company_id UUID,
timestamp TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS textile.warehouses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES common.companies(id),
name TEXT NOT NULL,
type warehouse_type NOT NULL,
location TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS textile.inventory_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES purchaser.production_plans(id),
warehouse_id UUID NOT NULL REFERENCES textile.warehouses(id),
quantity NUMERIC NOT NULL DEFAULT 0,
rolls INT,
price_per_meter NUMERIC,
price_note TEXT,
warehouse_location TEXT,
operator_id UUID,
company_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS textile.yarn_stock (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES common.companies(id),
name TEXT NOT NULL,
spec TEXT,
quantity NUMERIC NOT NULL DEFAULT 0,
unit TEXT NOT NULL DEFAULT 'kg',
min_stock NUMERIC NOT NULL DEFAULT 0,
warehouse_id UUID REFERENCES textile.warehouses(id),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS textile.yarn_stock_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
yarn_stock_id UUID REFERENCES textile.yarn_stock(id),
company_id UUID NOT NULL REFERENCES common.companies(id),
record_type TEXT NOT NULL,
quantity NUMERIC NOT NULL DEFAULT 0,
unit TEXT NOT NULL DEFAULT 'kg',
batch_no TEXT,
plan_id UUID,
notes TEXT,
operator_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS textile.payments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
plan_id UUID NOT NULL REFERENCES purchaser.production_plans(id),
from_company_id UUID NOT NULL REFERENCES common.companies(id),
to_company_id UUID NOT NULL REFERENCES common.companies(id),
amount NUMERIC NOT NULL DEFAULT 0,
quantity NUMERIC NOT NULL DEFAULT 0,
price_per_meter NUMERIC NOT NULL DEFAULT 0,
status payment_status NOT NULL DEFAULT 'pending',
paid_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- =============================================
-- 6. washing Schema 表
-- =============================================
CREATE TABLE IF NOT EXISTS washing.washing_process_steps (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
washing_plan_id UUID NOT NULL REFERENCES purchaser.washing_plans(id) ON DELETE CASCADE,
company_id UUID NOT NULL REFERENCES common.companies(id),
step_type TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
notes TEXT,
operator_id UUID,
timestamp TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS washing.washing_plan_completions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
washing_plan_id UUID NOT NULL REFERENCES purchaser.washing_plans(id),
company_id UUID NOT NULL REFERENCES common.companies(id),
actual_shrinkage_rate NUMERIC NOT NULL,
actual_washed_meters NUMERIC NOT NULL,
actual_washing_cost NUMERIC,
unit_cost NUMERIC,
rolls INT NOT NULL DEFAULT 0,
washing_date DATE NOT NULL,
notes TEXT,
completed_by UUID,
completed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
finished_product_id UUID,
auto_imported BOOLEAN DEFAULT false,
warehouse_id UUID,
warehouse_location TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS washing.finished_products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
company_id UUID NOT NULL REFERENCES common.companies(id),
product_name TEXT NOT NULL,
fabric_code TEXT NOT NULL,
color TEXT NOT NULL,
color_code TEXT,
weight NUMERIC,
shrinkage_rate NUMERIC NOT NULL DEFAULT 0,
washed_meters NUMERIC NOT NULL DEFAULT 0,
stock_meters NUMERIC NOT NULL DEFAULT 0,
stock_rolls INT NOT NULL DEFAULT 0,
rolls INT,
washing_cost NUMERIC,
unit_cost NUMERIC,
status TEXT NOT NULL DEFAULT 'active',
notes TEXT,
product_id UUID,
washing_plan_id UUID,
warehouse_id UUID,
warehouse_location TEXT,
created_by UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS washing.finished_product_inventory_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
finished_product_id UUID NOT NULL REFERENCES washing.finished_products(id) ON DELETE CASCADE,
company_id UUID NOT NULL REFERENCES common.companies(id),
record_type TEXT NOT NULL,
rolls INT NOT NULL DEFAULT 0,
meters NUMERIC NOT NULL DEFAULT 0,
batch_no TEXT,
notes TEXT,
operator_id UUID,
warehouse_id UUID,
warehouse_location TEXT,
washing_completion_id UUID,
related_order_id UUID,
related_order_type TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- =============================================
-- 7. audit Schema 表
-- =============================================
CREATE TABLE IF NOT EXISTS audit.audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
company_id UUID,
action TEXT NOT NULL,
resource_type TEXT NOT NULL,
resource_id UUID,
details JSONB,
ip_address TEXT,
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS audit.data_audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
table_name TEXT NOT NULL,
record_id TEXT NOT NULL,
operation TEXT NOT NULL,
old_values JSONB,
new_values JSONB,
changed_by UUID,
error_message TEXT,
validation_passed BOOLEAN NOT NULL DEFAULT true,
changed_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- =============================================
-- 8. 跨 Schema 只读视图
-- =============================================
-- textile-service 需要读取分配给自己的计划
CREATE OR REPLACE VIEW textile.v_assigned_plans AS
SELECT
pp.id, pp.plan_code, pp.product_name, pp.fabric_code,
pp.color, pp.color_code, pp.target_quantity, pp.completed_quantity,
pp.production_price, pp.yarn_usage_per_meter, pp.status,
pp.remark, pp.start_time, pp.created_at, pp.updated_at,
pf.factory_id, pf.id AS plan_factory_id,
c.name AS purchaser_name
FROM purchaser.production_plans pp
JOIN purchaser.plan_factories pf ON pp.id = pf.plan_id
JOIN common.companies c ON pp.purchaser_id = c.id
WHERE pf.factory_type = 'textile';
-- washing-service 需要读取分配给自己的水洗计划
CREATE OR REPLACE VIEW washing.v_assigned_washing_plans AS
SELECT
wp.id, wp.plan_code, wp.company_id, wp.product_id,
wp.washing_factory_id, wp.planned_meters, wp.washing_price,
wp.estimated_shrinkage_rate, wp.estimated_washed_meters,
wp.estimated_total_cost, wp.actual_shrinkage_rate,
wp.actual_washed_meters, wp.actual_total_cost,
wp.washing_date, wp.status, wp.notes, wp.created_at, wp.updated_at,
p.product_name, p.fabric_code, p.color, p.color_code,
c.name AS purchaser_name
FROM purchaser.washing_plans wp
LEFT JOIN purchaser.products p ON wp.product_id = p.id
LEFT JOIN common.companies c ON wp.company_id = c.id;
-- purchaser-service 需要读取计划的流程步骤
CREATE OR REPLACE VIEW purchaser.v_plan_steps AS
SELECT
ps.id, ps.plan_id, ps.step_type, ps.status,
ps.notes, ps.operator_id, ps.company_id, ps.timestamp, ps.created_at,
pr.display_name AS operator_name
FROM textile.plan_process_steps ps
LEFT JOIN common.profiles pr ON ps.operator_id = pr.id;
-- purchaser-service 需要读取入库记录
CREATE OR REPLACE VIEW purchaser.v_plan_inventory AS
SELECT
ir.id, ir.plan_id, ir.warehouse_id, ir.quantity, ir.rolls,
ir.price_per_meter, ir.price_note, ir.warehouse_location,
ir.operator_id, ir.company_id, ir.created_at,
w.name AS warehouse_name,
pr.display_name AS operator_name
FROM textile.inventory_records ir
LEFT JOIN textile.warehouses w ON ir.warehouse_id = w.id
LEFT JOIN common.profiles pr ON ir.operator_id = pr.id;
-- =============================================
-- 9. 索引
-- =============================================
CREATE INDEX IF NOT EXISTS idx_profiles_username ON common.profiles(username);
CREATE INDEX IF NOT EXISTS idx_profiles_company ON common.profiles(company_id);
CREATE INDEX IF NOT EXISTS idx_company_members_company ON common.company_members(company_id);
CREATE INDEX IF NOT EXISTS idx_company_relationships_purchaser ON common.company_relationships(purchaser_company_id);
CREATE INDEX IF NOT EXISTS idx_company_relationships_factory ON common.company_relationships(factory_company_id);
CREATE INDEX IF NOT EXISTS idx_notifications_recipient ON common.notifications(recipient_id);
CREATE INDEX IF NOT EXISTS idx_share_links_code ON common.share_links(short_code);
CREATE INDEX IF NOT EXISTS idx_plans_purchaser ON purchaser.production_plans(purchaser_id);
CREATE INDEX IF NOT EXISTS idx_plans_status ON purchaser.production_plans(status);
CREATE INDEX IF NOT EXISTS idx_plan_factories_plan ON purchaser.plan_factories(plan_id);
CREATE INDEX IF NOT EXISTS idx_plan_factories_factory ON purchaser.plan_factories(factory_id);
CREATE INDEX IF NOT EXISTS idx_yarn_ratios_plan ON purchaser.yarn_ratios(plan_id);
CREATE INDEX IF NOT EXISTS idx_products_company ON purchaser.products(company_id);
CREATE INDEX IF NOT EXISTS idx_product_inventory_product ON purchaser.product_inventory_records(product_id);
CREATE INDEX IF NOT EXISTS idx_ap_purchaser ON purchaser.accounts_payable(purchaser_id);
CREATE INDEX IF NOT EXISTS idx_washing_plans_company ON purchaser.washing_plans(company_id);
CREATE INDEX IF NOT EXISTS idx_washing_plans_factory ON purchaser.washing_plans(washing_factory_id);
CREATE INDEX IF NOT EXISTS idx_process_steps_plan ON textile.plan_process_steps(plan_id);
CREATE INDEX IF NOT EXISTS idx_inventory_plan ON textile.inventory_records(plan_id);
CREATE INDEX IF NOT EXISTS idx_yarn_stock_company ON textile.yarn_stock(company_id);
CREATE INDEX IF NOT EXISTS idx_yarn_records_stock ON textile.yarn_stock_records(yarn_stock_id);
CREATE INDEX IF NOT EXISTS idx_payments_to ON textile.payments(to_company_id);
CREATE INDEX IF NOT EXISTS idx_washing_steps_plan ON washing.washing_process_steps(washing_plan_id);
CREATE INDEX IF NOT EXISTS idx_completions_plan ON washing.washing_plan_completions(washing_plan_id);
CREATE INDEX IF NOT EXISTS idx_finished_products_company ON washing.finished_products(company_id);
CREATE INDEX IF NOT EXISTS idx_fp_inventory_product ON washing.finished_product_inventory_records(finished_product_id);
-- =============================================
-- 10. 权限授予
-- =============================================
GRANT USAGE ON SCHEMA common TO iloom;
GRANT USAGE ON SCHEMA purchaser TO iloom;
GRANT USAGE ON SCHEMA textile TO iloom;
GRANT USAGE ON SCHEMA washing TO iloom;
GRANT USAGE ON SCHEMA audit TO iloom;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA common TO iloom;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA purchaser TO iloom;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA textile TO iloom;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA washing TO iloom;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA audit TO iloom;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA common TO iloom;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA purchaser TO iloom;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA textile TO iloom;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA washing TO iloom;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA audit TO iloom;
ALTER DEFAULT PRIVILEGES IN SCHEMA common GRANT ALL ON TABLES TO iloom;
ALTER DEFAULT PRIVILEGES IN SCHEMA purchaser GRANT ALL ON TABLES TO iloom;
ALTER DEFAULT PRIVILEGES IN SCHEMA textile GRANT ALL ON TABLES TO iloom;
ALTER DEFAULT PRIVILEGES IN SCHEMA washing GRANT ALL ON TABLES TO iloom;
ALTER DEFAULT PRIVILEGES IN SCHEMA audit GRANT ALL ON TABLES TO iloom;