Bloqueo catalogo OEM hasta completarse
This commit is contained in:
@@ -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': []})
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
49
pos/tests/test_oem_block.py
Normal file
49
pos/tests/test_oem_block.py
Normal 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.")
|
||||
Reference in New Issue
Block a user