"""Supplier and purchase order blueprint. Endpoints (all under /pos/api): GET/POST /suppliers GET/PUT /suppliers/ GET /suppliers//purchase-orders POST /purchase-orders GET /purchase-orders GET /purchase-orders/ PUT /purchase-orders//send PUT /purchase-orders//receive PUT /purchase-orders//cancel """ from flask import Blueprint, request, jsonify, g from middleware import require_auth from tenant_db import get_tenant_conn from services.supplier_engine import ( create_supplier, update_supplier, get_supplier, list_suppliers, create_po, send_po, receive_po, cancel_po, get_po, list_pos, ) supplier_bp = Blueprint('supplier', __name__, url_prefix='/pos/api') # ── SUPPLIERS ────────────────────────────────────────────────────────────── @supplier_bp.route('/suppliers', methods=['GET']) @require_auth('inventory.view') def get_suppliers(): """List suppliers.""" conn = get_tenant_conn(g.tenant_id) active_only = request.args.get('active_only', 'true').lower() == 'true' limit = request.args.get('limit', 100, type=int) offset = request.args.get('offset', 0, type=int) data = list_suppliers(conn, active_only=active_only, limit=limit, offset=offset) conn.close() return jsonify({'data': data}) @supplier_bp.route('/suppliers', methods=['POST']) @require_auth('inventory.edit') def post_supplier(): """Create a supplier.""" 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: supplier_id = create_supplier(conn, data) conn.commit() conn.close() return jsonify({'id': supplier_id, 'message': 'Supplier created'}), 201 except Exception as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 500 @supplier_bp.route('/suppliers/', methods=['GET']) @require_auth('inventory.view') def get_supplier_detail(supplier_id): """Get supplier by ID.""" conn = get_tenant_conn(g.tenant_id) supplier = get_supplier(conn, supplier_id) conn.close() if not supplier: return jsonify({'error': 'Supplier not found'}), 404 return jsonify(supplier) @supplier_bp.route('/suppliers/', methods=['PUT']) @require_auth('inventory.edit') def put_supplier(supplier_id): """Update supplier.""" data = request.get_json() or {} conn = get_tenant_conn(g.tenant_id) try: updated = update_supplier(conn, supplier_id, data) conn.commit() conn.close() if not updated: return jsonify({'error': 'Supplier not found or no changes'}), 404 return jsonify({'message': 'Supplier updated'}) except Exception as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 500 @supplier_bp.route('/suppliers//purchase-orders', methods=['GET']) @require_auth('inventory.view') def get_supplier_pos(supplier_id): """List POs for a supplier.""" conn = get_tenant_conn(g.tenant_id) status = request.args.get('status') limit = request.args.get('limit', 50, type=int) offset = request.args.get('offset', 0, type=int) data = list_pos(conn, status=status, supplier_id=supplier_id, limit=limit, offset=offset) conn.close() return jsonify({'data': data}) # ── PURCHASE ORDERS ──────────────────────────────────────────────────────── @supplier_bp.route('/purchase-orders', methods=['POST']) @require_auth('inventory.edit') def post_purchase_order(): """Create a purchase order.""" data = request.get_json() or {} if not data.get('items'): return jsonify({'error': 'items are required'}), 400 conn = get_tenant_conn(g.tenant_id) try: result = create_po(conn, data, branch_id=g.branch_id, employee_id=g.employee_id) conn.commit() conn.close() return jsonify(result), 201 except ValueError as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 400 except Exception as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 500 @supplier_bp.route('/purchase-orders', methods=['GET']) @require_auth('inventory.view') def get_purchase_orders(): """List purchase orders.""" conn = get_tenant_conn(g.tenant_id) status = request.args.get('status') supplier_id = request.args.get('supplier_id', type=int) limit = request.args.get('limit', 50, type=int) offset = request.args.get('offset', 0, type=int) data = list_pos(conn, status=status, supplier_id=supplier_id, limit=limit, offset=offset) conn.close() return jsonify({'data': data}) @supplier_bp.route('/purchase-orders/', methods=['GET']) @require_auth('inventory.view') def get_purchase_order(po_id): """Get PO detail with items.""" conn = get_tenant_conn(g.tenant_id) po = get_po(conn, po_id) conn.close() if not po: return jsonify({'error': 'Purchase order not found'}), 404 return jsonify(po) @supplier_bp.route('/purchase-orders//send', methods=['PUT']) @require_auth('inventory.edit') def put_send_po(po_id): """Mark PO as sent.""" conn = get_tenant_conn(g.tenant_id) try: ok = send_po(conn, po_id) conn.commit() conn.close() if not ok: return jsonify({'error': 'PO not found or not in draft status'}), 400 return jsonify({'message': 'PO marked as sent'}) except Exception as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 500 @supplier_bp.route('/purchase-orders//receive', methods=['PUT']) @require_auth('inventory.edit') def put_receive_po(po_id): """Receive items from a PO.""" data = request.get_json() or {} received_items = data.get('items', []) if not received_items: return jsonify({'error': 'items are required'}), 400 conn = get_tenant_conn(g.tenant_id) try: result = receive_po( conn, po_id, received_items, supplier_invoice=data.get('supplier_invoice'), notes=data.get('notes') ) conn.commit() conn.close() return jsonify(result) except ValueError as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 400 except Exception as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 500 @supplier_bp.route('/purchase-orders//cancel', methods=['PUT']) @require_auth('inventory.edit') def put_cancel_po(po_id): """Cancel a PO.""" data = request.get_json() or {} reason = data.get('reason', '') conn = get_tenant_conn(g.tenant_id) try: cancel_po(conn, po_id, reason) conn.commit() conn.close() return jsonify({'message': 'PO cancelled'}) except ValueError as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 400 except Exception as e: conn.rollback() conn.close() return jsonify({'error': str(e)}), 500