- Add MercadoLibre OAuth, listings, orders, webhooks and category search - New marketplace_external_bp.py, meli_service.py, marketplace_external_service.py - New marketplace_external.html/js with ML management UI - Inventory: bulk publish to ML with category autocomplete, listing type and shipping selectors - Inventory: new .btn--meli styles, select/label CSS fixes - WhatsApp bridge: rate limiting, 440/515/408 error handling, stale watchdog - DB migration v3.4_meli_integration.sql for marketplace_listings, orders, sync_queue - Add Celery tasks for ML sync and webhook processing - Sidebar: MercadoLibre navigation link
111 lines
4.2 KiB
SQL
111 lines
4.2 KiB
SQL
-- ============================================================
|
|
-- v3.4 MercadoLibre Integration
|
|
-- ============================================================
|
|
-- Adds tables for external marketplace listings, orders,
|
|
-- order items, and a generic sync queue.
|
|
-- All tables live in the tenant DB.
|
|
-- ============================================================
|
|
|
|
-- Listings published on MercadoLibre (extensible to Amazon later)
|
|
CREATE TABLE IF NOT EXISTS marketplace_listings (
|
|
id SERIAL PRIMARY KEY,
|
|
inventory_id INTEGER REFERENCES inventory(id),
|
|
channel VARCHAR(20) NOT NULL DEFAULT 'mercadolibre',
|
|
external_item_id VARCHAR(50) NOT NULL,
|
|
external_status VARCHAR(30) DEFAULT 'active',
|
|
external_permalink TEXT,
|
|
title TEXT,
|
|
meli_category_id VARCHAR(30),
|
|
publish_price NUMERIC(12,2),
|
|
last_sync_at TIMESTAMPTZ,
|
|
sync_errors TEXT,
|
|
is_active BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_marketplace_listings_inventory
|
|
ON marketplace_listings(inventory_id);
|
|
CREATE INDEX IF NOT EXISTS idx_marketplace_listings_external
|
|
ON marketplace_listings(external_item_id);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_marketplace_listings_unique
|
|
ON marketplace_listings(inventory_id, channel) WHERE is_active = true;
|
|
|
|
-- Orders received from MercadoLibre
|
|
CREATE TABLE IF NOT EXISTS marketplace_orders (
|
|
id SERIAL PRIMARY KEY,
|
|
channel VARCHAR(20) NOT NULL DEFAULT 'mercadolibre',
|
|
external_order_id VARCHAR(50) NOT NULL UNIQUE,
|
|
external_status VARCHAR(30) NOT NULL,
|
|
buyer_name VARCHAR(200),
|
|
buyer_email VARCHAR(200),
|
|
buyer_phone VARCHAR(50),
|
|
buyer_nickname VARCHAR(100),
|
|
shipping_address JSONB,
|
|
total_amount NUMERIC(12,2),
|
|
shipping_cost NUMERIC(12,2),
|
|
meli_shipping_id VARCHAR(50),
|
|
nexus_sale_id INTEGER REFERENCES sales(id),
|
|
status VARCHAR(20) DEFAULT 'pending',
|
|
notes TEXT,
|
|
raw_json JSONB,
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_marketplace_orders_status
|
|
ON marketplace_orders(status);
|
|
CREATE INDEX IF NOT EXISTS idx_marketplace_orders_external
|
|
ON marketplace_orders(external_order_id);
|
|
|
|
-- Items inside a marketplace order
|
|
CREATE TABLE IF NOT EXISTS marketplace_order_items (
|
|
id SERIAL PRIMARY KEY,
|
|
marketplace_order_id INTEGER REFERENCES marketplace_orders(id) ON DELETE CASCADE,
|
|
inventory_id INTEGER REFERENCES inventory(id),
|
|
external_item_id VARCHAR(50),
|
|
title VARCHAR(300),
|
|
quantity INTEGER NOT NULL,
|
|
unit_price NUMERIC(12,2),
|
|
total_price NUMERIC(12,2),
|
|
listing_id INTEGER REFERENCES marketplace_listings(id)
|
|
);
|
|
|
|
-- Generic sync queue (reusable for future Amazon integration)
|
|
CREATE TABLE IF NOT EXISTS marketplace_sync_queue (
|
|
id SERIAL PRIMARY KEY,
|
|
inventory_id INTEGER REFERENCES inventory(id),
|
|
channel VARCHAR(20) NOT NULL,
|
|
action VARCHAR(20) NOT NULL,
|
|
status VARCHAR(20) DEFAULT 'pending',
|
|
payload JSONB,
|
|
error_message TEXT,
|
|
retry_count INT DEFAULT 0,
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
processed_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_marketplace_sync_queue_pending
|
|
ON marketplace_sync_queue(status, channel) WHERE status = 'pending';
|
|
|
|
-- Add source column to sales to track origin (POS, ML, Amazon, etc.)
|
|
-- If the column already exists from another migration, do nothing.
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_name = 'sales' AND column_name = 'source'
|
|
) THEN
|
|
ALTER TABLE sales ADD COLUMN source VARCHAR(30) DEFAULT 'pos';
|
|
END IF;
|
|
END $$;
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_name = 'sales' AND column_name = 'external_order_id'
|
|
) THEN
|
|
ALTER TABLE sales ADD COLUMN external_order_id VARCHAR(50);
|
|
END IF;
|
|
END $$;
|