Skip to content

Commit 38b9733

Browse files
authored
Merge pull request #1660 from SatyamPandey-07/feature/autonomous-supply-chain-1644
feat: Autonomous Supply Chain System #1644
2 parents b806579 + 212878c commit 38b9733

File tree

11 files changed

+360
-11
lines changed

11 files changed

+360
-11
lines changed

backend/api/v1/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@
4747
from .vaults import vaults_bp
4848
from .carbon import carbon_bp
4949
from .logistics import smart_freight_bp
50-
from .biomass import biomass_bp
51-
from .energy_grid import energy_grid_bp
50+
from .supply_chain import supply_chain_bp
5251

5352
# Create v1 API blueprint
5453
api_v1 = Blueprint('api_v1', __name__, url_prefix='/api/v1')
@@ -103,5 +102,4 @@
103102
api_v1.register_blueprint(biosecurity_bp, url_prefix='/biosecurity')
104103
api_v1.register_blueprint(vaults_bp, url_prefix='/vaults')
105104
api_v1.register_blueprint(carbon_bp, url_prefix='/carbon')
106-
api_v1.register_blueprint(biomass_bp, url_prefix='/biomass')
107-
api_v1.register_blueprint(energy_grid_bp, url_prefix='/vpp-grid')
105+
api_v1.register_blueprint(supply_chain_bp, url_prefix='/autonomous-supply')

backend/api/v1/supply_chain.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from flask import Blueprint, jsonify, request
2+
from backend.auth_utils import token_required
3+
from backend.models.autonomous_supply import SmartContractOrder
4+
from backend.services.sc_orchestrator import SupplyChainOrchestrator
5+
from backend.extensions import db
6+
7+
supply_chain_bp = Blueprint('supply_chain', __name__)
8+
9+
@supply_chain_bp.route('/contract/init', methods=['POST'])
10+
@token_required
11+
def init_smart_contract(current_user):
12+
"""Initializes an autonomous supply chain order."""
13+
data = request.json
14+
try:
15+
order = SupplyChainOrchestrator.initialize_contract(
16+
buyer_id=current_user.id,
17+
vendor_id=data.get('vendor_id'),
18+
commodity_info=data.get('commodity')
19+
)
20+
return jsonify({
21+
'status': 'success',
22+
'order_id': order.id,
23+
'message': 'Smart contract order initialized'
24+
}), 201
25+
except Exception as e:
26+
return jsonify({'status': 'error', 'message': str(e)}), 400
27+
28+
@supply_chain_bp.route('/contract/<int:order_id>/telemetry', methods=['POST'])
29+
@token_required
30+
def update_order_telemetry(current_user, order_id):
31+
"""Updates GPS telemetry and checks geofence for order completion."""
32+
data = request.json
33+
lat = data.get('lat')
34+
lng = data.get('lng')
35+
36+
triggered = SupplyChainOrchestrator.update_gps_telemetry(order_id, lat, lng)
37+
38+
return jsonify({
39+
'status': 'success',
40+
'geofence_triggered': triggered,
41+
'message': 'Telemetry processed'
42+
}), 200
43+
44+
@supply_chain_bp.route('/orders/active', methods=['GET'])
45+
@token_required
46+
def get_active_orders(current_user):
47+
"""Retrieves active smart contract orders."""
48+
orders = SmartContractOrder.query.filter(SmartContractOrder.status != 'COMPLETED').all()
49+
return jsonify({
50+
'status': 'success',
51+
'data': [{
52+
'id': o.id,
53+
'commodity': o.commodity,
54+
'status': o.status,
55+
'quantity': o.quantity_kg
56+
} for o in orders]
57+
}), 200

