nordabiz/database/migrations/042_membership_applications.sql
Maciej Pienczyn 0f8aca1435 feat: Add membership application system
Implement full online membership application workflow:
- 3-step wizard form with KRS/CEIDG auto-fill
- Admin panel for application review (approve/reject/request changes)
- Company data update requests for existing members
- Dashboard CTA for users without company
- API endpoints for NIP lookup and draft management

New files:
- database/migrations/042_membership_applications.sql
- blueprints/membership/ (routes, templates)
- blueprints/admin/routes_membership.py
- blueprints/api/routes_membership.py
- templates/membership/ and templates/admin/membership*.html

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 12:38:31 +01:00

184 lines
7.2 KiB
SQL

-- ============================================================
-- 042_membership_applications.sql
-- System Zgłoszeń Członkowskich (Membership Application)
-- ============================================================
-- Created: 2026-02-01
-- Description:
-- - Creates membership_applications table for new member applications
-- - Creates company_data_requests table for data update requests
-- - Full workflow support: draft -> submitted -> approved/rejected
-- ============================================================
-- ============================================================
-- 1. MEMBERSHIP APPLICATIONS TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS membership_applications (
id SERIAL PRIMARY KEY,
-- Kto złożył
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
-- Status workflow
-- draft: zapisany szkic
-- submitted: wysłany do rozpatrzenia
-- under_review: w trakcie rozpatrywania
-- changes_requested: prośba o poprawki
-- approved: zatwierdzony
-- rejected: odrzucony
status VARCHAR(20) NOT NULL DEFAULT 'draft',
-- Dane firmy (strona 1 - Deklaracja)
company_name VARCHAR(255) NOT NULL,
nip VARCHAR(10) NOT NULL,
address_postal_code VARCHAR(6),
address_city VARCHAR(100),
address_street VARCHAR(200),
address_number VARCHAR(50),
-- Delegaci do Walnego Zgromadzenia
delegate_1 VARCHAR(150),
delegate_2 VARCHAR(150),
delegate_3 VARCHAR(150),
-- Kontakt (strona 2 - Karta Informacyjna)
website VARCHAR(255),
email VARCHAR(255) NOT NULL,
phone VARCHAR(30),
short_name VARCHAR(100),
-- Informacje dodatkowe
description TEXT,
founded_date DATE,
employee_count INTEGER,
show_employee_count BOOLEAN DEFAULT FALSE,
annual_revenue VARCHAR(50),
related_companies JSONB, -- ["Firma A", "Firma B"]
-- Sekcje i typ działalności (strona 3)
-- Sekcje: turystyka, szkolnictwo, budownictwo, produkcja, handel, uslugi, inna
sections JSONB NOT NULL DEFAULT '[]',
sections_other VARCHAR(200), -- jeśli wybrano "inna"
-- Typ działalności
-- jdg, spolka_cywilna, spolka_jawna, spolka_partnerska, spolka_komandytowa,
-- spolka_komandytowo_akcyjna, sp_z_oo_komandytowa, spolka_akcyjna, sp_z_oo, inna
business_type VARCHAR(50) NOT NULL DEFAULT 'sp_z_oo',
business_type_other VARCHAR(100),
-- Zgody RODO
consent_email BOOLEAN NOT NULL DEFAULT FALSE,
consent_email_address VARCHAR(255),
consent_sms BOOLEAN DEFAULT FALSE,
consent_sms_phone VARCHAR(30),
-- Oświadczenie końcowe
declaration_accepted BOOLEAN NOT NULL DEFAULT FALSE,
declaration_accepted_at TIMESTAMP,
declaration_ip_address VARCHAR(45), -- IPv4/IPv6
-- Dane z rejestru KRS/CEIDG
registry_source VARCHAR(20), -- 'KRS', 'CEIDG', 'manual'
registry_data JSONB, -- surowe dane z API
krs_number VARCHAR(10), -- numer KRS jeśli dotyczy
regon VARCHAR(14),
-- Workflow timestamps
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
submitted_at TIMESTAMP,
reviewed_at TIMESTAMP,
reviewed_by_id INTEGER REFERENCES users(id),
review_comment TEXT,
-- Po zatwierdzeniu
company_id INTEGER REFERENCES companies(id),
member_number VARCHAR(20) -- Nr ewidencyjny członka
);
-- Indeksy
CREATE INDEX IF NOT EXISTS idx_membership_app_status ON membership_applications(status);
CREATE INDEX IF NOT EXISTS idx_membership_app_user ON membership_applications(user_id);
CREATE INDEX IF NOT EXISTS idx_membership_app_nip ON membership_applications(nip);
CREATE INDEX IF NOT EXISTS idx_membership_app_created ON membership_applications(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_membership_app_submitted ON membership_applications(submitted_at DESC);
-- Komentarze
COMMENT ON TABLE membership_applications IS 'Deklaracje przystąpienia do Izby NORDA';
COMMENT ON COLUMN membership_applications.status IS 'Status: draft, submitted, under_review, changes_requested, approved, rejected';
COMMENT ON COLUMN membership_applications.sections IS 'JSON array sekcji tematycznych: turystyka, szkolnictwo, budownictwo, produkcja, handel, uslugi, inna';
COMMENT ON COLUMN membership_applications.registry_source IS 'Źródło danych: KRS, CEIDG lub manual (ręcznie)';
COMMENT ON COLUMN membership_applications.member_number IS 'Numer ewidencyjny członka nadawany przy zatwierdzeniu';
-- ============================================================
-- 2. COMPANY DATA REQUESTS TABLE
-- ============================================================
-- Prostsza tabela dla uzupełnienia danych istniejącej firmy
CREATE TABLE IF NOT EXISTS company_data_requests (
id SERIAL PRIMARY KEY,
-- Typ zgłoszenia
-- update_data: uzupełnienie danych istniejącej firmy (np. brak NIP)
-- claim_company: przejęcie firmy bez właściciela
request_type VARCHAR(30) NOT NULL DEFAULT 'update_data',
-- Kto zgłasza
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
-- Firma (jeśli istnieje)
company_id INTEGER REFERENCES companies(id) ON DELETE SET NULL,
-- NIP wprowadzony przez użytkownika
nip VARCHAR(10) NOT NULL,
-- Dane pobrane z KRS/CEIDG
registry_source VARCHAR(20), -- 'KRS', 'CEIDG'
fetched_data JSONB,
-- Status
-- pending: oczekuje na rozpatrzenie
-- approved: zatwierdzono, dane zaktualizowane
-- rejected: odrzucono
status VARCHAR(20) NOT NULL DEFAULT 'pending',
-- Workflow
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
reviewed_at TIMESTAMP,
reviewed_by_id INTEGER REFERENCES users(id),
review_comment TEXT,
-- Notatka użytkownika
user_note TEXT,
-- Które pola zostały zaktualizowane (przy approve)
applied_fields JSONB
);
-- Indeksy
CREATE INDEX IF NOT EXISTS idx_data_request_status ON company_data_requests(status);
CREATE INDEX IF NOT EXISTS idx_data_request_user ON company_data_requests(user_id);
CREATE INDEX IF NOT EXISTS idx_data_request_company ON company_data_requests(company_id);
CREATE INDEX IF NOT EXISTS idx_data_request_nip ON company_data_requests(nip);
CREATE INDEX IF NOT EXISTS idx_data_request_created ON company_data_requests(created_at DESC);
-- Komentarze
COMMENT ON TABLE company_data_requests IS 'Zgłoszenia uzupełnienia danych firmy przez użytkowników';
COMMENT ON COLUMN company_data_requests.request_type IS 'Typ: update_data (uzupełnienie), claim_company (przejęcie)';
COMMENT ON COLUMN company_data_requests.fetched_data IS 'Dane pobrane z KRS/CEIDG jako JSON';
COMMENT ON COLUMN company_data_requests.applied_fields IS 'Lista pól zaktualizowanych przy zatwierdzeniu';
-- ============================================================
-- 3. GRANT PERMISSIONS
-- ============================================================
GRANT ALL ON TABLE membership_applications TO nordabiz_app;
GRANT USAGE, SELECT ON SEQUENCE membership_applications_id_seq TO nordabiz_app;
GRANT ALL ON TABLE company_data_requests TO nordabiz_app;
GRANT USAGE, SELECT ON SEQUENCE company_data_requests_id_seq TO nordabiz_app;
-- ============================================================
-- MIGRATION COMPLETE
-- ============================================================