Files
Autoparts-DB/pos/blueprints/peer_bp.py
consultoria-as e95f7cf684 feat: complete session — catalog, marketplace, WhatsApp, peer-to-peer, install scripts
Major features:
- Pixel-Perfect glassmorphism design (landing + POS + public catalog)
- OEM/Local catalog toggle with Nexpart taxonomy (14 groups, 108 subgroups, 558 part types)
- Marketplace B2B Phase 1 (bodegas, POs, status machine, WA+email notifications)
- Peer-to-peer inventory (multi-instance, LAN discovery)
- WhatsApp: photo→Vision AI, voice→Whisper, conversational quotations
- Smart unified search (VIN/plate/part_number/keyword auto-detect)
- Shop Supplies tab (vehicle-independent parts)
- Chatbot AI fallback chain (5 models) + response cache
- CSV inventory import tool + setup_instance.sh installer
- Tablet-responsive CSS + sidebar toggle
- Filters, export CSV, employee edit, business data save
- Quotation system (WA→POS) with auto-print on confirmation
- Live stats on landing page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 05:35:53 +00:00

96 lines
3.3 KiB
Python

"""
Peer API — public endpoints for inter-instance communication.
These endpoints do NOT require auth (they're called machine-to-machine by
other Nexus instances on the network). They expose read-only inventory data
so the marketplace can aggregate stock across the whole Nexus network.
Routes:
GET /pos/api/peer/health — instance status + inventory count
GET /pos/api/peer/inventory — search this instance's inventory
"""
from flask import Blueprint, request, jsonify, g
from tenant_db import get_tenant_conn
from services import peer_service
peer_bp = Blueprint('peer', __name__, url_prefix='/pos/api/peer')
# ─── Which tenant to use for the peer endpoint? ──────────────────────────
# In production each instance serves one tenant. For the demo, we hardcode
# tenant_id=11 (the demo refaccionaria). This will be read from a config
# file in the future when each instance has exactly 1 active tenant.
import os
import json
def _get_local_tenant_id():
"""Read the local tenant ID from peers.json or fall back to 11."""
try:
cfg_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'peers.json')
with open(cfg_path, 'r') as f:
cfg = json.load(f)
return cfg.get('tenant_id', 11)
except Exception:
return 11
@peer_bp.route('/health', methods=['GET'])
def peer_health():
"""Public health check — no auth. Returns instance name + basic stats."""
tenant_id = _get_local_tenant_id()
inventory_count = 0
try:
conn = get_tenant_conn(tenant_id)
cur = conn.cursor()
cur.execute("""
SELECT COUNT(*) FROM inventory i
WHERE i.is_active = TRUE
AND COALESCE((SELECT SUM(quantity) FROM inventory_operations WHERE inventory_id = i.id), 0) > 0
""")
inventory_count = cur.fetchone()[0]
cur.close()
conn.close()
except Exception as e:
print(f'[peer] health check DB error: {e}')
return jsonify({
'status': 'ok',
'instance_name': peer_service.get_instance_name(),
'instance_id': peer_service.get_instance_id(),
'inventory_count': inventory_count,
'peer_count': len(peer_service.get_peers()),
})
@peer_bp.route('/inventory', methods=['GET'])
def peer_inventory():
"""Public inventory search — no auth.
Called by other Nexus instances to see what this refaccionaria has in stock.
Returns minimal data: part number, name, brand, price, stock hint.
Does NOT expose exact stock quantities (competitive info).
Query params:
q: search term (optional — without it, returns popular/all items)
limit: max results (default 50, max 200)
"""
q = request.args.get('q', '').strip() or None
limit = min(request.args.get('limit', 50, type=int), 200)
tenant_id = _get_local_tenant_id()
try:
conn = get_tenant_conn(tenant_id)
data = peer_service.get_local_inventory(conn, query=q, limit=limit)
conn.close()
except Exception as e:
print(f'[peer] inventory query error: {e}')
data = []
return jsonify({
'instance_name': peer_service.get_instance_name(),
'data': data,
'count': len(data),
})