"""CRM Blueprint: activities, tags, loyalty, analytics. Prefixes: /pos/api/customers//activities /pos/api/customers//tags /pos/api/customers//loyalty /pos/api/customers//analytics /pos/api/tags /pos/api/rewards """ from flask import Blueprint, request, jsonify, g from middleware import require_auth from tenant_db import get_tenant_conn from services.crm_engine import ( log_activity, get_activities, create_tag, list_tags, assign_tag, remove_tag, get_customer_tags, add_loyalty_points, redeem_points, get_loyalty_history, create_reward, list_rewards, get_customer_analytics, ) crm_bp = Blueprint('crm', __name__, url_prefix='/pos/api') # ─── Customer Activities ───────────────────────────── @crm_bp.route('/customers//activities', methods=['GET']) @require_auth('customers.view') def customer_activities(customer_id): activity_type = request.args.get('type') limit = min(int(request.args.get('limit', 50)), 200) conn = get_tenant_conn(g.tenant_id) try: activities = get_activities(conn, customer_id, activity_type=activity_type, limit=limit) return jsonify({'activities': activities}) finally: conn.close() @crm_bp.route('/customers//activities', methods=['POST']) @require_auth('customers.edit') def add_customer_activity(customer_id): data = request.get_json() or {} activity_type = data.get('activity_type', 'note') conn = get_tenant_conn(g.tenant_id) try: activity_id = log_activity( conn, customer_id, activity_type, title=data.get('title'), description=data.get('description'), metadata=data.get('metadata'), employee_id=getattr(g, 'employee_id', None), ) return jsonify({'id': activity_id, 'message': 'Activity logged'}), 201 finally: conn.close() # ─── Customer Tags ───────────────────────────── @crm_bp.route('/tags', methods=['GET']) @require_auth('customers.view') def get_tags(): conn = get_tenant_conn(g.tenant_id) try: tags = list_tags(conn, g.tenant_id) return jsonify({'tags': tags}) finally: conn.close() @crm_bp.route('/tags', methods=['POST']) @require_auth('customers.edit') def create_new_tag(): data = request.get_json() or {} if not data.get('name'): return jsonify({'error': 'name is required'}), 400 conn = get_tenant_conn(g.tenant_id) try: tag_id = create_tag(conn, g.tenant_id, data['name'], color=data.get('color', '#6B7280'), description=data.get('description')) return jsonify({'id': tag_id, 'message': 'Tag created'}), 201 finally: conn.close() @crm_bp.route('/customers//tags', methods=['GET']) @require_auth('customers.view') def get_customer_tags_endpoint(customer_id): conn = get_tenant_conn(g.tenant_id) try: tags = get_customer_tags(conn, customer_id) return jsonify({'tags': tags}) finally: conn.close() @crm_bp.route('/customers//tags', methods=['POST']) @require_auth('customers.edit') def assign_customer_tag(customer_id): data = request.get_json() or {} tag_id = data.get('tag_id') if not tag_id: return jsonify({'error': 'tag_id is required'}), 400 conn = get_tenant_conn(g.tenant_id) try: assign_tag(conn, customer_id, tag_id, assigned_by=getattr(g, 'employee_id', None)) return jsonify({'message': 'Tag assigned'}) finally: conn.close() @crm_bp.route('/customers//tags/', methods=['DELETE']) @require_auth('customers.edit') def remove_customer_tag(customer_id, tag_id): conn = get_tenant_conn(g.tenant_id) try: remove_tag(conn, customer_id, tag_id) return jsonify({'message': 'Tag removed'}) finally: conn.close() # ─── Loyalty ───────────────────────────── @crm_bp.route('/customers//loyalty', methods=['GET']) @require_auth('customers.view') def get_loyalty(customer_id): conn = get_tenant_conn(g.tenant_id) try: history = get_loyalty_history(conn, customer_id) # Get current balance cur = conn.cursor() cur.execute("SELECT loyalty_points_balance, loyalty_tier FROM customers WHERE id = %s", (customer_id,)) row = cur.fetchone() cur.close() return jsonify({ 'balance': row[0] or 0, 'tier': row[1] or 'bronze', 'history': history, }) finally: conn.close() @crm_bp.route('/customers//loyalty/add', methods=['POST']) @require_auth('customers.edit') def add_loyalty(customer_id): data = request.get_json() or {} points = int(data.get('points', 0)) if points <= 0: return jsonify({'error': 'points must be > 0'}), 400 conn = get_tenant_conn(g.tenant_id) try: point_id = add_loyalty_points( conn, customer_id, points, points_type=data.get('points_type', 'earned'), source_type=data.get('source_type'), source_id=data.get('source_id'), description=data.get('description'), expires_at=data.get('expires_at'), ) return jsonify({'id': point_id, 'message': f'{points} points added'}), 201 finally: conn.close() @crm_bp.route('/customers//loyalty/redeem', methods=['POST']) @require_auth('customers.edit') def redeem_loyalty(customer_id): data = request.get_json() or {} points = int(data.get('points', 0)) if points <= 0: return jsonify({'error': 'points must be > 0'}), 400 conn = get_tenant_conn(g.tenant_id) try: redemption_id = redeem_points( conn, customer_id, points, reward_id=data.get('reward_id'), reward_value=data.get('reward_value'), description=data.get('description'), employee_id=getattr(g, 'employee_id', None), ) return jsonify({'id': redemption_id, 'message': f'{points} points redeemed'}), 201 except ValueError as e: return jsonify({'error': str(e)}), 400 # ─── Rewards Catalog ───────────────────────────── @crm_bp.route('/rewards', methods=['GET']) @require_auth('customers.view') def get_rewards(): conn = get_tenant_conn(g.tenant_id) try: rewards = list_rewards(conn, g.tenant_id) return jsonify({'rewards': rewards}) finally: conn.close() @crm_bp.route('/rewards', methods=['POST']) @require_auth('customers.edit') def create_new_reward(): data = request.get_json() or {} if not data.get('name') or data.get('points_cost') is None: return jsonify({'error': 'name and points_cost are required'}), 400 conn = get_tenant_conn(g.tenant_id) try: reward_id = create_reward( conn, g.tenant_id, data['name'], int(data['points_cost']), reward_type=data.get('reward_type', 'discount'), reward_value=data.get('reward_value'), description=data.get('description'), ) return jsonify({'id': reward_id, 'message': 'Reward created'}), 201 finally: conn.close() # ─── Customer Analytics ───────────────────────────── @crm_bp.route('/customers//analytics', methods=['GET']) @require_auth('customers.view') def customer_analytics(customer_id): conn = get_tenant_conn(g.tenant_id) try: analytics = get_customer_analytics(conn, customer_id) return jsonify(analytics) finally: conn.close()