216 lines
7.6 KiB
PL/PgSQL
216 lines
7.6 KiB
PL/PgSQL
BEGIN;
|
|
|
|
-- Market Management base schema.
|
|
-- Fachliche Ownership: market_management.
|
|
|
|
CREATE TABLE market_category (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
code TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE UNIQUE INDEX uq_market_category_code ON market_category(code);
|
|
CREATE UNIQUE INDEX uq_market_category_name ON market_category(name);
|
|
|
|
INSERT INTO market_category (code, name)
|
|
VALUES
|
|
('herbstmarkt', 'Herbstmärkte'),
|
|
('weihnachtsmarkt', 'Weihnachtsmärkte'),
|
|
('fruehlingsmarkt', 'Frühlingsmärkte'),
|
|
('ostermarkt', 'Ostermärkte'),
|
|
('kunsthandwerksmarkt', 'Kunsthandwerksmärkte'),
|
|
('regionalmarkt', 'Regionalmärkte'),
|
|
('weitere_geeignete_maerkte', 'Weitere geeignete Märkte');
|
|
|
|
CREATE TABLE market_municipality_reference (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
bfs_municipality_number INTEGER NOT NULL,
|
|
name TEXT NOT NULL,
|
|
canton_code TEXT NOT NULL,
|
|
data_version DATE NOT NULL,
|
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE UNIQUE INDEX uq_market_municipality_reference_bfs_number_version
|
|
ON market_municipality_reference(bfs_municipality_number, data_version);
|
|
CREATE INDEX idx_market_municipality_reference_canton
|
|
ON market_municipality_reference(canton_code, name);
|
|
|
|
CREATE TABLE market_definition (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
category_id BIGINT NOT NULL REFERENCES market_category(id) ON DELETE RESTRICT,
|
|
archived_at TIMESTAMP,
|
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE UNIQUE INDEX uq_market_definition_name ON market_definition(name);
|
|
CREATE INDEX idx_market_definition_category ON market_definition(category_id);
|
|
|
|
CREATE TABLE market_occurrence (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
market_definition_id BIGINT NOT NULL REFERENCES market_definition(id) ON DELETE RESTRICT,
|
|
status TEXT NOT NULL DEFAULT 'open',
|
|
place TEXT,
|
|
address TEXT,
|
|
municipality_reference_id BIGINT REFERENCES market_municipality_reference(id) ON DELETE RESTRICT,
|
|
notes TEXT,
|
|
registration_deadline DATE,
|
|
request_or_registration_date DATE,
|
|
confirmation_date DATE,
|
|
payment_deadline DATE,
|
|
stand_size TEXT,
|
|
table_available BOOLEAN,
|
|
table_rentable BOOLEAN,
|
|
own_table_required BOOLEAN,
|
|
shelter_available BOOLEAN,
|
|
power_available BOOLEAN,
|
|
water_available BOOLEAN,
|
|
lighting_available BOOLEAN,
|
|
other_infrastructure TEXT,
|
|
own_stand_requirements TEXT,
|
|
travel_address TEXT,
|
|
travel_distance_km NUMERIC(10, 2),
|
|
travel_duration_minutes INTEGER,
|
|
parking_options TEXT,
|
|
delivery_access TEXT,
|
|
direct_unload_possible BOOLEAN,
|
|
storage_options TEXT,
|
|
travel_notes TEXT,
|
|
payment_status TEXT NOT NULL DEFAULT 'unpaid',
|
|
payment_date DATE,
|
|
paid_amount NUMERIC(14, 2),
|
|
payment_method_code TEXT,
|
|
cancellation_terms TEXT,
|
|
revenue_share_terms TEXT,
|
|
other_participation_conditions TEXT,
|
|
contract_folder_url TEXT,
|
|
archived_at TIMESTAMP,
|
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT chk_market_occurrence_status CHECK (
|
|
status IN ('open', 'waitlist', 'registered', 'confirmation_pending', 'confirmed', 'cancelled', 'completed')
|
|
),
|
|
CONSTRAINT chk_market_occurrence_payment_status CHECK (
|
|
payment_status IN ('paid', 'unpaid')
|
|
),
|
|
CONSTRAINT chk_market_occurrence_travel_distance CHECK (
|
|
travel_distance_km IS NULL OR travel_distance_km >= 0
|
|
),
|
|
CONSTRAINT chk_market_occurrence_travel_duration CHECK (
|
|
travel_duration_minutes IS NULL OR travel_duration_minutes >= 0
|
|
),
|
|
CONSTRAINT chk_market_occurrence_paid_amount CHECK (
|
|
paid_amount IS NULL OR paid_amount >= 0
|
|
)
|
|
);
|
|
|
|
CREATE INDEX idx_market_occurrence_market ON market_occurrence(market_definition_id);
|
|
CREATE INDEX idx_market_occurrence_status ON market_occurrence(status);
|
|
CREATE INDEX idx_market_occurrence_municipality
|
|
ON market_occurrence(municipality_reference_id);
|
|
CREATE INDEX idx_market_occurrence_archived_at ON market_occurrence(archived_at);
|
|
|
|
CREATE TABLE market_occurrence_organizer (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
occurrence_id BIGINT NOT NULL UNIQUE REFERENCES market_occurrence(id) ON DELETE RESTRICT,
|
|
organization_contact_id BIGINT NOT NULL,
|
|
contact_person_id BIGINT NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX idx_market_occurrence_organizer_organization
|
|
ON market_occurrence_organizer(organization_contact_id);
|
|
CREATE INDEX idx_market_occurrence_organizer_contact_person
|
|
ON market_occurrence_organizer(contact_person_id);
|
|
|
|
CREATE TABLE market_occurrence_day (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
occurrence_id BIGINT NOT NULL REFERENCES market_occurrence(id) ON DELETE RESTRICT,
|
|
date DATE NOT NULL,
|
|
stand_start_time TIME,
|
|
stand_end_time TIME,
|
|
setup_start_time TIME,
|
|
setup_end_time TIME,
|
|
delivery_start_time TIME,
|
|
delivery_end_time TIME,
|
|
observations TEXT,
|
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT chk_market_occurrence_day_stand_time CHECK (
|
|
stand_start_time IS NULL OR stand_end_time IS NULL OR stand_end_time >= stand_start_time
|
|
),
|
|
CONSTRAINT chk_market_occurrence_day_setup_time CHECK (
|
|
setup_start_time IS NULL OR setup_end_time IS NULL OR setup_end_time >= setup_start_time
|
|
),
|
|
CONSTRAINT chk_market_occurrence_day_delivery_time CHECK (
|
|
delivery_start_time IS NULL OR delivery_end_time IS NULL OR delivery_end_time >= delivery_start_time
|
|
)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX uq_market_occurrence_day_date ON market_occurrence_day(occurrence_id, date);
|
|
CREATE INDEX idx_market_occurrence_day_date ON market_occurrence_day(date);
|
|
|
|
CREATE TABLE market_occurrence_cost_item (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
occurrence_id BIGINT NOT NULL REFERENCES market_occurrence(id) ON DELETE RESTRICT,
|
|
cost_type TEXT NOT NULL,
|
|
description TEXT,
|
|
gross_amount NUMERIC(14, 2) NOT NULL,
|
|
tax_status TEXT NOT NULL,
|
|
tax_rate NUMERIC(5, 2) NOT NULL DEFAULT 0,
|
|
tax_amount NUMERIC(14, 2) GENERATED ALWAYS AS (
|
|
CASE
|
|
WHEN tax_status = 'tax_free' THEN 0
|
|
ELSE ROUND(gross_amount - gross_amount / (1 + tax_rate / 100), 2)
|
|
END
|
|
) STORED,
|
|
net_amount NUMERIC(14, 2) GENERATED ALWAYS AS (
|
|
gross_amount - CASE
|
|
WHEN tax_status = 'tax_free' THEN 0
|
|
ELSE ROUND(gross_amount - gross_amount / (1 + tax_rate / 100), 2)
|
|
END
|
|
) STORED,
|
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT chk_market_occurrence_cost_gross_nonnegative CHECK (gross_amount >= 0),
|
|
CONSTRAINT chk_market_occurrence_cost_tax_status CHECK (tax_status IN ('tax_free', 'taxable')),
|
|
CONSTRAINT chk_market_occurrence_cost_tax_rate CHECK (
|
|
(tax_status = 'tax_free' AND tax_rate = 0)
|
|
OR (tax_status = 'taxable' AND tax_rate > 0)
|
|
)
|
|
);
|
|
|
|
CREATE INDEX idx_market_occurrence_cost_item_occurrence
|
|
ON market_occurrence_cost_item(occurrence_id);
|
|
|
|
CREATE TABLE market_mcp_idempotency (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_subject TEXT NOT NULL,
|
|
client_id TEXT NOT NULL,
|
|
idempotency_key TEXT NOT NULL,
|
|
tool_name TEXT NOT NULL,
|
|
request_hash TEXT NOT NULL,
|
|
result_status TEXT NOT NULL,
|
|
result_entity_type TEXT,
|
|
result_entity_id TEXT,
|
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
expires_at TIMESTAMP NOT NULL,
|
|
CONSTRAINT chk_market_mcp_idempotency_result_status CHECK (
|
|
result_status IN ('processing', 'succeeded', 'failed')
|
|
)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX uq_market_mcp_idempotency_client_key
|
|
ON market_mcp_idempotency(client_id, idempotency_key);
|
|
CREATE INDEX idx_market_mcp_idempotency_expiry ON market_mcp_idempotency(expires_at);
|
|
|
|
COMMIT;
|