Mejoras de sesion: estabilizacion, IA, Nexus Yonke y marketplace B2B
- F0 blindaje: Redis/Celery, pg_hba sin trust LAN, secretos a env 600, backups, webhook auth, jobs muertos - F1 caja: bugs POS, reembolsos al corte, apartados, CFDI, topes de descuento en cotizacion/apartado - F2/F7 IA de catalogo: autocategorizacion, dedup de SKUs con embeddings, OCR de facturas, descripciones, claves SAT, limpieza de fitment - F3 IA en el flujo: vision Yonke, preguntas MeLi, venta cruzada, anomalias, sinonimos, busqueda semantica (rerank/embeddings) - F4/F8 escala y cartera: /metrics+Prometheus+Grafana, pool, score de credito, churn, metricas multi-tenant - Nexus Yonke (M1-M6): modelo de datos 1-de-1, alta por donador, vitrina publica, MeLi usado, consignacion, garantia por dias, reportes, etiquetas - Marketplace B2B entre yonkes (catalogo + pedidos cross-tenant) - Seguridad: auth en /api/admin/* (35 endpoints), alertas por tenant - Migraciones v4.27/v4.28; timers expire-demos y rollup-metrics
This commit is contained in:
113
pos/migrations/v4.27_yonke_m1.sql
Normal file
113
pos/migrations/v4.27_yonke_m1.sql
Normal file
@@ -0,0 +1,113 @@
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
-- v4.27 — Yonke M1: used-parts (parts-usadas) data model
|
||||
-- Additive + idempotent. Runs against tenant DBs.
|
||||
--
|
||||
-- Enables businesses that sell ONLY used parts (yonkes/deshuesaderos):
|
||||
-- * condition (nuevo/usado/reconstruido) + grade (A/B/C/D)
|
||||
-- * unique 1-of-1 pieces (is_unique_piece) with a donor vehicle
|
||||
-- * multiple photos per item (inventory_images)
|
||||
-- * ownership (propio/consigna) + consignment tables
|
||||
-- * warranty expressed in days (for used parts)
|
||||
-- ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
-- ─── 1. inventory: condition / donor / ownership / unique-piece columns ─────
|
||||
ALTER TABLE inventory
|
||||
ADD COLUMN IF NOT EXISTS condition VARCHAR(20) DEFAULT 'nuevo',
|
||||
ADD COLUMN IF NOT EXISTS condition_grade VARCHAR(2),
|
||||
ADD COLUMN IF NOT EXISTS is_unique_piece BOOLEAN DEFAULT FALSE,
|
||||
ADD COLUMN IF NOT EXISTS serial_number VARCHAR(100),
|
||||
ADD COLUMN IF NOT EXISTS donor_vin VARCHAR(20),
|
||||
ADD COLUMN IF NOT EXISTS donor_make VARCHAR(60),
|
||||
ADD COLUMN IF NOT EXISTS donor_model VARCHAR(60),
|
||||
ADD COLUMN IF NOT EXISTS donor_year INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS donor_mileage_km INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS ownership VARCHAR(20) DEFAULT 'propio',
|
||||
ADD COLUMN IF NOT EXISTS acquisition_cost NUMERIC(12,2);
|
||||
|
||||
-- CHECK constraints (guarded so re-runs are safe)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'inventory_condition_chk') THEN
|
||||
ALTER TABLE inventory ADD CONSTRAINT inventory_condition_chk
|
||||
CHECK (condition IS NULL OR condition IN ('nuevo','usado','reconstruido'));
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'inventory_ownership_chk') THEN
|
||||
ALTER TABLE inventory ADD CONSTRAINT inventory_ownership_chk
|
||||
CHECK (ownership IS NULL OR ownership IN ('propio','consigna'));
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'inventory_grade_chk') THEN
|
||||
ALTER TABLE inventory ADD CONSTRAINT inventory_grade_chk
|
||||
CHECK (condition_grade IS NULL OR condition_grade IN ('A','B','C','D'));
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_inventory_condition
|
||||
ON inventory(condition);
|
||||
CREATE INDEX IF NOT EXISTS idx_inventory_donor_vin
|
||||
ON inventory(donor_vin) WHERE donor_vin IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_inventory_donor_vehicle
|
||||
ON inventory(donor_make, donor_model, donor_year) WHERE is_unique_piece;
|
||||
|
||||
-- ─── 2. Relax part_number NOT NULL so codeless unique pieces can exist ──────
|
||||
-- A standard UNIQUE index in PostgreSQL already treats NULLs as distinct, so
|
||||
-- the existing full unique index (idx_inventory_part_unique) keeps enforcing
|
||||
-- uniqueness on non-null codes while allowing many NULLs. We deliberately do
|
||||
-- NOT turn it into a partial index: that would break `ON CONFLICT (part_number)`
|
||||
-- used by the importers.
|
||||
ALTER TABLE inventory ALTER COLUMN part_number DROP NOT NULL;
|
||||
|
||||
-- ─── 3. inventory_images: multiple photos per item ─────────────────────────
|
||||
CREATE TABLE IF NOT EXISTS inventory_images (
|
||||
id SERIAL PRIMARY KEY,
|
||||
inventory_id INTEGER NOT NULL REFERENCES inventory(id) ON DELETE CASCADE,
|
||||
url VARCHAR(500) NOT NULL,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
is_primary BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_inventory_images_inv
|
||||
ON inventory_images(inventory_id, sort_order);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_inventory_images_primary
|
||||
ON inventory_images(inventory_id) WHERE is_primary;
|
||||
|
||||
-- Migrate the existing single image_url into the new table (first photo).
|
||||
INSERT INTO inventory_images (inventory_id, url, sort_order, is_primary)
|
||||
SELECT i.id, i.image_url, 0, TRUE
|
||||
FROM inventory i
|
||||
WHERE i.image_url IS NOT NULL AND i.image_url <> ''
|
||||
AND NOT EXISTS (SELECT 1 FROM inventory_images ii WHERE ii.inventory_id = i.id);
|
||||
|
||||
-- ─── 4. warranties: express warranty in days (used parts) ──────────────────
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regclass('public.warranties') IS NOT NULL THEN
|
||||
EXECUTE 'ALTER TABLE warranties ADD COLUMN IF NOT EXISTS warranty_days INTEGER';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- ─── 5. Consignments (third-party parts held for sale) ─────────────────────
|
||||
CREATE TABLE IF NOT EXISTS consignments (
|
||||
id SERIAL PRIMARY KEY,
|
||||
consignor_name VARCHAR(200) NOT NULL,
|
||||
consignor_rfc VARCHAR(13),
|
||||
consignor_phone VARCHAR(30),
|
||||
commission_pct NUMERIC(5,2) DEFAULT 0,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'open', -- open | closed | settled
|
||||
notes TEXT,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS consignment_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
consignment_id INTEGER NOT NULL REFERENCES consignments(id) ON DELETE CASCADE,
|
||||
inventory_id INTEGER REFERENCES inventory(id) ON DELETE SET NULL,
|
||||
agreed_price NUMERIC(12,2),
|
||||
commission_amount NUMERIC(12,2),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'in_stock', -- in_stock | sold | returned | settled
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_consignment_items_cons
|
||||
ON consignment_items(consignment_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_consignment_items_inv
|
||||
ON consignment_items(inventory_id);
|
||||
Reference in New Issue
Block a user