backend/models/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
from .reliability_log import ReliabilityLog
4949
from .market import ForwardContract, PriceHedgingLog
5050
from .circular import WasteInventory, BioEnergyOutput, CircularCredit
51-
from .biomass import BiomassStockpile, BiogasDigesterLog
52-
from .energy_grid import DecentralizedEnergyGrid, EnergyTokenMint, GridInjectionLog
51+
from .autonomous_supply import SmartContractOrder, FreightGeoFence
52+
from .freight_v2 import AutonomousVehicle, VehicleMission
5353
from .disease import MigrationVector, ContainmentZone
5454
from .ledger import (
5555
LedgerAccount, LedgerTransaction, LedgerEntry,
@@ -126,8 +126,8 @@
126126
'ReliabilityLog', 'ForwardContract', 'PriceHedgingLog',
127127
# Circular Economy & Biomass Energy
128128
'WasteInventory', 'BioEnergyOutput', 'CircularCredit',
129-
'BiomassStockpile', 'BiogasDigesterLog',
130-
'DecentralizedEnergyGrid', 'EnergyTokenMint', 'GridInjectionLog',
129+
# Autonomous Supply Chain (L3-1644)
130+
'SmartContractOrder', 'FreightGeoFence', 'AutonomousVehicle', 'VehicleMission',
131131
# Double-Entry Ledger
132132
'LedgerAccount', 'LedgerTransaction', 'LedgerEntry',
133133
'FXValuationSnapshot', 'Vault', 'VaultCurrencyPosition', 'FXRate',

backend/models/audit_log.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ class AuditLog(db.Model):
3535
# Smart Freight (L3-1631)
3636
ai_logistics_flag = db.Column(db.Boolean, default=False) # For geo-fence & phyto auto-decisions
3737

38-
# Virtual Power Plant Grid (L3-1636)
39-
vpp_grid_flag = db.Column(db.Boolean, default=False)
38+
# Autonomous Supply Chain (L3-1644)
39+
autonomous_supply_flag = db.Column(db.Boolean, default=False)
4040

4141
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
4242

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
Autonomous Supply Chain Models — L3-1644
3+
=======================================
4+
Smart-contract driven automatic procurement and smart-lock freight.
5+
"""
6+
7+
from datetime import datetime
8+
from backend.extensions import db
9+
10+
class SmartContractOrder(db.Model):
11+
__tablename__ = 'smart_contract_orders'
12+
13+
id = db.Column(db.Integer, primary_key=True)
14+
buyer_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
15+
vendor_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
16+
17+
commodity = db.Column(db.String(100), nullable=False)
18+
quantity_kg = db.Column(db.Float, nullable=False)
19+
strike_price_usd = db.Column(db.Float, nullable=False)
20+
21+
# Auto-conditions
22+
auto_execute_at_price = db.Column(db.Float)
23+
24+
# Status: PENDING_TRIGGER -> FUNDED -> SHIPPED -> COMPLETED
25+
status = db.Column(db.String(30), default='PENDING_TRIGGER')
26+
27+
freight_locked_id = db.Column(db.Integer)
28+
created_at = db.Column(db.DateTime, default=datetime.utcnow)
29+
30+
class FreightGeoFence(db.Model):
31+
"""
32+
Electronic seals that trigger fund release on reaching destination.
33+
"""
34+
__tablename__ = 'freight_geofences'
35+
36+
id = db.Column(db.Integer, primary_key=True)
37+
order_id = db.Column(db.Integer, db.ForeignKey('smart_contract_orders.id'), nullable=False)
38+
39+
target_lat = db.Column(db.Float, nullable=False)
40+
target_lng = db.Column(db.Float, nullable=False)
41+
radius_meters = db.Column(db.Float, default=500.0)
42+
43+
current_lat = db.Column(db.Float)
44+
current_lng = db.Column(db.Float)
45+
46+
is_triggered = db.Column(db.Boolean, default=False)
47+
triggered_at = db.Column(db.DateTime)

backend/models/freight_v2.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""
2+
Freight Pairing & Vehicle Network Models — L3-1644
3+
=================================================
4+
Manages autonomous vehicle pairing for supply chain orders.
5+
"""
6+
7+
from datetime import datetime
8+
from backend.extensions import db
9+
10+
class AutonomousVehicle(db.Model):
11+
__tablename__ = 'autonomous_vehicles'
12+
13+
id = db.Column(db.Integer, primary_key=True)
14+
serial_number = db.Column(db.String(100), unique=True, nullable=False)
15+
vehicle_type = db.Column(db.String(50)) # DRONE, TRUCK, AGV
16+
17+
current_capacity_kg = db.Column(db.Float)
18+
battery_level_pct = db.Column(db.Float)
19+
20+
# Status: IDLE, IN_TRANSIT, CHARGING, MAINTENANCE
21+
status = db.Column(db.String(20), default='IDLE')
22+
23+
current_lat = db.Column(db.Float)
24+
current_lng = db.Column(db.Float)
25+
26+
last_ping = db.Column(db.DateTime, default=datetime.utcnow)
27+
28+
class VehicleMission(db.Model):
29+
__tablename__ = 'vehicle_missions'
30+
31+
id = db.Column(db.Integer, primary_key=True)
32+
vehicle_id = db.Column(db.Integer, db.ForeignKey('autonomous_vehicles.id'), nullable=False)
33+
order_id = db.Column(db.Integer, db.ForeignKey('smart_contract_orders.id'), nullable=False)
34+
35+
assigned_at = db.Column(db.DateTime, default=datetime.utcnow)
36+
completed_at = db.Column(db.DateTime)
37+
38+
distance_traveled_km = db.Column(db.Float, default=0.0)
39+
energy_consumed_kwh = db.Column(db.Float, default=0.0)

backend/models/ledger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class TransactionType(enum.Enum):
4444
DIVIDEND = 'DIVIDEND'
4545
FEE = 'FEE'
4646
INTEREST = 'INTEREST'
47-
BIOMASS_ENERGY_MINT = 'BIOMASS_ENERGY_MINT' # Decentralized VPP grid payout for biomass energy injected
47+
AUTONOMOUS_PROCUREMENT = 'AUTONOMOUS_PROCUREMENT' # Automated payment for supply chain fulfillment
4848
CARBON_CREDIT_MINT = 'CARBON_CREDIT_MINT' # New credit minted from sequestration
4949
CARBON_CREDIT_SALE = 'CARBON_CREDIT_SALE' # Credit sold to ESG buyer
5050

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
Autonomous Freight Matching Service — L3-1644
3+
============================================
4+
Algorithm for matching logistics orders to available autonomous vehicles.
5+
"""
6+
7+
from datetime import datetime
8+
from backend.extensions import db
9+
from backend.models.freight_v2 import AutonomousVehicle, VehicleMission
10+
from backend.models.autonomous_supply import SmartContractOrder
11+
import math
12+
import logging
13+
14+
logger = logging.getLogger(__name__)
15+
16+
class FreightMatchEngine:
17+
18+
@staticmethod
19+
def find_nearest_vehicle(order_lat: float, order_lng: float, required_capacity: float):
20+
"""
21+
Heuristic-based search for nearest available autonomous asset.
22+
"""
23+
vehicles = AutonomousVehicle.query.filter_by(status='IDLE').all()
24+
25+
best_vehicle = None
26+
min_distance = float('inf')
27+
28+
for v in vehicles:
29+
if v.current_capacity_kg < required_capacity:
30+
continue
31+
32+
# Haversine approximation
33+
dist = math.sqrt((v.current_lat - order_lat)**2 + (v.current_lng - order_lng)**2)
34+
35+
if dist < min_distance:
36+
min_distance = dist
37+
best_vehicle = v
38+
39+
return best_vehicle
40+
41+
@staticmethod
42+
def assign_vehicle_to_order(order_id: int):
43+
"""
44+
Pairs an order to a vehicle and initiates mission state.
45+
"""
46+
order = SmartContractOrder.query.get(order_id)
47+
# Assuming order has pickup coordinates (mocked for L3 brevity)
48+
pickup_lat, pickup_lng = 12.9716, 77.5946
49+
50+
vehicle = FreightMatchEngine.find_nearest_vehicle(pickup_lat, pickup_lng, order.quantity_kg)
51+
52+
if vehicle:
53+
vehicle.status = 'IN_TRANSIT'
54+
mission = VehicleMission(
55+
vehicle_id=vehicle.id,
56+
order_id=order_id
57+
)
58+
db.session.add(mission)
59+
order.status = 'SHIPPED'
60+
db.session.commit()
61+
62+
logger.info(f"Matched Vehicle {vehicle.serial_number} to Order {order_id}.")
63+
return vehicle
64+
65+
return None
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
Autonomous Supply Chain Engine — L3-1644
3+
========================================
4+
Orchestrates automated procurement and IoT-based shipment release.
5+
"""
6+
7+
from datetime import datetime
8+
import uuid
9+
from backend.extensions import db
10+
from backend.models.autonomous_supply import SmartContractOrder, FreightGeoFence
11+
import logging
12+
13+
logger = logging.getLogger(__name__)
14+
15+
class SupplyChainOrchestrator:
16+
17+
@staticmethod
18+
def initialize_contract(buyer_id: int, vendor_id: int, commodity_info: dict):
19+
"""
20+
Creates a new smart order with auto-trigger conditions.
21+
"""
22+
order = SmartContractOrder(
23+
buyer_id=buyer_id,
24+
vendor_id=vendor_id,
25+
commodity=commodity_info['name'],
26+
quantity_kg=commodity_info['quantity'],
27+
strike_price_usd=commodity_info['price'],
28+
auto_execute_at_price=commodity_info.get('trigger_price')
29+
)
30+
db.session.add(order)
31+
db.session.flush()
32+
33+
# Set up geofence for delivery
34+
fence = FreightGeoFence(
35+
order_id=order.id,
36+
target_lat=commodity_info['dest_lat'],
37+
target_lng=commodity_info['dest_lng'],
38+
radius_meters=200.0
39+
)
40+
db.session.add(fence)
41+
db.session.commit()
42+
43+
logger.info(f"Smart order {order.id} initialized. Pending execution trigger.")
44+
return order
45+
46+
@staticmethod
47+
def update_gps_telemetry(order_id: int, lat: float, lng: float):
48+
"""
49+
Updates shipment location and checks for geofence breach to complete order.
50+
"""
51+
fence = FreightGeoFence.query.filter_by(order_id=order_id).first()
52+
if not fence or fence.is_triggered:
53+
return False
54+
55+
fence.current_lat = lat
56+
fence.current_lng = lng
57+
58+
# Simple Euclidean approximation for distance (L3 logic)
59+
dist = ((lat - fence.target_lat)**2 + (lng - fence.target_lng)**2)**0.5
60+
61+
# 0.001 deg is approx 111 meters
62+
if dist < 0.002: # Within approx 220m
63+
fence.is_triggered = True
64+
fence.triggered_at = datetime.utcnow()
65+
66+
order = SmartContractOrder.query.get(order_id)
67+
order.status = 'COMPLETED'
68+
69+
# Settlement logic: Release digital payment automatically
70+
logger.info(f"ORDER {order_id} DELIVERED. Releasing payment to vendor.")
71+
72+
db.session.commit()
73+
return fence.is_triggered

backend/tasks/supply_chain_sync.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from backend.celery_app import celery_app
2+
from backend.models.autonomous_supply import SmartContractOrder
3+
from backend.services.freight_match_service import FreightMatchEngine
4+
import logging
5+
6+
logger = logging.getLogger(__name__)
7+
8+
@celery_app.task(name='tasks.autonomous_logistics_sweep')
9+
def logistics_matching_sweep():
10+
"""
11+
Scans for orders in PENDING_TRIGGER status and attempts vehicle pairing.
12+
"""
13+
logger.info("🚚 [L3-1644] Scanning for pending autonomous logistics assignments...")
14+
15+
pending_orders = SmartContractOrder.query.filter_by(status='PENDING_TRIGGER').all()
16+
matches_found = 0
17+
18+
for order in pending_orders:
19+
vehicle = FreightMatchEngine.assign_vehicle_to_order(order.id)
20+
if vehicle:
21+
matches_found += 1
22+
23+
logger.info(f"Logistics sweep complete. Paired {matches_found} missions.")
24+
return {'matches': matches_found}

0 commit comments

Comments
 (0)