FASE 4-5-6: Infraestructura, CRM, Service Orders, Notificaciones, Ahorro, Logistica, API Publica
FASE 4: - Redis cache de stock con fallback graceful - Multi-moneda (MXN/USD) con contabilidad en MXN - Proveedores y ordenes de compra completo - Meilisearch 1.5M+ partes indexadas - Metabase KPIs con dashboard auto-generado FASE 5: - CRM mejorado: activities, tags, loyalty program, analytics - Imagenes de partes: upload, resize, thumbnails WebP - Ordenes de servicio Kanban: received->diagnosis->repair->ready->delivered - Garantias/RMA, alertas de reorden, multi-sucursal - Stubs BNPL (APLAZO) y ERP Sync (Aspel/Contpaqi) FASE 6: - Notificaciones automaticas: push/WhatsApp/email/in-app - Reportes de ahorro vs retail_price - Logistica + tracking: DHL, FedEx, Estafeta, 99min, Uber - API Publica: API keys, rate limiting, catalog search Migraciones: v1.9-v3.0 Tests: 93/93 pasando Backup: nexus_backup_20260427_045859.tar.gz
This commit is contained in:
82
pos/migrations/v2.9_logistics.sql
Normal file
82
pos/migrations/v2.9_logistics.sql
Normal file
@@ -0,0 +1,82 @@
|
||||
-- v2.9 Logistics & Shipment Tracking
|
||||
|
||||
-- Couriers / carriers
|
||||
CREATE TABLE IF NOT EXISTS couriers (
|
||||
id SERIAL PRIMARY KEY,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
name VARCHAR(100) NOT NULL, -- 'DHL', 'FedEx', 'Estafeta', '99minutos', 'Uber Direct'
|
||||
code VARCHAR(20) NOT NULL, -- internal code
|
||||
tracking_url_template VARCHAR(500), -- e.g. "https://www.dhl.com/track?trackingNumber={tracking_number}"
|
||||
api_endpoint VARCHAR(500),
|
||||
api_key_encrypted TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_couriers_code ON couriers(tenant_id, code);
|
||||
|
||||
-- Shipments
|
||||
CREATE TABLE IF NOT EXISTS shipments (
|
||||
id SERIAL PRIMARY KEY,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
branch_id INTEGER REFERENCES branches(id),
|
||||
shipment_type VARCHAR(20) DEFAULT 'outbound', -- outbound, inbound, return
|
||||
related_type VARCHAR(50), -- 'sale', 'purchase_order', 'service_order', 'marketplace_order'
|
||||
related_id INTEGER,
|
||||
courier_id INTEGER REFERENCES couriers(id),
|
||||
tracking_number VARCHAR(100),
|
||||
tracking_url VARCHAR(500),
|
||||
status VARCHAR(30) DEFAULT 'pending', -- pending, label_created, picked_up, in_transit, out_for_delivery, delivered, failed, returned
|
||||
origin_address TEXT,
|
||||
destination_address TEXT,
|
||||
recipient_name VARCHAR(200),
|
||||
recipient_phone VARCHAR(50),
|
||||
estimated_delivery DATE,
|
||||
actual_delivery TIMESTAMPTZ,
|
||||
shipping_cost NUMERIC(12,2) DEFAULT 0,
|
||||
weight_kg NUMERIC(8,3),
|
||||
dimensions_cm VARCHAR(50), -- "30x20x15"
|
||||
notes TEXT,
|
||||
created_by INTEGER REFERENCES employees(id),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_shipments_tracking ON shipments(tracking_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_shipments_status ON shipments(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_shipments_related ON shipments(related_type, related_id);
|
||||
|
||||
-- Shipment tracking history
|
||||
CREATE TABLE IF NOT EXISTS shipment_tracking (
|
||||
id SERIAL PRIMARY KEY,
|
||||
shipment_id INTEGER NOT NULL REFERENCES shipments(id) ON DELETE CASCADE,
|
||||
status VARCHAR(30) NOT NULL,
|
||||
location VARCHAR(200),
|
||||
description TEXT,
|
||||
raw_response JSONB,
|
||||
tracked_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_shipment_tracking_shipment ON shipment_tracking(shipment_id, tracked_at DESC);
|
||||
|
||||
-- Trigger for updated_at
|
||||
CREATE OR REPLACE FUNCTION update_shipment_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_shipments_updated_at ON shipments;
|
||||
CREATE TRIGGER trg_shipments_updated_at
|
||||
BEFORE UPDATE ON shipments
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_shipment_updated_at();
|
||||
|
||||
-- Insert default couriers
|
||||
INSERT INTO couriers (tenant_id, name, code, tracking_url_template, is_active) VALUES
|
||||
(1, 'DHL Express', 'dhl', 'https://www.dhl.com/mx/es/home/tracking/tracking-ecommerce.html?tracking-id={tracking_number}', true),
|
||||
(1, 'FedEx', 'fedex', 'https://www.fedex.com/apps/fedextrack/?tracknumbers={tracking_number}', true),
|
||||
(1, 'Estafeta', 'estafeta', 'https://www.estafeta.com/herramientas/rastreo?guias={tracking_number}', true),
|
||||
(1, '99 Minutos', '99minutos', 'https://99minutos.com/track/{tracking_number}', true),
|
||||
(1, 'Uber Direct', 'uber_direct', NULL, true),
|
||||
(1, 'Recolección en tienda', 'pickup', NULL, true)
|
||||
ON CONFLICT DO NOTHING;
|
||||
Reference in New Issue
Block a user