/** * Commercial bounded context: quotes (ofertas) — the pricing/fidelity/ * approval core of the legacy system, eden.md module 2. Ported with exact * fidelity to the formulas documented there (see apps/api/src/quotes/ * pricing.ts for the calculation engine itself). * * `client_registration_id` is added as a plain nullable UUID WITHOUT a * foreign key — the Customer 360 module (client_registrations table) is * being built in parallel by another agent and doesn't exist yet in this * migration's context. The FK is added in a follow-up migration once both * land (this mirrors the legacy's own history: client_registration_id was * itself added to quotes in a later migration, 1785513008756). * * `users.can_approve_discount` is added here too (small, single-column * change) since it's exclusively needed by the discount-approval rule * this migration's quotes table exists to support — eden.md §1.1: * `canApproveDiscount(user) = super_admin || (admin && can_approve_discount)`. */ exports.shorthands = undefined; exports.up = (pgm) => { pgm.sql(` ALTER TABLE users ADD COLUMN can_approve_discount BOOLEAN NOT NULL DEFAULT false; COMMENT ON COLUMN users.can_approve_discount IS 'Business flag (not a role) — an admin can approve a quote''s discount/reduced-fidelity exception only if this is true; super_admin always can, regardless of this flag. eden.md §1.1, §3.3.'; CREATE SEQUENCE quotes_quote_number_seq START 1; CREATE TABLE quotes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), created_by UUID REFERENCES users(id), quote_number TEXT NOT NULL UNIQUE DEFAULT ('Q-' || to_char(now(), 'YYYY') || '-' || lpad(nextval('quotes_quote_number_seq')::text, 6, '0')), reseller_id UUID NOT NULL REFERENCES resellers(id), client_name TEXT NOT NULL, client_company TEXT, client_email TEXT, client_phone TEXT NOT NULL, contract_period INTEGER NOT NULL DEFAULT 0 CHECK (contract_period IN (0,12,24,36,48)), fidelity_period INTEGER CHECK (fidelity_period IS NULL OR (fidelity_period >= 0 AND fidelity_period <= contract_period)), items JSONB NOT NULL DEFAULT '[]'::jsonb, implementation_fee NUMERIC(12,2) NOT NULL DEFAULT 0, impl_geral NUMERIC(12,2) NOT NULL DEFAULT 0, monthly_total NUMERIC(12,2) NOT NULL DEFAULT 0, contract_total NUMERIC(12,2) NOT NULL DEFAULT 0, proposed_monthly_total NUMERIC(12,2), approval_status TEXT NOT NULL DEFAULT 'none' CHECK (approval_status IN ('none','pending','approved','rejected')), approval_notes TEXT, approved_by_id UUID REFERENCES users(id), notes TEXT, deal_status TEXT NOT NULL DEFAULT 'orcamento' CHECK (deal_status IN ('orcamento','fechado','perdido')), impl_payment_condition TEXT NOT NULL DEFAULT 'À vista' CHECK (impl_payment_condition IN ('À vista','1+1','1+2')), client_registration_id UUID ); COMMENT ON TABLE quotes IS 'Ofertas comerciais — eden.md módulo 2. contract_period é a faixa de preço; fidelity_period é a permanência efetiva quando MENOR que a faixa, só produz efeito legal (vigência/multa) depois de approval_status=approved (eden.md §3.4). client_registration_id referencia client_registrations (Customer 360) sem FK por enquanto — ver comentário no topo desta migration.'; COMMENT ON COLUMN quotes.client_registration_id IS 'Setar este campo trava a oferta para edição (exceto super_admin) — eden.md §5.1. FK a ser adicionada em migration futura quando client_registrations existir.'; COMMENT ON COLUMN quotes.impl_payment_condition IS 'À vista / 1+1 / 1+2 — progressivo por faixa de valor de implantação, eden.md §7 (paymentConditions.js). Faixas validadas na aplicação, não aqui.'; CREATE TRIGGER trg_quotes_updated_at BEFORE UPDATE ON quotes FOR EACH ROW EXECUTE FUNCTION set_updated_at(); CREATE INDEX idx_quotes_reseller ON quotes(reseller_id); CREATE INDEX idx_quotes_deal_status ON quotes(deal_status); CREATE INDEX idx_quotes_created_by ON quotes(created_by); CREATE INDEX idx_quotes_client_registration ON quotes(client_registration_id); ALTER SEQUENCE quotes_quote_number_seq OWNED BY NONE; `); }; exports.down = (pgm) => { pgm.sql(` DROP TABLE IF EXISTS quotes; DROP SEQUENCE IF EXISTS quotes_quote_number_seq; ALTER TABLE users DROP COLUMN IF EXISTS can_approve_discount; `); };