Bloqueo catalogo OEM hasta completarse

This commit is contained in:
Nexus Dev
2026-04-27 05:41:35 +00:00
parent 9ff3dc4c8b
commit 142abbc217
5 changed files with 90 additions and 2 deletions

View File

@@ -19,10 +19,22 @@ from tenant_db import get_master_conn, get_tenant_conn
from services import catalog_service
from services.vin_decoder import decode_vin
from services.plate_lookup import search_plate, register_plate, is_valid_mexican_plate, normalize_plate
from config import CATALOG_OEM_ENABLED
catalog_bp = Blueprint('catalog', __name__, url_prefix='/pos/api/catalog')
def _oem_blocked():
"""Return a 403 response if OEM catalog is disabled."""
if not CATALOG_OEM_ENABLED:
return jsonify({
'error': 'Catálogo OEM no disponible',
'message': 'El catálogo OEM está en construcción. Por favor usa el modo Local o Shop Supplies.',
'oem_disabled': True,
}), 403
return None
def _with_conns(fn):
"""Helper: open master + tenant connections, call fn, close both.
fn receives (master_conn, tenant_conn, branch_id).
@@ -298,6 +310,12 @@ def parts():
if not use_nexpart_nav and not group_id:
return jsonify({'error': 'group_id (or nexpart_group + subgroup + part_type) required'}), 400
# Block OEM catalog if not enabled
if mode != 'local' and not use_nexpart_nav:
blocked = _oem_blocked()
if blocked:
return blocked
def _do(master, tenant, branch_id):
if use_nexpart_nav:
result = catalog_service.get_parts_for_nexpart_triple(
@@ -319,6 +337,9 @@ def parts():
@catalog_bp.route('/part/<int:part_id>', methods=['GET'])
@require_auth('catalog.view')
def part_detail(part_id):
blocked = _oem_blocked()
if blocked:
return blocked
def _do(master, tenant, branch_id):
result = catalog_service.get_part_detail(master, part_id, tenant, branch_id)
if not result:
@@ -330,6 +351,9 @@ def part_detail(part_id):
@catalog_bp.route('/search', methods=['GET'])
@require_auth('catalog.view')
def search():
blocked = _oem_blocked()
if blocked:
return blocked
q = request.args.get('q', '').strip()
if not q or len(q) < 2:
return jsonify({'data': []})

View File

@@ -67,3 +67,11 @@ EXCHANGE_RATE_USD_MXN = float(os.environ.get('EXCHANGE_RATE_USD_MXN', '17.5'))
REDIS_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379/0')
REDIS_ENABLED = os.environ.get('REDIS_ENABLED', 'true').lower() == 'true'
REDIS_STOCK_TTL = int(os.environ.get('REDIS_STOCK_TTL', '300'))
# ─── Meilisearch ───────────────────────────────────────────────────────────
MEILI_URL = os.environ.get('MEILI_URL', 'http://localhost:7700')
MEILI_API_KEY = os.environ.get('MEILI_API_KEY', '')
MEILI_ENABLED = os.environ.get('MEILI_ENABLED', 'true').lower() == 'true'
# ─── Catalog OEM Access ────────────────────────────────────────────────────
CATALOG_OEM_ENABLED = os.environ.get('CATALOG_OEM_ENABLED', 'false').lower() == 'true'

View File

@@ -69,7 +69,9 @@
};
// ─── Catalog mode (OEM / Local) ───
var catalogMode = (localStorage.getItem('catalog_mode') === 'local' ? 'local' : 'oem');
// OEM catalog is disabled until fully completed — force local mode
var catalogMode = 'local';
localStorage.setItem('catalog_mode', 'local');
function updateModeToggleUI() {
var btns = document.querySelectorAll('#modeToggle button');
@@ -84,6 +86,11 @@
function setCatalogMode(mode) {
if (mode !== 'oem' && mode !== 'local' && mode !== 'supplies') return;
if (mode === 'oem') {
// OEM catalog is disabled until fully completed
alert('Catálogo OEM próximamente. Por favor usa el modo Local o Shop Supplies.');
return;
}
if (mode === catalogMode) return;
catalogMode = mode;
localStorage.setItem('catalog_mode', mode);

View File

@@ -660,7 +660,7 @@
</nav>
<div class="header-actions" style="position:relative;">
<div class="mode-toggle" id="modeToggle" title="Cambiar entre catalogo OEM (TecDoc), marcas locales y consumibles">
<button data-mode="oem" onclick="CatalogApp.setMode('oem')">OEM</button>
<button data-mode="oem" onclick="CatalogApp.setMode('oem')" disabled style="opacity:0.5;cursor:not-allowed;" title="Próximamente">OEM 🔒</button>
<button data-mode="local" onclick="CatalogApp.setMode('local')">Local</button>
<button data-mode="supplies" onclick="CatalogApp.setMode('supplies')" title="Aceites, quimicos, herramientas — sin vehiculo">Supplies</button>
</div>

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python3
"""Test OEM catalog block."""
import os, sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from tenant_db import get_master_conn, get_tenant_conn_by_dbname
from services.catalog_service import smart_search, get_part_detail
PASS = '\033[92mPASS\033[0m'
FAIL = '\033[91mFAIL\033[0m'
def ok(label, condition, detail=''):
if condition:
print(f" [{PASS}] {label}")
else:
print(f" [{FAIL}] {label} {detail}")
master = get_master_conn()
cur = master.cursor()
cur.execute("SELECT db_name FROM tenants WHERE is_active = true LIMIT 1")
row = cur.fetchone()
cur.close(); master.close()
db_name = row[0]
tenant = get_tenant_conn_by_dbname(db_name)
master = get_master_conn()
print("OEM Catalog Block Test")
print("=" * 40)
# smart_search should be blocked at blueprint level, but let's check the service
# The service itself still works; the blueprint blocks it.
# Let's verify the config flag is False
from config import CATALOG_OEM_ENABLED
ok("CATALOG_OEM_ENABLED is False", CATALOG_OEM_ENABLED is False, f"value={CATALOG_OEM_ENABLED}")
# Local mode endpoints should still work
from services.catalog_modes import normalize_mode
ok("normalize_mode local", normalize_mode('local') == 'local')
ok("normalize_mode oem", normalize_mode('oem') == 'oem')
# Check that get_parts_local is available
from services.catalog_service import get_parts_local
ok("get_parts_local exists", callable(get_parts_local))
master.close()
tenant.close()
print("Done.")