Mejoras de sesion: estabilizacion, IA, Nexus Yonke y marketplace B2B
- F0 blindaje: Redis/Celery, pg_hba sin trust LAN, secretos a env 600, backups, webhook auth, jobs muertos - F1 caja: bugs POS, reembolsos al corte, apartados, CFDI, topes de descuento en cotizacion/apartado - F2/F7 IA de catalogo: autocategorizacion, dedup de SKUs con embeddings, OCR de facturas, descripciones, claves SAT, limpieza de fitment - F3 IA en el flujo: vision Yonke, preguntas MeLi, venta cruzada, anomalias, sinonimos, busqueda semantica (rerank/embeddings) - F4/F8 escala y cartera: /metrics+Prometheus+Grafana, pool, score de credito, churn, metricas multi-tenant - Nexus Yonke (M1-M6): modelo de datos 1-de-1, alta por donador, vitrina publica, MeLi usado, consignacion, garantia por dias, reportes, etiquetas - Marketplace B2B entre yonkes (catalogo + pedidos cross-tenant) - Seguridad: auth en /api/admin/* (35 endpoints), alertas por tenant - Migraciones v4.27/v4.28; timers expire-demos y rollup-metrics
This commit is contained in:
@@ -2,11 +2,14 @@
|
||||
"""Customers blueprint: CRUD, credit management, vehicles, account statements."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
from flask import Blueprint, request, jsonify, g
|
||||
from middleware import require_auth, has_permission
|
||||
from tenant_db import get_tenant_conn
|
||||
from services.audit import log_action
|
||||
|
||||
logger = logging.getLogger('pos')
|
||||
|
||||
customers_bp = Blueprint('customers', __name__, url_prefix='/pos/api/customers')
|
||||
|
||||
|
||||
@@ -155,6 +158,14 @@ def get_customer(customer_id):
|
||||
|
||||
customer['created_at'] = str(customer['created_at']) if customer['created_at'] else None
|
||||
|
||||
# Credit risk score (A9). Never block customer detail on scoring errors.
|
||||
try:
|
||||
from services.credit_scoring import score_customer
|
||||
customer['credit_score'] = score_customer(conn, customer_id)
|
||||
except Exception as exc:
|
||||
logger.warning('credit score for customer %s failed: %s', customer_id, exc)
|
||||
customer['credit_score'] = None
|
||||
|
||||
# Recent purchases (last 20)
|
||||
cur.execute("""
|
||||
SELECT s.id, s.total, s.payment_method, s.sale_type, s.status, s.created_at,
|
||||
@@ -199,6 +210,28 @@ def get_customer(customer_id):
|
||||
return jsonify(customer)
|
||||
|
||||
|
||||
@customers_bp.route('/<int:customer_id>/credit-score', methods=['GET'])
|
||||
@require_auth()
|
||||
def get_customer_credit_score(customer_id):
|
||||
"""Credit risk score for a customer (A9).
|
||||
|
||||
Returns {score, tier, recommended_limit, reasons, data_points, ...}.
|
||||
"""
|
||||
if not _can_view_customers():
|
||||
return jsonify({'error': 'Missing permissions: customers.view'}), 403
|
||||
conn = get_tenant_conn(g.tenant_id)
|
||||
try:
|
||||
from services.credit_scoring import score_customer
|
||||
return jsonify(score_customer(conn, customer_id))
|
||||
except ValueError as e:
|
||||
return jsonify({'error': str(e)}), 404
|
||||
except Exception as e:
|
||||
logger.error('credit-score for customer %s failed: %s', customer_id, e)
|
||||
return jsonify({'error': 'Could not compute credit score'}), 500
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
@customers_bp.route('/<int:customer_id>/purchases', methods=['GET'])
|
||||
@require_auth()
|
||||
def get_customer_purchases(customer_id):
|
||||
@@ -624,6 +657,24 @@ def record_customer_payment(customer_id):
|
||||
new_value={'credit_balance': new_balance, 'payment': amount})
|
||||
|
||||
conn.commit()
|
||||
|
||||
# Accounting entry (non-blocking): Cobro de credito
|
||||
# Debit Caja/Bancos, Credit Clientes
|
||||
try:
|
||||
from services.accounting_engine import record_credit_payment_entry
|
||||
record_credit_payment_entry(conn, {
|
||||
'customer_id': customer_id,
|
||||
'customer_name': cust[0],
|
||||
'amount': amount,
|
||||
'payment_method': payment_method,
|
||||
})
|
||||
conn.commit()
|
||||
except Exception as acc_err:
|
||||
conn.rollback()
|
||||
logger.error(
|
||||
f'Accounting entry for customer payment #{payment_id} failed: {acc_err}'
|
||||
)
|
||||
|
||||
cur.close(); conn.close()
|
||||
|
||||
return jsonify({
|
||||
|
||||
Reference in New Issue
Block a user