first commit
This commit is contained in:
0
Project/Dockerfile
Normal file
0
Project/Dockerfile
Normal file
533
Project/microservice.py
Normal file
533
Project/microservice.py
Normal file
@ -0,0 +1,533 @@
|
||||
from flask import Flask, request, jsonify, Response
|
||||
import requests
|
||||
import os
|
||||
from flask_cors import CORS
|
||||
|
||||
# Initialize Flask app
|
||||
app = Flask(__name__)
|
||||
|
||||
# Enhanced CORS configuration
|
||||
CORS(app,
|
||||
resources={r"/*": {"origins": "*"}},
|
||||
supports_credentials=True,
|
||||
allow_headers=["Content-Type", "Authorization", "Access-Control-Allow-Credentials"],
|
||||
methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"]
|
||||
)
|
||||
|
||||
# Configuration - point to your main backend
|
||||
MAIN_BACKEND_URL = "http://127.0.0.1:5000" # Change this to your main backend URL
|
||||
|
||||
# Add OPTIONS handler for preflight requests
|
||||
@app.before_request
|
||||
def handle_preflight():
|
||||
if request.method == "OPTIONS":
|
||||
response = Response()
|
||||
response.headers.add("Access-Control-Allow-Origin", "*")
|
||||
response.headers.add('Access-Control-Allow-Headers', "*")
|
||||
response.headers.add('Access-Control-Allow-Methods', "*")
|
||||
return response
|
||||
|
||||
# Routes
|
||||
@app.route('/login', methods=['POST'])
|
||||
def login():
|
||||
"""Handle machine login"""
|
||||
try:
|
||||
data = request.json
|
||||
print(f"Login request received: {data}")
|
||||
|
||||
# Forward the login request to the main backend
|
||||
response = requests.post(f"{MAIN_BACKEND_URL}/login", json=data)
|
||||
print(f"Login response status: {response.status_code}")
|
||||
|
||||
# Pass through the response
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Login error: {e}")
|
||||
return jsonify({"error": "Login service unavailable"}), 500
|
||||
|
||||
@app.route('/uploads/<path:filename>', methods=['GET'])
|
||||
def get_image(filename):
|
||||
"""Forward image requests to the main backend"""
|
||||
try:
|
||||
response = requests.get(f"{MAIN_BACKEND_URL}/uploads/{filename}", stream=True)
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'image/jpeg')
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Image fetch error: {e}")
|
||||
return jsonify({"error": "Image not found"}), 404
|
||||
|
||||
@app.route('/machine-slots/<machine_id>', methods=['GET'])
|
||||
def get_machine_slots(machine_id):
|
||||
"""Get slots for a specific machine"""
|
||||
try:
|
||||
print(f"Fetching slots for machine: {machine_id}")
|
||||
# Simply forward the request to the main backend
|
||||
response = requests.get(f"{MAIN_BACKEND_URL}/machine-slots/{machine_id}")
|
||||
print(f"Slots response status: {response.status_code}")
|
||||
|
||||
# Pass through the response
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Machine slots error: {e}")
|
||||
return jsonify({"error": "Could not fetch machine slots"}), 500
|
||||
|
||||
@app.route('/machine-slots/update-inventory', methods=['POST'])
|
||||
def update_inventory():
|
||||
"""Forward inventory update request to main backend"""
|
||||
try:
|
||||
print("=== Inventory Update Request ===")
|
||||
data = request.json
|
||||
|
||||
if not data:
|
||||
return jsonify({"error": "No data received"}), 400
|
||||
|
||||
machine_id = data.get('machineId')
|
||||
updates = data.get('inventoryUpdates', [])
|
||||
|
||||
print(f"Machine ID: {machine_id}")
|
||||
print(f"Inventory updates: {len(updates)}")
|
||||
|
||||
response = requests.post(
|
||||
f"{MAIN_BACKEND_URL}/machine-slots/update-inventory",
|
||||
json=data,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
print(f"Inventory update response: {response.status_code}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Inventory update error: {e}")
|
||||
return jsonify({"error": "Could not update inventory"}), 500
|
||||
|
||||
@app.route('/vending-state/<machine_id>', methods=['GET'])
|
||||
def get_vending_state(machine_id):
|
||||
"""Get the vending state for a machine"""
|
||||
try:
|
||||
# Forward the request to the main backend
|
||||
response = requests.get(f"{MAIN_BACKEND_URL}/machines/{machine_id}")
|
||||
|
||||
# Pass through the response
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Vending state error: {e}")
|
||||
return jsonify({"error": "Could not fetch vending state"}), 500
|
||||
|
||||
@app.route('/create-payu-order', methods=['POST', 'OPTIONS'])
|
||||
def create_payu_order():
|
||||
"""Create PayU payment order - forward to main backend"""
|
||||
try:
|
||||
print("=== PayU Order Creation Request ===")
|
||||
data = request.json
|
||||
print(f"Request data: {data}")
|
||||
|
||||
if not data:
|
||||
print("No data received in request")
|
||||
return jsonify({"error": "No data received"}), 400
|
||||
|
||||
# Forward to main backend
|
||||
print(f"Forwarding to: {MAIN_BACKEND_URL}/create-payu-order")
|
||||
response = requests.post(
|
||||
f"{MAIN_BACKEND_URL}/create-payu-order",
|
||||
json=data,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
print(f"Main backend response status: {response.status_code}")
|
||||
print(f"Main backend response: {response.text}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
print(f"Connection error to main backend: {e}")
|
||||
return jsonify({"error": "Payment service unavailable"}), 503
|
||||
except Exception as e:
|
||||
print(f"PayU order creation error: {e}")
|
||||
return jsonify({"error": "Could not create payment order"}), 500
|
||||
|
||||
@app.route('/vending-state/<machine_id>', methods=['PUT'])
|
||||
def update_vending_state(machine_id):
|
||||
"""Update the vending state for a machine"""
|
||||
try:
|
||||
# Forward the request to the main backend
|
||||
headers = {k: v for k, v in request.headers.items() if k not in ['Host', 'Content-Length']}
|
||||
response = requests.put(
|
||||
f"{MAIN_BACKEND_URL}/machines/{machine_id}/vending-state",
|
||||
json=request.json,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
# Pass through the response
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Update vending state error: {e}")
|
||||
return jsonify({"error": "Could not update vending state"}), 500
|
||||
|
||||
# NEW: Serial Communication Routes
|
||||
|
||||
@app.route('/machine/connect', methods=['POST'])
|
||||
def connect_machine():
|
||||
"""Forward machine connection request to main backend"""
|
||||
try:
|
||||
print("=== Machine Connection Request ===")
|
||||
data = request.json or {}
|
||||
print(f"Connection data: {data}")
|
||||
|
||||
response = requests.post(
|
||||
f"{MAIN_BACKEND_URL}/machine/connect",
|
||||
json=data,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
print(f"Connection response: {response.status_code}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Machine connection error: {e}")
|
||||
return jsonify({"error": "Could not connect to machine"}), 500
|
||||
|
||||
@app.route('/machine/status', methods=['GET'])
|
||||
def get_machine_status():
|
||||
"""Forward machine status request to main backend"""
|
||||
try:
|
||||
print("=== Machine Status Request ===")
|
||||
|
||||
response = requests.get(f"{MAIN_BACKEND_URL}/machine/status")
|
||||
|
||||
print(f"Status response: {response.status_code}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Machine status error: {e}")
|
||||
return jsonify({"error": "Could not get machine status"}), 500
|
||||
|
||||
@app.route('/machine/dispense', methods=['POST'])
|
||||
def dispense_product():
|
||||
"""Forward single product dispensing to main backend"""
|
||||
try:
|
||||
print("=== Single Product Dispensing Request ===")
|
||||
data = request.json
|
||||
|
||||
if not data:
|
||||
return jsonify({"error": "No data received"}), 400
|
||||
|
||||
print(f"Dispense data: {data}")
|
||||
|
||||
response = requests.post(
|
||||
f"{MAIN_BACKEND_URL}/machine/dispense",
|
||||
json=data,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
print(f"Dispense response: {response.status_code}")
|
||||
print(f"Dispense result: {response.text}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Product dispensing error: {e}")
|
||||
return jsonify({"error": "Could not dispense product"}), 500
|
||||
|
||||
@app.route('/machine/dispense-multiple', methods=['POST'])
|
||||
def dispense_multiple_products():
|
||||
"""Forward multiple product dispensing to main backend"""
|
||||
try:
|
||||
print("=== Multiple Product Dispensing Request ===")
|
||||
data = request.json
|
||||
|
||||
if not data:
|
||||
return jsonify({"error": "No data received"}), 400
|
||||
|
||||
machine_id = data.get('machineId')
|
||||
items = data.get('items', [])
|
||||
|
||||
print(f"Machine ID: {machine_id}")
|
||||
print(f"Items to dispense: {len(items)}")
|
||||
for item in items:
|
||||
print(f" - Slot {item.get('slotId')}: {item.get('quantity')}x {item.get('productName')}")
|
||||
|
||||
response = requests.post(
|
||||
f"{MAIN_BACKEND_URL}/machine/dispense-multiple",
|
||||
json=data,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
print(f"Multiple dispense response: {response.status_code}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Multiple product dispensing error: {e}")
|
||||
return jsonify({"error": "Could not dispense multiple products"}), 500
|
||||
|
||||
@app.route('/machine/reset', methods=['POST'])
|
||||
def reset_machine():
|
||||
"""Forward machine reset request to main backend"""
|
||||
try:
|
||||
print("=== Machine Reset Request ===")
|
||||
|
||||
response = requests.post(f"{MAIN_BACKEND_URL}/machine/reset")
|
||||
|
||||
print(f"Reset response: {response.status_code}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Machine reset error: {e}")
|
||||
return jsonify({"error": "Could not reset machine"}), 500
|
||||
|
||||
@app.route('/machine/disconnect', methods=['POST'])
|
||||
def disconnect_machine():
|
||||
"""Forward machine disconnect request to main backend"""
|
||||
try:
|
||||
print("=== Machine Disconnect Request ===")
|
||||
|
||||
response = requests.post(f"{MAIN_BACKEND_URL}/machine/disconnect")
|
||||
|
||||
print(f"Disconnect response: {response.status_code}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Machine disconnect error: {e}")
|
||||
return jsonify({"error": "Could not disconnect machine"}), 500
|
||||
|
||||
@app.route('/payment-confirmed', methods=['POST'])
|
||||
def payment_confirmed():
|
||||
"""Forward payment confirmation to main backend for dispensing"""
|
||||
try:
|
||||
print("=== Payment Confirmation Request ===")
|
||||
data = request.json
|
||||
|
||||
if not data:
|
||||
return jsonify({"error": "No data received"}), 400
|
||||
|
||||
machine_id = data.get('machineId')
|
||||
cart_items = data.get('cartItems', [])
|
||||
|
||||
print(f"Payment confirmed for machine: {machine_id}")
|
||||
print(f"Cart items: {len(cart_items)}")
|
||||
|
||||
response = requests.post(
|
||||
f"{MAIN_BACKEND_URL}/payment-confirmed",
|
||||
json=data,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
print(f"Payment confirmation response: {response.status_code}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Payment confirmation error: {e}")
|
||||
return jsonify({"error": "Could not process payment confirmation"}), 500
|
||||
|
||||
@app.route('/transactions/bulk-create', methods=['POST'])
|
||||
def bulk_create_transactions():
|
||||
"""Forward bulk transaction creation to main backend"""
|
||||
try:
|
||||
print("=== Bulk Transaction Creation Request ===")
|
||||
data = request.json
|
||||
|
||||
if not data:
|
||||
return jsonify({"error": "No data received"}), 400
|
||||
|
||||
transactions = data.get('transactions', [])
|
||||
print(f"Creating {len(transactions)} transactions")
|
||||
|
||||
for trans in transactions:
|
||||
print(f" - {trans.get('product_name')} x {trans.get('quantity')} = ₹{trans.get('amount')}")
|
||||
|
||||
response = requests.post(
|
||||
f"{MAIN_BACKEND_URL}/transactions/bulk-create",
|
||||
json=data,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
print(f"Bulk transaction response: {response.status_code}")
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Bulk transaction creation error: {e}")
|
||||
return jsonify({"error": "Could not create transactions"}), 500
|
||||
|
||||
# LEGACY: Keep existing dispense-products route for backward compatibility
|
||||
@app.route('/dispense-products', methods=['POST'])
|
||||
def dispense_products():
|
||||
"""Legacy route - redirect to new dispensing system"""
|
||||
print("=== Legacy Dispense Products Request ===")
|
||||
print("Redirecting to new dispensing system...")
|
||||
|
||||
# Get dispensing instructions from the request
|
||||
data = request.json
|
||||
if not data:
|
||||
print("No JSON data received")
|
||||
return jsonify({"error": "No data received"}), 400
|
||||
|
||||
machine_id = data.get('machineId')
|
||||
dispensing_instructions = data.get('dispensingInstructions', [])
|
||||
|
||||
if not machine_id or not dispensing_instructions:
|
||||
print("Missing machine ID or dispensing instructions")
|
||||
return jsonify({"error": "Missing machine ID or dispensing instructions"}), 400
|
||||
|
||||
# Convert to new format and forward to new dispensing endpoint
|
||||
try:
|
||||
new_format = {
|
||||
'machineId': machine_id,
|
||||
'items': [
|
||||
{
|
||||
'slotId': instruction.get('slotId'),
|
||||
'quantity': instruction.get('quantity', 1),
|
||||
'productName': instruction.get('productName', 'Unknown')
|
||||
}
|
||||
for instruction in dispensing_instructions
|
||||
]
|
||||
}
|
||||
|
||||
return dispense_multiple_products_internal(new_format)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Legacy conversion error: {e}")
|
||||
return jsonify({"error": "Could not process legacy request"}), 500
|
||||
|
||||
def dispense_multiple_products_internal(data):
|
||||
"""Internal function to handle dispensing without duplicate logging"""
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{MAIN_BACKEND_URL}/machine/dispense-multiple",
|
||||
json=data,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
return Response(
|
||||
response.content,
|
||||
status=response.status_code,
|
||||
content_type=response.headers.get('Content-Type', 'application/json')
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({"error": "Could not dispense products"}), 500
|
||||
|
||||
@app.route('/payment-success', methods=['POST', 'GET'])
|
||||
def payment_success():
|
||||
data = request.form.to_dict() or request.args.to_dict()
|
||||
print("✅ Payment Success:", data)
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Payment successful",
|
||||
"data": data
|
||||
}), 200
|
||||
|
||||
@app.route('/payment-failure', methods=['POST', 'GET'])
|
||||
def payment_failure():
|
||||
data = request.form.to_dict() or request.args.to_dict()
|
||||
print("❌ Payment Failure:", data)
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"message": "Payment failed",
|
||||
"data": data
|
||||
}), 200
|
||||
|
||||
|
||||
|
||||
# Add a test route to verify the server is running
|
||||
@app.route('/', methods=['GET'])
|
||||
def test_route():
|
||||
return jsonify({"status": "Flask server is running"}), 200
|
||||
|
||||
# Add error handlers
|
||||
@app.errorhandler(404)
|
||||
def not_found(error):
|
||||
return jsonify({"error": "Endpoint not found"}), 404
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_error(error):
|
||||
return jsonify({"error": "Internal server error"}), 500
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Print startup message
|
||||
print("Starting Flask server on port 5001...")
|
||||
print("Available routes:")
|
||||
print(" - /")
|
||||
print(" - /login [POST]")
|
||||
print(" - /uploads/<filename> [GET]")
|
||||
print(" - /machine-slots/<machine_id> [GET]")
|
||||
print(" - /vending-state/<machine_id> [GET/PUT]")
|
||||
print(" - /create-payu-order [POST]")
|
||||
print(" - /dispense-products [POST] (legacy)")
|
||||
print(" - /machine/connect [POST]")
|
||||
print(" - /machine/status [GET]")
|
||||
print(" - /machine/dispense [POST]")
|
||||
print(" - /machine/dispense-multiple [POST]")
|
||||
print(" - /machine/reset [POST]")
|
||||
print(" - /machine/disconnect [POST]")
|
||||
print(" - /payment-confirmed [POST]")
|
||||
print(f"Main backend URL: {MAIN_BACKEND_URL}")
|
||||
|
||||
# Run the server
|
||||
app.run(host='0.0.0.0', debug=True, port=5001)
|
||||
Reference in New Issue
Block a user